软件架构的演进
讲正事儿之前,先讲个故事——话说,从前有个叫周星星的少年,从摆街边摊起家,通过自己的奋斗,最终成为饮食界的大亨。他的发家过程经历了四个阶段:
-
街边摊阶段:这时刚刚创业,一穷二白,要钱没钱、要人没人,自己什么都得做,卖材料、做饭菜、摆桌子、收钱,全都他一个人搞定。刚开始,客人不多,一个人游刃有余。后来,来光顾的客人也越来越多,一个人就忙不过来了,有时客人看要等很久就走了……于是,赚了些钱的他,盘算着开个小店……
-
快餐店阶段:他招了几个员工,简单分为了三组:一组服务员,负责接送客人,人多的时候引导客人排队;一组厨师,他自己做主厨,指导其他厨师做菜;一组采购,负责买菜等。就这样,快餐店开起来了。三组人员各司其职……他家秘制的“撒尿牛丸”远近闻名,客人络绎不绝……但慢慢地,有客人反映,他家的菜品太少,没办法满足客人的需求了……
-
大酒店阶段:为了满足客人越来越高的要求,他把快餐店升级为大酒店。他成立了四大厨师部门,分别为客人提供川菜、东北菜、粤菜、湘菜四大不同菜系,通过统一的后勤、财务把这四大菜系管理起来……刚开始,一切都很好,赚的钵满盆满。但随着生意越来越旺,客人越来越多,又开始出问题了:餐厅地方不够!排队的人越来越多。周星星打算开分店,但问题来了:这个分店,吃川菜的多,其他菜没什么人吃;那个分店,吃粤菜的多,别的菜系厨师闲着……后来,又发生了一件事:吃东北菜的两桌客人,一句“你愁啥”,一句“瞅你咋地”,就打起来了,拦都拦不住。这一闹,把吃粤菜、川菜、湘菜的客人都给吓跑了……精明的周星星一眼看出了问题,这是因为四个菜系共享了一个资源(餐厅),导致了一个服务出问题,别的服务都遭殃。他意识到,要继续发展,企业的组织方式还得调整。
-
饮食集团阶段:周星星成立了周氏饮食集团,掌控各个子公司,每个子公司都有独立的前台、后勤,互不干扰,自负盈亏。还有一个额外的好处,比如这段时间日料流行,那就多开几个日料店;又过一阵子,西餐流行,那就把日料店关一些,多开些西餐店。整个集团很灵活,总是能快速的抓住商机。至此,周星星成为饮食界的老大。
其实,软件架构的演进过程和周氏企业演进过程是一模一样的!软件架构的演进也分为四个阶段:单体架构(街边摊)、分层架构(快餐店)、SOA架构(大酒店)和微服务架构(饮食集团)
单体架构:实际上没什么架构的概念,所有的业务逻辑都在一个项目里打包成一个二进制的编译后文件,通过这个文件进行部署,并提供业务能力。它就像上面的“街边摊”,很小很灵活。但是处理能力有限;没有分工,难以扩展。
分层架构:又叫“三明治”架构。分层架构中的每一层都着特定的职能。层之间是隔离的,即一个请求,必须一层一层的传递,而不能跨层传递。分层架构的流行,催生了大量的可复用的中间件。它就像上面的“快餐店”,有了明确分工的几个组,团队的能力大于个人,处理能力有了一定的提升。但是面对更复杂服务要求的时候,无论是扩展能力,还是服务能力,都有点力不从心。
SOA架构:即面向服务的架构(Service Oriented Architecture),它的关注点是服务。一个服务定义了一个相对独立、自包含、可重用的业务功能。服务间一般通过企业服务总线(ESB)的方式组装起来。它就像上面的“大酒店”,可以把各个较独立的服务组装起来,对外提供更复杂的服务,满足客户更多样化的需求。SOA架构要提高扩展性,就需要采用“分布式”的方式了。那么,各种服务如何行“分布式化”?这就催生了下面要说的微服务架构。也可以认为,微服务架构就是SOA架构分布式化的一种实现。
微服务架构:以一组小而自治的服务来构建整个系统,系统的一大特点是去中心化,从而实现更灵活的扩展能力。它就像上面的“饮食集团”,每个服务都独立而自治,整个系统(集团)具有很强的弹性,扩展自如,风险可控。当然,这样的弹性是要付出一定代价的,后面我们再详细分析。
回顾软件架构的演进其实是与企业组织演进一样的:都是为了满足客户越来越多、越来越复杂的需求,不断调整软件(企业)内部结构的过程。最后,都使得软件(企业)的处理能力、扩展能力、抗风险能力等等更强。
微服务架构的产生
通过前面软件架构演进史的介绍,可以对微服务的产生有个总体的认识。下面讲讲微服务具体是如何从SOA架构中衍生出来的。
可以说,微服务是在领域驱动设计(DDD)、持续交付(DevOps)、对Web的理解(REST)、六边形架构、虚拟化平台等一系列技术的基础上,发展建立起来的。微服务架构应用这些技术解决了原来SOA中面临的一系列问题。可以说,这五大技术是微服务架构的基石,没有它们,就不可能建立起微服务架构。
原SOA面临的一些问题,及微服务对此的解决之道:
- 如何划分服务:SOA虽然提出了以服务为核心的观念,但是对于如何划分服务,并没有很好的指导方法。“领域驱动设计”理论为如何进行服务划分提供了方法论。虽然对于微服务架构,如何划分服务仍是一大难题,但比之前有了一定改善。
- 服务如何集成:持续集成及DevOps技术的发展,为自动化的服务集成,提供了一系列工具和解决方案。多个协同工作的服务需要集成测试、联合部署,没有自动化的持续集成基本无法实施。持续集成是微服务架构中的一个不可或缺的部分。
- 服务如何通信:随着HTTP技术的发展,产生了RESTful的架构风格,它为服务之间通信和集成提供了很好的解决方案。其中最重要的一点是资源的概念,将服务看成是对外提供的一系列资源,资源在服务内的形态与客户端能看到的表现形态是分离的。一般使用HTTP作为REST的底层通信协议。HTTP提供了get、post、put、delete等动词,可以很好的表达对资源的使用;同时,HTTP周边有一整套完善的生态系统,可以使得服务的通信、负载均衡、缓存、监控等更加容易。
- 服务内部如何组织:六边形架构通过对领域模型、应用、适配器的划分,使得业务领域的边界更加清晰,服务具有更好的可扩展性,更容易测试。微服务中的单个服务,一般使用六边形的架构风格。
- 服务如何扩展:虚拟化技术的发展,尤其是Docker技术、云技术的发展,使得服务的分布式安装、部署、弹性扩展成为一件相对容易的事。弹性扩展是微服务架构的一个重要优点,脱离了虚拟化技术,这个优点将很难实现。
微服务架构的特点
上面说了那么多微服务,到底什么才是微服务呢?这里姑且给出一个定义:微服务就是一些协同工作的小而自治的服务。所谓“小”,就是专注做好一件事;所谓“自治”,就是服务是独立的实体,服务之间彼此独立,修改部署一个服务不会影响其他服务。
按Martin Fowler大神的想法,微服务应该具备以下特点:
- 通过服务实现组件化:使用微服务作为组装应用的组件,有三大好处:一是可以独立部署、替换和升级;二是由于强迫使用网络通信,会使得接口更加明确;三是可以实现不同技术栈的组合。
- 围绕业务能力组织服务:按照业务划分服务,更符合康威定律。一个服务可以由一个全栈团队负责。相比分层架构,一个变更需要更少的沟通,也就更高效。
- 产品而非项目模式:微服务架构倡导一个团队负责一个“微服务”完整的生命周期,把每个微服务当成一个产品来看待。
- 智能端点与哑管道:传统SOA架构,强调ESB(企业服务总线)等中间件,试图把这些中间件做得更智能;而微服务架构与此相反,更强调把这些智能放到端点(也就是微服务)中,而微服务之间的通信应尽量简单。微服务就像Unix中的一个独立的命令,他们间的通信就像Unix中的管道那么简单。这也是微服务与传统SOA的一个重要差别。
- “去中心化”治理:整体式应用往往倾向于采用单一技术栈,微服务架构则鼓励使用最合适技术栈完成各自的任务。
- “去中心化”数据管理:微服务架构倡导让每个微服务管理其自有数据,并允许不同微服务采用不同的数据持久化技术。
- 基础设施自动化:通过持续集成和持续交付等方法自动化的构建、部署微服务。
- 为容错设计:因为微服务可能随时出现故障,微服务架构中实时监控和日志机制非常重要,可以帮助快速发现故障。出现故障时微服务应该尽可能自动恢复。
- 演进式设计:微服务应用更注重快速更新,因此系统的设计会随时间不断变化及演进。
微服务架构的优势
“天下熙熙皆为利来,天下攘攘皆为利往”——这么多人追随微服务而来,必有其“利”!相比之前的架构,微服务主要有下面几个优点:
- 技术异构性:微服务可以轻松采用不同的技术栈。
- 弹性:一个服务不可用不会导致整个系统不可用。
- 扩展:可以只针对那些需要扩展的微服务进行扩展。
- 简化部署:不用重新部署整个应用,只需要部署个别服务,并可以快速回滚。
- 与组织结构相匹配:符合康威定律。
- 可组合性:对已有功能组合实现新的应用。
- 可替代性:重新实现某个服务相对容易些。
微服务架构的挑战
俗话说:“天下没有免费的午餐”,要获得微服务带来益处,是要付出一定代价的!下面看看微服务对比原来架构带来了哪些挑战:
1. 版本
各个微服务应该用统一版本号呢,还是各自独立版本?”——一旦为图方便,使用统一一个版本,就会使得微服务带来的“自治、独立发布部署”的优点不复存在。而每个服务维护不同的版本,又为版本管理的复杂度带来极大的挑战。并且不同版本之间的兼容性测试也会十分复杂。
2. 代码
重复的代码怎么办?——这还用问吗?根据DRY原则,当然要抽取出来——然而,在微服务时,则不是这样的。因为不同服务间一旦抽取了公共的业务逻辑,就意味着这两个服务耦合在一起了。公共模块的变更会影响这两个服务。所以,一般建议微服务内遵守DRY原则,而跨服务可以适当违反DRY原则……这同时又带来了另外一个问题,就是重构代码会变得十分困难,出现共性的问题,可能需要多个团队同时修改。在老板眼里,这就是资源浪费啊。
3. 界面
服务拆分了,那用户界面怎么办?——如果不分,那界面就是所有服务耦合的地方,很容易就退回到分层合作的模式;如果界面也分开,要怎么组合在一起,给用户最终呈现一个统一的整体呢?虽然可以通过“UI片段组合”或者“前端专用后端”的方法予以解决,但其引入的复杂性也是一项不小的挑战。
4. 数据
各服务是共享数据还是独占数据?——如果共享数据,这些数据就是微服务之间耦合的点。一个微服务修改了数据或者数据结构,就可能对另外的服务产生影响。而如果数据分离到每个服务中,又带来了一些新的挑战,比如:如何保证事务的一致性、如何处理报表系统等等。这些都是设计上要面临的挑战。
5. 分布式
微服务架构是典型的分布式架构。天生具有分布式架构所面临的挑战。可以了解一下:分布式系统的八大谬误,CAP定理。这些复杂性,都是微服务架构需要克服的。
6. 监控
监控对于微服务架构十分重要。一个业务流程可能涉及多个微服务协同工作,日志散落在各处。如果没有有效的监控手段,出了问题将很难查。
7. 安全
服务之间的调用,能信任吗?——如果全信任,意味着攻击者只要进入内网中,就可以采用中间人攻击任何服务。如果不信任,那服务之间的认证、鉴权、证书发布、证书管理等一系列复杂的安全问题,都是需要认真考虑的。
可见,微服务架构面临的挑战难度还是比较高的。虽然,现有的一些微服务框架可以帮助解决一部分问题,但要将微服务落地,这些挑战仍然是需要认真面对的。
该不该用微服务架构?
关于这个问题,《微服务设计》的作者这样建议道:
越不了解一个领域,为服务找到合适的限界上下文就越难。请考虑首先构建单块系统,当稳定以后再进行拆分。一块块地拆分你的系统,持续地改进和演进系统,拥抱变化!
我在此基础上,再增加“四看”:
- 看系统规模
- 看组织结构
- 看基础设施
- 看人员能力
1. 看系统规模:
从前面架构演进的历史,可以知道微服务是为解决规模比较大的系统的问题而诞生的。如果现在的业务量以及未来一、两年内的业务量都不会很大,一台服务器就可以搞定,这样小规模的系统就没必要硬上微服务。因为这样微服务带来的挑战比它带来的好处大得多。
有些反对这个观点的人说:“即使系统规模不大,使用微服务也可以使系统更解耦,后面扩展更容易”。——这是本末倒置了。并不是微服务架构使得系统更解耦,而恰恰相反,是解耦做好了,才能做好微服务架构!优秀微服务架构实践的前提是合理划分服务,使得服务高内聚、低耦合,而不是反过来。微服务架构中划分服务的方法论是DDD(按照限界上下文来划分服务),这个方法论并不要求一定是微服务架构,各种架构都可以实施。正如前面所说“越不了解一个领域,为服务找到合适的限界上下文就越难”。微服务架构中,一旦服务边界划错了,带来的后果是灾难性的;而不是分布式的架构中,这种错误的修正要容易得多。
2. 看组织结构:
微服务架构倡导的是每个服务由一个具备全栈能力的团队负责。如果当前组织是按技能划分的,比如前端团队、后端团队、数据库团队等,那就不是很合适。要么放弃微服务,要么调整组织结构。
3. 看基础设施:
虚拟化/云化、持续集成等自动化基础设施,是微服务实施和运维的有力保障。如果组织目前还不具备这些基础设施,那么微服务的落地将面临很多困难。
4. 看人员能力:
不管一开始看起来什么样,它永远是人的问题。
微服务架构赋权给开发人员以增进自治也是充满挑战的。过去人们习惯把工作扔给别人,习惯指责别人,现在要让他们对自己的工作完全负责可能会让其感觉不舒服。微服务架构要求研发团队具备全栈技术能力,对单个研发人员的综合素质要求也比以往更高。如果人员没有从心理上和技能上准备好,强行推行微服务,很可能为失败埋下种子。
最后,
按照InfoQ发布的2019架构和设计领域趋势报告,微服务架构很可能进入晚期大众阶段,这也意味着,按照Gartner炒作周期,微服务架构已经走过了盲目追捧和幻灭谷底阶段,开始逐渐走向成熟,走向切实可落地阶段。
微服务是一个很容易被滥用或误用的术语。本文从架构演进史入手,介绍了微服务架构的来龙去脉、它的优点以及它带来的挑战。希望可以帮助大家更好的理解微服务架构。根据自己项目的实际情况,权衡利弊,决定是否向微服务架构演进。