《企业级容器云架构开发指南》—2.3.4 微服务事件驱动管理

举报
华章计算机 发表于 2019/05/30 22:33:51 2019/05/30
【摘要】 本书摘自《企业级容器云架构开发指南》一书中的第2章,第2.3.4节,编著是闫健勇 龚 正 吴治辉  屈晓萌 王健飞 王 伟 刘晓红。

2.3.4 微服务事件驱动管理

其实微服务事件驱动管理是为了解决一致性的问题。因为如果我们当初在单体里用一个交易型数据库,很容易就能够实现:

原子性(任何改变都是原子的)。

一致性(数据库状态始终一致)。

隔离性(即使交易并发执行,看起来也是串行)。

交易一旦提交不可回滚。

鉴于以上特性,应用可以简化为:开始一个交易,改变(插入、删除、更新),然后提交这些交易。

使用关系型数据库带来另外一个优势在于提供SQL支持。用户可以非常容易地通过查询将多个表的数据组合起来,RDBMS查询调度器决定最佳实现方式,用户不需要担心如如何访问数据库等底层问题。另外,所有应用的数据都在一个数据库中,很容易查询。对于微服务架构,由于数据都是微服务私有化的,只能通过API访问,且不同微服务经常使用不同的数据库,因此可能带来以下挑战:

如何在完成一笔交易的同时保持多个服务之间的数据一致性。

如何从多个服务中搜索数据。

原来数据库很轻松做到的事情,到了微服务时代,为了做这件事我们要额外地做很多事情,目的是为了保持多个服务之间的数据一致性,那么我们要做什么呢?

当重要事件发生时,微服务会发布一个事件,当订阅的微服务接收此事件时,就可以执行相应的操作,一般会通过消息代理交换事件。举一个例子,如图2-22所示,订单如果生成了,要扣减个人的信用,只有信用扣减成功,这个订单才真正成功。

image.png

图2-22 事件驱动架构

我们可以将这个例子分为3步:第一步,我们要由订单服务创建一个订单,并发布订单生成这一事件;第二步,要扣减客户信用,之前是客户在这个服务订阅了订单生成事件,当它接收到这个事件的时候,就会扣减相应的信用;第三步,在扣减信用成功之后,再发布一个事件说明扣减信用成功,这个时候又通知到订单服务,订单服务才能够知道信用扣减成功了,这个订单的状态才真正地可以开始后续的流转。

如图2-23所示,关于如何保证原子性的更新状态和发布事件,目前业界有3种办法。

办法一:使用本地交易发布事件。要求程序员在所有订阅、被订阅的状态更新之后都要发布事件,如果在后续的测试中发现没有发生,那么就认为这个程序员的程序开发是不行的,所以这是靠人写一个订单,然后再写一个事件。这种办法的优点是可以确保事件发布不依赖于2PC,但缺点是需要开发人员牢记发布事件,有出错的可能,且无法应用于某些NoSQL数据库。

办法二:挖掘数据库交易日志,从数据库ORDER表中找到当ORDER某个状态发生到什么的时候,由数据库自动发布这个事件。交易日志挖掘通过发布事件和应用业务逻辑分离得到简化。只有当数据库不可用的时候才会发生问题,所以相对于第一种方式这个方式可靠很多。但这个方式不太容易做到,因为数据库的交易事件是海量的,如何从海量的日志中找到它该发布日志的交易事件?以后如果数据库变动频繁,后续的分析、解析、发布实践也会跟着变,所以这个工作也是很复杂的。

办法三:使用事件源,改变原有我们对整个数据库表的定义。ORDER表不再是订单对一个状态,它直接记录每一条流水,而不是记录最终状态。把每一笔订单的每一次变化都作为一个持久化事件直接记录到数据库,因为持久化了每一个事件,所以也就能够按时保持住这些具体该发布事件的原子性。只要状态变化就能可靠地发布事件,也解决了数据一致性的问题。该方法提供了可靠的业务实体变化的监控日志,使得单体应用迁移到微服务相对容易。所以相对来说这种方式是最可行的,工作量也不是很大。但是因为持久化的是事件,而不是原来的实体,这种方式会使整个库表结构变得更难以理解,不像以实体直接去做库表结构那样清晰,所以这对开发人员的水平要求更高。

交易型数据库在做微服务的初期更多还是先去做纯查询的、纯的无状态的业务,这样会容易上手。如果直接要把一个有状态交易型数据库进行微服务拆分,后期难度会更大。

image.png

图2-23 如何原子性地更新状态和发布事件


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。