单体架构
为了更好的说明微服务,先来说下单体架构。
单体架构就是传统的开发模式,即将应用写在同一个目录下,一次部署。如图:

固然这种开发方式是最快最方便的,但随着开发层次的深入、应用的逐次迭代,代码也不可避免的变得非常庞大、复杂,最终变成常人难以理解的一个“怪物”。
缺点:
- 部署时间长。 当对一个bug进行修复后重新进行部署时,由于是单体应用,所以就导致全部代码都要一起部署。应用越大,启动时间越长,一些单体应用的启动时间为十来分钟,甚至有的到达40分钟以上。如果开发人员经常要重启应用服务器,那么很大一部分时间都是在等待中度过,其生产力将受到严重限制。
- 迭代和维护困难。代码过于庞大和复杂,造成二代开发者理解困难,迭代困难,难以维护。许多公司使用了过时技术的项目时,往往因为项目太过庞大、难以理解,导致多次使用新技术栈的尝试失败。
- 代码之间耦合性高,牵一发而动全身。难以处理各部分之间的关系,维护困难,并且可能因为一个微小的问题,导致整个应用挂掉。
- 无法按需伸缩,扩展性差。比如搜索服务的压力大,需要水平扩展,但因为是单体应用,只能整个应用进行水平扩充。
正是这些缺陷使得单体架构随着应用愈发壮大而注定要被抛弃,也呼唤一种新的架构模式的出现。
当然在微服务之前还有一些其它的解决方案,微服务也是在SOA架构的基础上发展起来的。
什么是微服务
顾名思义,就是体积“微”小的服务,即把一个大的单体应用拆分成多个小的服务,各个小服务都算得上是一个独立的应用,独立开发,独立部署,独立迭代。客户端和这些服务之间有一个 API Geteway,用于统一转发客户端的请求,底层的服务对于客户端来说是透明的。
目的:有效的拆分应用,实现敏捷开发和部署
特点
- 高内聚,低耦合。
- 各个服务独立开发、独立部署。独立开发不仅仅是指开发人员单独对这个模块进行开发,还指该服务可以使用不同的开发技术。
- 统一的API Gateway中介。API网关负责负载均衡、访问控制、缓存和监控等。
- 服务之间使用IPC机制来通信。
- RESTful(HTTP协议)
- RPC
- 异步通信(Kafaka、NSQ、Redis)
优势
-
模块分离,便于敏捷开发、功能拓展和项目维护。单个微服务内部的实现对其它微服务而言是透明的,所以只要接口约定好了,那么就可以尽情的实现优化和功能扩展。而单个微服务规模更小,代码容易理解,因此维护的难度更低。
-
独立部署效率高,局部的修改更容易部署。对于微服务,可以只更改单个服务,并独立于系统的其余部分进行部署,这样部署更快。如果发生问题,则可以将其快速隔离到单个服务,从而轻松实现快速回滚。
-
易于迭代和技术创新。单个服务可以采用更好的技术来优化、迭代。甚至可以使用不同的开发语言。
-
易于水平扩展、按需伸缩。当某个服务压力大时,可以单独对其进行水平扩展。
缺点
正如某书中所说的“没有银弹”,微服务也有其自身的缺陷和不足,无法奉为圭臬。
“银弹”就是指对某种怪物的最有效的杀伤武器,或称为杀手锏。
“没有银弹”是指计算机科学家、图灵奖获得者布鲁克斯(Frederick Phillips Brooks,Jr.)提出的一个论断:“没有任何一种单纯的技术或管理上的进步,能够独立地承诺在10年内大幅度地提高软件的生产效率、可靠性和简洁性。”
- 多服务导致部署和运维难度增加。
单体应用只有一个运维对象,但微服务由多个服务组成,当服务数量增多时,不可避免地导致部署和运维难度增大,如Netflix 拥有的服务就超过 600 个。这就导致微服务开发团队必须要具备自动化部署和运维的策略和能力。
-
跨越多个服务,排错困难,测试困难。
-
接口调整成本高。比如用户服务被评论服务和选课调用,一旦用户服务的接口发生变化,那么所有依赖于它的服务都需要做相应的调整。
-
统一的API Gateway 可能会导致单点故障。
-
……
适用条件
- 易于拆分、模块耦合低的应用。一些诸如偏于底层的应用,各个模块之间耦合度高,就不适用于微服务。
- 各个微服务能够独立地部署。
微服务架构需要考虑的问题
- 客户端如何访问这些服务
- 每个服务之间如何通信
- 服务如何发现
- 服务挂了,如何解决
Q&A
为什么要使用API网关来作为系统的单入口点,而不直接请求各个服务?
API网关并不只是为客户端提供流量转发,还负责用户认证、请求的分发与聚合、负载均衡、缓存、监控和协议转换等任务。
用户认证由API网关来负责,可以避免各个微服务对相同认证模块代码的重写,提高开发效率,并避免不同代码可能造成的混乱,实现认证机制的统一。
对于客户端的请求,大多数情况下都不是仅有一个服务可以完成的,需要其它服务的配合,比如获取商品详情信息,可能需要商品服务提高商品信息、库存服务提供库存信息,因为要尽量降低耦合度,这些信息的组合应该由API网关来完成。
除此以外,当某个微服务发生故障时,API网关还可以通过返回缓存或默认数据等来掩盖后端服务的故障,如果由客户端直接和服务通信,那么客户端就很容易知道服务端的故障,可能会因为得不到有效数据而降低用户体验。