亿级订单同步

  “你最近一段时间把我们的***页面查询优化一下”,刚入职的我接到领导这了这个任务,做为IT老鸟,这应该是So easy的,心想,该我表现的时候了,百分百没建索引,或是建了不合理的索引导致没有用上索引,这东西应该不要“一段”时间吧?当我信心满满地找熟悉这块的开发人员了解情况时,顿时当头暴击啊,我们用的是mysql数据库,先select count(id) 来一下,苦苦等等了近5分钟,给我个结果三千多万。“汗”下来了,跟据经验来说,mysql百万级,oracle千万级,现在都三千万了,而且了解下来会每天都有几万的新增,即使你这次搞定了,那以后呢,何时是个头啊?

  所以啊,得换个思想来解决了,常规的解决方案是分库分表、全部切换为cassandra,hbase等nosql数据库、用专业的查询中间件ES来做查询。切换为nosql和分库分表都不现实,因为这个东西是老系统,懂行的都走的差不多了,各种流程交织,特别是数据库新增和修改相关 谁也不敢动手,剩下的也就只有采用ES来做查询这条路了。我们可以保留现有的入库流程不动,只是查询由mysql改为es,这并不是问题,查询不会影响到其它模块,可以放心地改,缺点就是多了一份存储,有点让费资源,但相对于查询不可用来说肯定是划得来的。

  方案定了,接下来就是实施了,摆在面前有这么2座大山需地翻,第一:实时的mysql到es的增量同步如何做?第二:几千万的全量如何实施?但我和大家找各种同步方案不同的是,我有秘密武器啊,它就是"duckula"。

  分布式binlog监听中间件duckula能像吸血鬼一样从各mysql实例中得到变化的数据,又能自动复活(HA).支持插件化数据接收者和序列化.非常灵 活.,可在自定义接收者,项目内置了kafka和redis接收者,也可以自定义序列化格式,项目也内置了protobuf2/protobuf3序列化.通过插件的形式嵌入到 duckula. 具有丰富的界面操作,可以通过页面操作进行任务的创建,任务的启动与停止.合适的调度策略,当某个task由于某种原因"自杀"后,系统会自动 选择其它占用资源较少的服务器来运行此task.支持GTID和文件名+位置的2种形式的起动监听方式,且可以选择以前的任何位点进行监听(只要能起得 来).支持docker和k8s运行.支持metrics的计数。

  duckula最初确实较为简陋,仅支持binlog监听,监听后实时推送到kafka中间件就完了。但做为一个完整的mysql到ES的同步方案却还差了2步,就是监听kafka并实时推送到ES和全量把mysql导入到ES二步。越想越美好,看起来很完美了,但实施起来却要考虑的问题就很多了,由于我们要开发的是一个中间件,并不是简单的“项目”,做为中间件,那它的HA功能是必备的,由于kafka的监听要实时入ES,那么它的性能也不可忽视,一个中间件要做到较灵活,插件化是必需的,kafka的监听如果只能入ES,那太可惜了,后面肯定还要做到入另一个mysql实例,入cassandra,入hbase,入各种其它的存储类中间件,这样duckula的使用场景就较为宽广,所以我们要做插件化,还有从kafka拿到数据后,有些需求需要做数据转换、数据过滤、数据格式化等,那么duckula就得支持用户自定义插件功能。mysql的全量导入这块,我们也有过 挣扎,最开始想着直接拿外面开源的来导一次就好了,最开始看的是datax,但那时它只支持es5的全量导入,我们选型用的是es6,5和6跟本就不兼容,然后想着没办法,我来开发一个datax的es6的插件吧,最后一想,不对啊,为什么不自己实现一个全量导入es6功能呢,即然要做中间件,要做实时推送解决方案,全量这块也是非常重要的一环,没有它,duckula就不完整了,谁会想解决一个mysql同步es的功能去弄两套方案交差玩?所以后面我们就放弃找开源的全量方案的想法,自己玩,构建一个闭环。
  在做全量导入这块,也碰到一个大坑,几千万数据怎么快速入到ES呢? 我们用最容易想的limit方案,但是现实却狠狠打脸,前面跑的很好,到后面深度翻页了CPU直接100%,且没有降的趋势,这肯定会影响线上系统的。网上找了一个以为靠谱的方案(后面不用了,也忘了啥方案了),还是搞不定,由于工期要求紧,没办法,只能采用最笨的方案,把这张表做一个快照放到一个独立实例中,不影响线上系统,全量就采用多线程在那慢慢滚,当然在做全量前先要开启增量到kafka,但先不导到ES,等全量做完后再把kafka的数据从在ES上重演一次就可以了。

  不能用在线数据库的来做全量显然是不达标的。如何才能在不影响线上系统的情况下做全量呢?我再次拿起了disruptor神器。为了提高性能又不至于撑爆内存,我分为三步来做批量导入:

第一步:由一个单线程通过limit 方式,一次取20000个ID,select id from table where id>=0 limit 20000 ,第二次就变为select id from table where id>=20001 limit 20000 这样子,最后一次取到的记录数小于20000我们就认为取完了。取到20000个ID后把它们由小到大500个ID放一个单元,不是放全量的500个ID值,只要放一个最小值和最大值就可以了。

第二步:把第一步的每个单元里的最小值,最大值拿到,拼SQL,select * from table where id>=最小值 and id<=最大值,把500条记录的详细信息填放在本单元。

第三步:把第二步的500条记录的全量信息组装好批量发送给ES。

每个单元格的这三步是串行的,但对于整个ringbuff来说它们是并行的,这也是把串行化的逻辑并行处理的绝佳方案。经过这次处理后,我们做过一波压测:3台ES对等节点(4U32G),150个字段的表全量达到12000条/秒,对于50个字段左右的表达到26000条/秒的批量入库速度。几千万也就1个小时不到就完成了全量,由于都拆分成ID区间查询的小SQL,对于有聚族索引保障的ID查询对数据库毫无压力,数据库指标一切正常。

  翻过这二座大山后,duckula的雏形也基本告一段落了。后面我们又上了paas,基乎所有的中间件都上了k8s,那么duckula也肯定不能落后啊,肯定得搬到k8s上。但我们走的更远,进一步,把它SaaS化,数据同步并不是只有基础架构组才能玩的东西,SaaS后,就是各项目组的开发人员,都可以按需求在界面上点几下,就可以完成数据实时推送的功能了,各项目组要研究的就是如何正确使用ES了。

发布了20 篇原创文章 · 获赞 1 · 访问量 3746
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览