使用canal同步MySQL数据到ES的有序性保证

最近在做的项目中有用到canal实时同步MySQL的数据,并且写入es的场景,总结了一些心得,以备后查。
总体同步的流程图如下:


MySQL-es process.png

链路中的环节稍微解释下:

  • binlog MySQL的自身的操作日志,用来记录数据的变更操作及变更后的数据。需要开启并配置 binlog-format 为 ROW 模式。具体可查看canal文档

  • canal alibaba开源的用来同步MySQL binlog的工具,简单来说canal就是把自己伪装成了MySQL的一个slave,然后同步其binlog。具体使用方法和原理可以查看github主页https://github.com/alibaba/canal,里面写的很清楚了。P.S.这里表扬一下阿里巴巴,最近几年拥抱开源社区,开源了好多好用的工具,如datax,canal,druid等。

  • rocketMQ 阿里巴巴出品的消息中间件,现已孵化为apache顶级项目。具体文档可参考官网http://rocketmq.apache.org/

  • application自己实现的一个应用,主要的作用是消费mq中的消息,并且将其写入es。

  • Elasticsearch 基于Lucene的一款全文搜索引擎,在MySQL无法处理的海量数据的查询场景中发挥着重要的作用。具体文档可参考官网https://www.elastic.co/

为什么要保证有序性?原因很简单:更新和删除的操作,如果出现了先发后至/后发先至的情况,就会导致es里的数据是比较旧的数据。

对于如何保证有序性,我们首先要分析一下到底是哪一步破坏了有序性。一步步从头看:

  1. MySQL => binlog,显然它一定是有序的;
  2. binlog => canal,canal的原理是伪装成slave来dump binlog,这也是有序的,否则MySQL主从就不同步了;
  3. canal => rocketMQ,通过查阅canal的官方文档中的mq顺序性问题一节,发现只有指定了pkhash消息投递方式,且pk出现变更才可能出现无序,由于我们并不会出现这种情况,所以这步也是有序的;
  4. rocketMQ => application, 通过查阅rocketMQ的官方文档中的consumer一节,发现消息的消费是否有序取决与使用的是OrderlyListener还是ConcurrentlyListener,顾名思义,前者是保证有序消费的,后者是不保证但吞吐量更高的,所以这里是一个可以设置的点;
  5. application => es, 通过查阅Elasticsearch的官方文档中的versioning
    一节,发现es是通过版本号来控制更新/删除操作的有序性的,版本控制又分为两种:internalexternal,内部版本号是默认使用的,即操作时传入的版本号必须与文档当前版本号一致才可以操作成功,而外部版本号则是操作时传入的版本号必须大于文档当前版本号才可以操作成功,这里又是一个可以设置的点。

从上面的分析可得,我们可以在两个环节进行有序性的保证,一种是在第4部消费消息的时候保证有序性,另一种是在第5步es写入的时候保证有序性(更准确地说,应该是保证更新的数据总是能覆盖旧的数据)。

第一种实现方式很简单,只要在你的application中使用OrderlyListener来消费rocketMQ的消息,并且在写入es异常时返回ConsumeConcurrentlyStatus.RECONSUME_LATER,就能保证消息消费的有序性及消息消费成功(写入es)才会消费下一条消息。但由于这里用的是OrderlyListener,牺牲了并发的性能。而实际场景中我们关心其实是对于同一条数据的操作的有序性,而非整张表操作的有序性,在一个表一个topic的配置下所有的消息都变得串行了。所以为了达到更高吞吐量可以考虑下面一种方式。

第二种实现方式也是我比较推崇的,这需要表结构的配合,并在操作es时使用external外部版本号。首先需要为每条操作设置一个版本号,且新的操作的版本号一定要大于旧的操作,很显然,数据的变更时间戳很适合作这个版本号。那么我们就需要在创建表的时候为表增加一个updated_time并且由数据库来维护:

updated_time datetime(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3)

其实这个应该是每个表都默认有的字段,我在《设计之道-数据库设计》也有提过。这里和当时不同的是将精度设置为了3(毫秒),datetime不指定的话默认是秒。因为在实际业务场景中,同一秒钟同一条数据发生多次更新是很有可能的,如果设置成秒的话,生成的版本号就相同了,那么就无法正确写入es了。当然如果你的业务够牛逼,同一毫秒都能有多次更新,那么你可以设置为6(微秒)。这样我们在消费消息的时候就可以使用性能更好的ConcurrentlyListener并发地消费消息,只要在es写入时指定使用数据的updated_time时间戳作为外部版本号,这样即使出现了先发后至的情况,较老的数据由于版本号一定比新的数据更小,也无法覆盖es中已经存在的数据。

这里可以稍微展示下ES中指定外部版本号后更新的现象:

  1. 创建一个索引,这时我们能看到它的版本号是1。


    创建索引
  2. 将这个索引做一次全量替换,我们发现它的版本号变为了2。


    更新索引
  3. 接下来我们继续更新索引,这时我们指定外部版本号,并将版本号设置为1,便会出现version confict,原因也很明确:当前版本号2大于或等于传入的版本号1,写入失败。

    使用比较旧的版本号更新

  4. 接下来我们使用版本号3进行更新,看到es返回更新成功,并且版本号也变为了我们指定的3。


    使用新的版本号进行更新

上面的步骤3、4,确保了ES中即使出现了先发后至/后发先至的情况,在使用数据库update_time作为版本号时也不会出现老数据覆盖新数据的情况。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,444评论 4 365
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,867评论 1 298
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,157评论 0 248
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,312评论 0 214
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,673评论 3 289
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,802评论 1 223
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,010评论 2 315
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,743评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,470评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,696评论 2 250
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,187评论 1 262
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,538评论 3 258
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,188评论 3 240
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,127评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,902评论 0 198
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,889评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,741评论 2 274

推荐阅读更多精彩内容