转载自Microservices微服务简介和知识分享

1. Monolith大系统的演变

要讲微服务就要先讲讲它是为什么会产生的,那么我们就需要回顾下软件系统(这里主要是指企业应用系统)的发展历史:

最开始大概二三十年前,企业应用软件大多是以套装软件形式出现,由于电脑硬件性能和网络速度的限制,大多是基于C/S架构,跑在企业局域网里,那个时候大街上跑的基本都是VB、VC、PB、Delphi程序员,连Java也在搞GUI,Swing那些东西。

后来互联网提速,加上PC性能提高,价格下降,家用机普及,浏览器兴起,大家都开始上网,门户网站,电子商务渐渐兴起,大大小小的企业也都开始建portal,参与信息化建设,把各种企业应用系统开始往网页开发技术上靠,那个时候就是很多jsp程序员,而且面试都考EJB知识。

再往后就是Spring之父著书批判EJB,同时随着硬件和网络的继续发展,SSH的三层开发架构由于方便灵活等特点开始成为主流。但是这个时期主要是在快速开发实现功能,尽早上线拉用户,东西能用就行,所谓软件设计,大多是简单分一下模块,建好数据表,然后用框架来CRUD,再在服务service层把业务逻辑搭起来,所以面试时候我们闭着眼睛都会念叨entity,DAO层, service层,controller层这些。

那么我们可以看到这个趋势,软件的发展是建立在硬件发展和网络发展的基础之上的。这个后来发生了什么呢,大公司发现买的主机太多了,大部分主机常年资源只使用10%以下,在那干占着坑花电费,为什么不能把这些资源利用起来,出租什么的呢,共享经济么,于是在聪明人们的努力下,云平台诞生了。

Cloud这个东西其实对微服务的出现和发展是有很大推进作用的,最开始主机和资源共享出来,按需付费,那基本就抢了主机托管机房的生意,像AWS号称在全世界有好多个大区,可以到处给你容灾备份,我原来公司就在AWS上东海岸和西海岸各弄了两个区的主机,号称万一加州地震了业务也能无缝切换到东海岸去。等大家纷纷搬到云平台云主机上,发现在平台基础上各种基础软件服务也逐步完善和开放出来了,那么很多安全认证啊,缓存服务啊,消息队列啊,数据库啊,都已经在那了,也不需要你自己开发升级维护甚至配置,这样很多企业软件就开始了改造和切换到平台服务,被动的就推动了软件设计的分解和更加专注于业务逻辑。

enter image description here

2. Monolith大系统的缺点和开发周期特点

enter image description here

2.1 大系统的缺点

这个游戏不知道大家玩过没有,我觉得就很贴切的表达了大系统的一些缺点:

  • 子模块/系统的耦合度非常高,互相引用依赖,很容易出现牵一发而动全身的局面
  • 越往后加(抽)东西越难,前面累计的技术债就像地雷一样,说不定哪里就被你改坏了
  • 权责不明确,出了问题大家推锅
  • 系统越来越难以理解,整体架构基本没有人能够把握

enter image description here

2.2 大系统的开发周期特点

再来看看大系统的软件开发周期特点:

  1. 单一pipeline,任何一个人break了build,所有人都受影响提交不了代码
  2. 由于软件系统越来越大,代码行数越来越多,编译测试部署全都变得很慢,一个无奈的段子就是说也有好处就是程序员一旦提交了代码,就可以起来活动活动,喝杯咖啡,半小时后再回来看build成功没有
  3. 一点点修改,所有代码不管动没动过全部需要编译,所有测试不管相不相关全部要跑,浪费大量人力和时间成本
  4. 破坏开发人员创造力,当你整天面对这么个庞大又脆弱的怪物,感到精疲力尽很沮丧,试想如何能够进行快速迭代和创造性开发功能?
  5. 开发周期变长,系统迟迟加不上新功能,bug修复也变慢,逐渐造成用户流失
  6. 很难Scale,由于整体是一个大系统,部署的时候也是一个大War包,唯一的办法就是加机器

说到这最后一点系统的Scale我们来看一下这张著名的图:

enter image description here

这里X轴就是加机器搞集群,Y轴解决方案是类似数据库分区分表的做法,通过一些相同数据来进行分流,比如说针对一个大客户就可以按照特定orgId请求分配给某个大集群之类的,而Z轴代表把系统里不同的部分分开,区别做优化,就带出了我们的微服务。

3. 微服务系统MicroServices

其实微服务架构并不是一个突然出现的新鲜事物,它来自于多年来软件设计方面可复用组件的探索,从最早的EJB就是希望能够封装出可通用的Java Bean组件来,到后来的SOA面向服务架构,虽然都没有取得成功,但是都是在探索中积累出来了微服务架构的基础。

enter image description here

3.1 微服务系统的特点

我们来对比看一下微服务系统相应的特点:

  • 子系统的耦合度低,一个系统挂掉并不会影响到其他系统
  • 组件间通过Rest API通讯,相当于面向接口编程,一个子系统内部的实现变化,只要没有影响到接口,对外部都是不可见的,其他系统根本都不需要关心,增强了整体的灵活性
  • 责任明确,有专门的team负责某子系统,有了问题能够更快解决,而且基本不需要关心其他系统的实现逻辑,由于专注更容易培养领域专家
  • 系统越来越难以理解,整体架构基本没有人能够把握

enter image description here

3.2 微服务系统的开发周期特点

再来看看微服务的软件开发周期特点:

  • 两个披萨的team(来自Amazon的实践),大小适中,灵活自治
  • 分开的pipeline,任何一个人break了build,只有自己组和服务受影响,防止了问题扩大化
  • 单一系统相对小,代码行数少,编译测试部署速度飞快,我原来负责的服务大概编译测试CI跑下来一遍只要五分钟左右
  • 程序员生产效率高,能够实现快速迭代,代码重构也相对容易
  • 开发周期短平快,系统上新功能以及bug修复都很快,能够对用户需求快速响应,提高满意度
  • 很容易Scale,哪个子系统负载增加再加机器,AWS等云平台甚至可以配置动态Scale,实现按需分配

3.3 微服务系统的六大原则

微服务系统有以下几大原则:
enter image description here

3.3.1 第一原则是系统间交互要通过公开的API来进行

几年前我一个朋友创业要做新系统,我给建议用微服务架构,从头开始就有很多优势,不涉及大系统改造过来的数据迁移等等很多头疼步骤,然后朋友跟团队一研究发现不错,很多开源的组件能拿来直接用,系统很快搭出来拿给我一看,我说这不对啊,你们为什么只有一个数据库,然后他们说这不是快么方便一些,上层应用逻辑都是分开的,这个其实就是违背了第一原则,你只要数据库都混在一起,人都图方便开发时就都开始直接交叉查表,完全失去了微服务解耦的本意,所以说对一个子系统所有的CURD都要变成Rest API的调用,这样才不会一个表结构变化影响到一堆服务。
我们来看一下大系统和微服务的结构对比图:
enter image description here
enter image description here
这很明显微服务里每个子服务都应该是独立自治的,不管数据库还是程序以及API接口全是自己一套,不能调用混乱,对外只开放API,所有的交互都要在API层完成,这个其实也是我们软件设计的一大原则OCP开闭原则,开放接口,隐藏实现细节。

这里再借这两张图说一下如何设计拆分子系统,这里可以用到软件设计的一个方法,首先以故事的形式把系统的功能简单描述一下,比方说我这个系统要实现乘客可以创建旅行,司机可以查看离自己近的旅行去接乘客,然后实现生产账单乘客支付等等,那我们就可以看这个完整的故事里有多少个名词,比如这里的乘客、司机、账单、旅行等等就都可能是子系统,而主要的动词比如创建、查看、接、生成、支付等等就都是子系统间的交互动作。当然有时候足够复杂的动作也可能成为独立的子系统比如支付系统等,这个就需要灵活掌握了。
enter image description here

3.3.2 第二原则实际就是说各个子系统可以灵活使用合适的工具和语言

比如尽管大多数业务子系统都用Java,数据分析的子服务你就可以用Python等等,因为系统间都是通过API交互,使用什么技术或者语言对彼此来说并没有什么影响。

3.3.3 第三原则是子系统可以实现自己的安全认证机制

这样实际上就加强了安全性。

3.3.4 第四原则是要适合整个环境

主要指分布式的监控和日志管理,使用类似Splunk这样的日志工具软件可以很灵活的监控不同机器上的日志,也可以
通过tracing id这样的机制来跟踪整个分布事务的整个过程。

3.3.5 第五原则建立小而灵活的Scrum team来适应微服务的架构

微系统的不同并不只是软件架构上的不同,甚至要影响到整个公司架构的变化,通过建立小而灵活的Scrum team来适应微服务的架构。

3.3.6 第六原则就是自动化流程

即所谓的CICD,在美国这边有些公司类似Amazon和Netflix已经实现全部自动化,程序员提交修改,通过自动编译和测试的CI pipeline,再经过CD直接上生产,这个当然需要大量的自动化测试来保证质量,但是一旦实现能够极大的提高生产效率。

3.4 微服务系统的缺点/难点

万事万物都有缺点,那么微服务我们说也不是所谓的银弹,能够解决一切问题,它也有一些缺点或者想成功实现的难点:

  1. 复杂度高:这个主要是指大局观,从一开始就把整个业务系统分拆的明明白白,各系统设计划分及系统间交互关系都弄明白是非常难的一个事情,也就是说是非常难从一开始就做对的一件事,所以就需要有很多有经验的技术专家和业务领域专家合作来设计划分domain boundry,还需要公司管理层全力支持这个事情,要做好长期计划和财务支持。
  2. 管理难度:微服务架构的成功离不开管理方面的成功,组织架构的转变,team的敏捷实施,不同team之间的沟通协作,都是很有挑战的工作
  3. 工程师要求:首先要求工程师最好有相关经验,我当时建议朋友公司采用微服务架构的时候就发现国内找不到多少有相关工作经验的人,这两年好像稍微好了点,做过或者学习过微服务架构的工程师Mindset就不一样,如果习惯了大系统主流的分层式开发的工程师,很可能一看就觉得这玩意是不是过度设计?弄出几十个系统这么麻烦干什么,能做出来不就得了么,尤其微服务架构实施往往还伴随着DDD,看起来就更是过于抽象和高冷。这个学习和积累经验的过程还是有一个学习曲线在的。
  4. 迁移成本:大部分公司起步都是以大系统起家的,首先有了一个创业点子,赶紧做出一个系统来招揽生意,然后慢慢随着发展,用户增长,新功能都是一点点加在系统里,系统变得越来越大,很少有机会说一家公司起步就按微服务架构来设计,那么当意识到大系统的局限性,因为种种原因到了不得不转型的时候,往往就要付出代价,经历阵痛或剧痛,大量的历史遗留数据如何迁移处理?业务如何无缝切换?都是需要付出精力去计划实施的事情。
  5. 运营成本:这个其实很有意思,硅谷这边很多小公司最后是败在了这一环,实际上就是觉得这个东西听起来很高大上,一拍脑袋就上了,并没有做成本分析,结果好不容易系统开发好了,一上AWS发现每个月怎么交给Amazon那么多钱,而实际业务根本还没什么量,烧钱速度太快,本质原因是原来用大系统可能就是几个主机做一下集群,一个业务请求也就在一台主机里处理完毕成本极低,而改成微服务在AWS上,首先几十台虚机有事没事也得在那交钱了,然后一个业务请求来了,一堆系统间分布式事务,你才意识到所有云主机间通讯全要产生成本,就像开玩笑说的呼吸都要交钱,据我所知很多中小型公司每个月要花几万到几十万美金在AWS上,所以你就该明白为什么Amazon股价涨到天际,而谁才是最大的赢家了。
  6. 分布式事务处理及跟踪:与大系统不同,在微服务里面,一个业务请求往往是需要多个子服务协同来完成,原本的写在一个service类里的业务逻辑,或者一个复杂的SQL操作,现在变成跨好几个系统的分布式事务,那么如何保证事务的完整性,如何跟踪事务处理的过程和成败,这个复杂度也是相当的高,我下面就会详细的介绍一下这一块。

4. 微服务架构下的分布式事务

微服务架构下的分布式事务基本走的路线是多服务协作模式,那么主要的协作模式分为两种:交响乐Orchestration和**圆舞曲Choreography **
enter image description here

4.1 交响乐Orchestration模式

特点是像交响乐团有一位指挥家一样有一个中心控制服务(通常是一个工作流BPM系统),由它来负责告诉其他系统在什么时间做什么事,主要的分布式业务逻辑全部在这个中控服务当中。

4.1.1 交响乐Orchestration模式优缺点:

  • 优点是逻辑集中central brain,有统一地方方便出报表和查看逻辑走向
  • 缺点是单点依赖,这个服务出了故障整个系统就瘫痪了

4.2 圆舞曲Choreography模式

可以想象成站成一派的芭蕾舞演员,按照顺序旋转,它的特点是每个系统只关心自己的动作(自己系统相关的逻辑)和相关系统的动作,各个系统之间通过消息驱动实现联动。

4.2.1 圆舞曲Choreography模式优缺点:

  • 优点是业务专注,而且decouple,对其他服务的依赖不高,由于采用消息驱动,基本是异步相应模式,对平衡负载和稳健性都有帮助
  • 缺点是很难把握整体业务逻辑,整体比较凌乱,出了问题也不好跟踪调试

4.3 交响乐Orchestration模式和圆舞曲Choreography模式的对比

4.3.1 来看个对比图:

enter image description here

第一张就是圆舞曲模式,可以看到系统间交互都是比较零散的,第二个就是交响乐模式,可以看到系统交互是集中式的

再来看两个图例,这部分图文基本都是引用自这篇文章:https://microservices.io/patterns/data/saga.html
enter image description here

4.3.2 在交响乐模式下,一个订单创建流程基本是这样的:

  • 订单服务在本地创建一个pending状态的订单
  • 订单系统调用客户管理服务,查询客户可用信用额度
  • 如果客户管理系统返回结果为客户额度可用,则订单服务更改订单状态为approved状态
  • 如果客户管理系统返回结果为客户额度不可用,则订单服务更改订单状态为cancelled状态

enter image description here

4.3.3 在圆舞曲模式下,一个订单创建流程基本是这样的:

  • 订单服务在本地创建一个pending状态的订单,然后publish一条OrderCreated消息
  • 客户管理服务响应这条消息,开始查询客户可用信用额度
  • 如果客户额度可用,客户管理服务会publish一条CreditReserved消息,订单服务响应这条消息更改订单状态为approved状态
  • 如果客户额度不可用,客户管理服务会publish一条CreditLimitExceeded消息,订单服务响应这条消息更改订单状态为cancelled状态

5. 个人的一些经验分享:

我其实当初是负责一个Orchestrator指挥家服务的,这个服务主要责任是调用投资者服务、贷款服务等其他系统来完成发放贷款的流程,由于是总控系统,内部有BPM流程引擎,也是一个状态机。在这个服务里可以清晰的看到BPMN的流程图,也可以很容易的出报表因为它包含了每一笔贷款发放的每一步具体信息。
但是到后来我是比较倾向于Choreography圆舞曲这种模式的,主要原因如下:

  • 由于BPM流程引擎本质上是一个状态机,为了保证状态数据正确它实际上相当于一个单线程模式,这样就成为一个阻断的的系统,只能一步一步来,性能是有瓶颈的
  • 系统间交互如果采用Rest API 调用的方式,实际上servlet是阻断式的,而圆舞曲模式是pub-sub的模式,是非阻断异步式系统,同时也是响应式的,这些都增加了系统的稳定性和灵活性
  • 从我的工作经历来看,central brain确实不是一个好设计,典型问题就是系统间耦合太重,而主控系统责任大要求高,首先一旦主控系统出了问题或者bug,贷款马上发放不了,其次无论其他任何系统出了故障,主控系统只能等着,整个系统实际还是环环相扣,容易出问题
  • 圆舞曲模式由于采用消息驱动模式,系统间耦合度低,天生可以均衡负载,另外单点出了故障并不会阻断其他系统,各系统只订阅自己感兴趣的message,处理起来灵活,整个系统可以高并发无阻断

当然我们也要看到圆舞曲模式也不是完美无缺的,它对技术人员的要求相对更高,要比较熟悉消息驱动模式,还由于信息分散导致出报表要采用比较复杂的解决方案如CQRS和Event Sourcing这些。

6. 最后推荐一些学习资料:

版权说明:文中图片全部来自网络,版权属于原作者。文字部分都是我个人经验,转载请告知,谢谢!

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐