微服务架构之服务拆分确定服务边界

微服务拆分原则和方法:

              单一职责、高内聚低耦合;

              服务粒度适中;

             考虑团队结构:(康威定律:设计系统的组织其产生系统的设计和架构等价于组织间的沟通结构。就是指每个团队开发设计和测试发布自己团队的微服务时,要互不干扰系统效率才能得到提升,)

             以业务模型切入:(领域模型:对具体某个边界领域的抽象,反应了领域内用户业务需求的本质。领域模型只反应业务与任何技术是现实没有关系的,不仅反应领域间的实体概念还能反应领域间的过程概念)

             演进式的拆分;

             避免环形依赖与双向依赖:(如:商品服务于订单服务相互依赖)

                  1.容易造成死循环(服务僵死,或cpu达到100%)

                  2.在发布上线,代码回滚,故障恢复,和升级重构时,都是要按照一定的顺序进行的

                  3.会造成服务间紧密耦合,业务很难理解

好的微服务架构具备的特征:

                  微服务架构之服务拆分确定服务边界

                 微服务拆分步骤:

                      分析业务模型:

                               弱耦合在一起

                                高内聚力

                      确定服务边界:

                                服务应包含单一的界限上下文

分析业务模型:

                            微服务架构之服务拆分确定服务边界

                             用户服务:用户 经纪人 经纪机构 (不依赖其他服务)

                             房产服务:房产  推荐(依赖 用户服务  评论服务)

                             评论服务:评论 百科(依赖  用户服务)

                            需要一个网关对后端服务进行数据集合,并且对前端用户做身份鉴别:

                            微服务架构之服务拆分确定服务边界

                            房产不依赖评论是因为恰好API GATEWAY在做数据集合时帮我们做了关联。房产详情页面下面有一个评论                           页。APIGATEWAY去获取该房产的评论信息。通过API GATEWAY将两者关联起来。

确定服务边界:

                       微服务架构之服务拆分确定服务边界

              评论服务的用户模型只包含用户头像、用户名称这些信息,并不包含用户密码和自我介绍这些信息。用户服务需要为评论服务提供接口获取这些信息。

           用户服务和房产服务都关联一个经纪人,房产服务和用户服务共享模型是经纪人。房产服务只需要从用户服务那获取经纪人的一些信息,包含email头像联系方式等,并不需要包含密码信息。用户服务也需要提供接口给房产服务来访问。

         一个复杂的系统在拆分时确定好服务边界是很有必要的,他为我们的API接口提供了基础。

服务数据库的拆分 :

        在微服务中一个服务一般对应一个数据库:评论库、用户库、房产库。

         微服务架构之服务拆分确定服务边界

         数据表并没有发生变化,只是放在了不同的数据库中了,用户模型是最容易和业务产生关联关系的模型。如果所有的关系都维护在用户服务中,用户服务会非常庞大。将数据表放在各个对应的业务中。避免庞大业务的出现。

数据一致性:

         在微服务架构下,每个服务对应一个数据库,这就出现了在原来单体应用中,对同一个库的操作变成了跨服务数据库的操作。遇到有事务约束的场景,(比如转账汇款、订单状态、和库存扣减),就从本地事务过度到分布式事务上来了。

          微服务架构之服务拆分确定服务边界

       分布式事务不适用微服务:首先两阶段提交会出现同步阻塞和加锁,并且有单点故障,由于锁的原因又降低了吞吐量。Nosql数据库并不支持2pc(两阶段提交)。

        在微服务架构下,使用最终一致性来替代分布式事务中的强一致性。

       最终一致性:是指不同服务节点在一段时间后,节点间的数据会最终达到一致的状态。

     有两种模式来完成最终一致性:

  1. 可靠事件模式,一般借助消息队列和内部表来完成。(可靠事件模式是只要他的前序时间发生后序事件就一定发生,如支付宝中的余额转到余额宝中,支付宝中的金额扣减余额宝中等额金额的增加一定会发生。)可靠性事件模式不能够回滚。
  2. 补偿模式:通过-sagas模型来实现的。Sagas模型实际上是一个长事务。Sag是一系列本地的有序事务,每个本地事务通过更新数据库发送消息来触发下一个本地事务。如果本地事务失败,sag会有序的执行补偿事务,来回滚刚才的操作。

 可靠事件模式:

              微服务架构之服务拆分确定服务边界

 

  1. 用户发起请求调用支付宝扣款并记录该事件记录到数据库中。(作用:向余额宝发送消息的时候需要定时的检测,检测余额宝服务是否进行了加款操作)
  2. 发送消息,经过消息队列,消息队列向余额宝服务进行投递消息。余额宝收到消息后进行加款并且记录事件到数据库中。通过事件id 唯一的记录用户发起的一个转账事件。
  3. 余额宝加款后会发送一个确认消息,经过消息队列投递给支付宝。支付宝收到这个消息之后就会 将本地数据库的事件进行删除。
  4. 也可能余额宝服务不稳定或者有一段事件宕机了,或者消费事件消息失败了,就需要支付宝服务发起一个定时任务,定期的检测数据库中的事件记录,然后定期的进行发送消息,直到余额宝服务投递出确认消息。
  5. 假如余额宝服务已经做了加款,那么下依稀支付宝服务再发送重复的消息之后。余额宝服务会通过数据库去看一下该事件有没有进行执行。如果说已经执行了就会再触发确认消息的发送。结果就是支付宝系统会删除本地的事件记录。

       我们看到整个过程是没有回滚的,只要保证了支付宝服务进行扣款,余额宝服务就一定会加款。

      为什么在实现可靠事件模式要通过消息队列而不是RPC调用呢?

  1. 我们去调用支付宝服务时并不依赖余额宝的返回结果,这个时候使用异步消息来处理,会提升系统的吞吐量。
  2. 数据库记录,以及定时任务。可以集成到消息队列,一起来完成。(比如rocketMQ他是支持事务消息的。使用了RocketMQ,数据库记录的事情是不需要去关心的)

 补偿模式:

           补偿模式是由一系列小事务组成的一个长事务。

           微服务架构之服务拆分确定服务边界

 

          由客户服务,商家服务,骑士服务,配送服务共同完成用户下单到送餐到家的流程。流程中拆分成四个事务。每一个事务都对应着发送消息和接收消息的操作,下单支付要发送消息给餐馆备餐。餐馆备餐也要发送确认消息,给下单支付。(每一个服务都是发送消息确认消息)。当我们的本地事务失败时,我们会发起一个补偿子事务(compensation transaction)。 补偿子事务是针对本地模式的一个反向操作。

          比如:当我们的骑士取餐失败之后,会在本地做一下取餐失败的记录,然后发消息到消息队列,通知商家服务触发备餐失败的子事务,备餐失败的子事务又会发消息给订单服务。订单服务会发起向客户退款的补偿子事务。

         无论是本地事务还是补偿子事务都是需要严格的按照顺序来进行执行的。补偿子事务也需要按照顺序进行反向操作。补偿子事务就类似与发起了一次回滚无论是本地事务还是补偿子事务都需要进行发送消息以及消费消息。在我们的案例中每一个服务都需要发送两个消息,消费两个消息。这就造成了代码比较复杂。

补偿模式的两个缺点:1.本地事务和补偿子事务都需要严格按照顺序执行。

                                     2.操作比较复杂,目前还没有框架来支持sagas的补偿模式。