
技术干货 | 如何利用MongoDB Change Streams 实现数据实时同步?
当前实时数据同步的应用场景较多,实现方式主要有两种,一是数据库厂家本身提供了实时数据捕获工具,如 Oracle 的 OGG 等;另外一种是实时解析数据库的事务日志,获取到实时变化的数据后进行同步,如 Flink CDC 等。
对于 MongoDB 复制集来说,默认情况下,成员间通过 Oplog 实现的数据同步是有延迟的。因此,为了实现数据的实时同步,且能将数据同步到异构系统中,从3.6版本开始,MongoDB 提供了 Change Steams 功能,允许用户非常方便地将实时变更数据同步到下游系统进行处理。
其实在3.6版本之前,如果要实现这种实时同步,开发人员也可以通过实时解析复制集 Oplog 里面的日志条目来完成,只不过这种方式需要额外开发代码,实现起来较复杂。
实现原理
在应用程序里面,开启数据库或集合上的监听,一旦捕获到数据变更事件,就会产生变更流数据(类型为文档),变更流里面包含具体的动作(如 insert、delete、update 等)和变更的文档,应用程序可以将此变更流数据发送到下游系统,由下游系统进一步处理(如完成下游系统相应数据变更,实现数据实时同步)。
本质上,Change Streams 特性,可以完成与 Kafka 或 RabbitMQ 等消息组件类似的功能,这样当需要将 MongoDB 集群中的数据,向异构系统实时同步时,我们就不需要额外再部署一套类似 Kafka 等消息处理的集群了。
Change Streams 整体流程如下图所示:
可以看到直接打开 MongoDB 的 Change Streams 变更流监听,就可以实现向异构下游系统实时同步数据。。
实时流数据的格式
复制集与下游系统间的数据同步依赖于实时生成的变更流数据,实时流数据的格式为文档类型,包含如下字段:
打开实时数据流
打开一个实时数据流,会返回一个 cursor,变更的数据可以通过循环遍历 cursor 获得,相当于打开一个水龙头,水会源源不断地流过来。
针对不同编程语言的驱动,MongoDB 都提供了相应的 API 来打开实时数据流,下面以 Python 为例子进行说明,如下客户端应用代码:
其中,语句db.inventory.watch()
表示打开一个实时变更流,监听集合 inventory 上的任何数据变化。
for 循环语句对游标循环遍历,实时打印变更流里面的文档。
先运行上面的代码,再通过 mongo 连接到复制集,模拟向 inventory 集合插入、修改、删除数据,观察上面的代码是否能实时输出流数据。
插入数据语句如下:
如果实时输出如下流数据,说明打开的实时数据流是正确的:
同理,测试删除数据,如下语句:
也能实时输出如下信息:
*注意:删除变更操作,输出流数据不包含字段'fullDocument'
最后,测试下修改数据,如下语句:
实时输出如下流数据:
注意:默认情况下对于 update 操作,输出的实时流数据也不会包含字段'fullDocument'
;但是可以在打开变更流的方法里传入可选参数full_document= 'updateLookup'
实现输出的实时流数据包含'fullDocument'
字段及值,如带参数语句:cursor = db.inventory.watch(full_document='updateLookup')
控制实时流数据的输出
在有些场景下,需要控制实时流的输出,希望将不同的流数据传给不同的下游系统进行处理,类似快递公司的包裹分拣系统,将送往不同地方的包裹分开,如下图所示:
MongoDB提供了一种管道模式来处理这些数据流,当流数据经过预先配置好的管道时,数据会依次被管道中的每一个步骤进行处理。
这种数据处理模式与MongoDB自带的管道模式聚集框架类似。
如下代码示例:
先构造一个管道,然后在打开实时数据流时传入管道参数。
通过管道参数,从数据流里过滤出满足'fullDocument.model':'SIM'
条件的数据流,然后再向数据流添加一个额外的'newField'
字段。经过管道处理后的数据流可以被下游系统作进一步处理。
针对 MongoDB 4.2 版本,其它还可被使用的管道操作符有:$project
、$replaceRoot
、$replaceWith
、$redact
、$set
、$unset
注意:上面代码对实时数据流的处理只是简单的循环打印,如果需将数据实时同步到其它系统中,如 MySQL、Hbase 等,需要应用开发人员进一步编写相应的逻辑代码进行处理。
文章转载自公众号: Mongoing中文社区
