浅谈CDC在微服务中的应用
CDC(Change Data Capture)是一种通过监测数据变更(变更包括新增、修改、删除等)而对变更的数据进行进一步处理的一种设计模式,通常应用在数据仓库以及和数据库密切相关的一些应用上,比如数据同步、备份、审计、ETL等。实际上,早在二十多年前,CDC就已经用来将应用系统的数据变更实时发送到数据仓库,进一步转换后传递到数据分析系统,这样能够在极小地影响生产的情况下,有效而及时地将数据传递到消费方。而在微服务架构逐渐流行的今天,这种古老的技术是否能够焕发新的生机?
1.CDC实现原理
在说CDC在微服务中的应用之前,我们有必要先了解一下CDC的基本原理。
关键也许就在如何监测数据的变更。拿MySQL来说,我们知道MySQL中有binlog(binary log)可以记录用户对数据库进行的修改事件,顺理成章,一个最简单高效的CDC实现就可以利用binlog来完成。当然现在已经有很多开源的MySQL CDC实现,开箱即用。使用binlog并不是实现CDC的唯一途径(至少对于MySQL而言),甚至利用数据库触发器也能完成类似的功能,但从效率上以及对数据库影响的层面来看可能就相形见绌了。
通常而言,CDC捕获到数据库的变更之后,会将变更事件发布到消息队列中供消费者消费,例如Debezium,将MySQL(也支持PostgreSQL、Mongo等)的变更持久化到Kafka中,通过订阅Kafka中的事件,就可以得到变更的内容,实现我们需要的功能。
2.微服务解耦
我们刚才已经了解到,通过CDC可以把数据库的变更转变为各个“事件”,从而可以以“只关心这些事件”的方式来处理。对于传统的大型单体应用,可以通过这种方式来进行解耦,进而拆分成微服务出来。同样,如果已经是微服务架构,有时候也可以运用CDC来简化服务间的调用。
举个例子,我们在某项目中有这样的场景:
系统创建客户服务的预约,并分配给一个用户去处理 这些预约可能是用户手动创建的,也可能是通过第三方系统发送过来的 当系统中创建了预约、或者预约修改后,相关的用户会收到通知信息
很容易我们可以拆分出预约、通知两个服务出来。要想实现通知的功能,如果采用直接的做法,可以在通知的服务中定义一个接口来给某用户发送通知,这样在所有预约创建、修改的地方都需要进行相应的逻辑判断,并调用这个接口来发送通知。而实际上,有好几处地方都在创建或者修改预约信息,当这些业务代码需要修改的时候,都需要关心通知的部分是否需要作出修改。即便我们很小心的在维护这部分代码,但还是很容易会漏掉一些地方的通知逻辑,或者出现和业务要求上不一致的情况。
3. Data replication
(Event-carried State Transfer,图片来源:http://t.cn/ROGzKCB)
上图的架构中在Insurance Quoting服务中保存了一份customer的信息,这样当有需要查询的时候,不需要去调用customer management服务,而是直接从自己的副本中进行查询,这样做有一些好处:
提高了查询性能,直接从数据库里面拿,省去了远程调用 不用担心另外一个服务挂掉或者性能造成的影响,customer management挂了还可以用 缓解了customer management的压力
虽然好处不少,但是实现起来也不是那么容易,最大的问题就在于如何保证数据的一致(同步):当customer的数据发生了变化,如何告诉给insurance quoting?使用CDC来完成这个操作是比较合适了。通过CDC,我们可以将依赖系统的数据(只需要处理我们关心的部分)replicate到自身系统中,来支持自身系统的业务需要。
4.实现CQRS
(Example of CQRS,图片来源:http://t.cn/AiYxODiV)
5.CDC与Event Sourcing
(Eventuate Local Architecture,图片来源:http://t.cn/AiYxQdyV)
将事件可靠的持久化(只能新增新的事件而不能改变已经存在的事实) 根据一个ID查出一个实体上的所有有序的事件 将事件广播出去(当然这不应该是Event Store的职责,我们姑且认为是一体的)
利用RDBMS(关系型数据库)来保存事件是比较简单的一个操作了,需要注意的是需要保证事件的强一致性,在并发情况下,同一个聚合下多个事件同时发生的时候,需要保证这些事件依然是有序的,这里可以采取乐观锁的方式实现。
6.Puncturing encapsulation with change data capture
We're seeing some projects use CDC for publishing row-level change events and directly consuming these events in other services.
不同类型的Event都会存到这个表中,在存储Event的具体内容(Content)的时候,因为每种Event的内容不尽相同,我们可以选择以Json的方式存储,也可能会直接序列化成二进制格式。而下游系统关心的可能是特定类型的Event的特定内容,如果不加修改就将这个表的变化广播出去,那么下游系统就会依赖于我们的存储结构了,而且需要自己进行数据加工才能得到自己想要的数据。换而言之,如果以后发生改变,那所有的订阅者都得跟着改,这个是一个很大的隐患,会使得服务间的集成相当脆弱。
7.写在最后
- 相关阅读 -
点击【阅读原文】可至洞见网站查看原文&绿色字体部分的相关链接。
本文版权属ThoughtWorks公司所有,如需转载请在后台留言联系。