前言
随着业务发展的越来越快,订单越来越多,针对于搜索场景和详情查询场景的需求越来越多,亿级订单的查询和同步需要进行详细的了解。
公司业务发展到一定规模后,类似于全文检索的需求或者高频的key:value需求比较多,推荐采用ES+HBase的方案,同时数据会先写入数据库,在通过binlog的方式维护增量数据到ES+HBase,ES本身是非实时性查询系统(ES的写流程决定),这种就造成了ES和HBase是一个准实时系统。这种实时纬度是可以满足商家需求的。
现有解决方案
关键技术:
- ES+HBase解决搜索和详情需求
- canal将数据库变更写入MQ,增量追加到ES+HBase中,采用同步系统解决数据同步需求
同步实现
单表顺序解决
通过顺序解析binlog,为每条statement sql执行结果分配一个顺序SeqNo,SeqNo保证有序,通过NoSql中乐观锁控制解决顺序问题。
HBase:
HBase内部拥有timestamp协助控制每个qualify版本,只要让timestamp传入构造上文的顺序SeqNo,就可以保证每个字段读取数据是最终一致的。
ES:
ES对于单表场景可以通过index的操作来进行写入,index可以采用exteneral版本来进行控制,使用上文的SeqNo来做乐观锁解决。
多表同步
多表同步和单表同步的区别在于,不同表产生的binlog的SeqNo,如果因为网络抖动造成SeqNo顺序不匹配,无法写入Nosql中。
HBase:
HBase自带版本号会自动处理或丢弃低版本数据,设计过程中可以将每个table表中的字段列入HBase中。
- 针对订单主表,我们写入的数据以订单号做 hash,然后以 hash 值:订单号作为主键降低热点问题,同时定义单 column family,qualifiy 格式为 表:字段 value为对应的 value 值,timestamp 为 SeqNo。
- 针对订单商品表,我们写入的数据同样以订单号生成相应的 rowkey,同时定义单 column family,qualifiy 格式为 表:字段:对应记录的 id 值 value 为对应的 value 值,timestamp 为 SeqNo。
- 通过上述写入,能够针对具体到某个字段都有对应的 timestamp 值的更新,为后期写入更新数据能够更新到具体字段级别。
ES:
ES没有HBase这种列版本号,只有Doc级别的version,如果出现来SeqNo2>SeqNo1,同时SeqNo2早于SeqNo1写入ES中的情况,会出现SeqNo1数据内容无法写入。
如果保证数据有序就可以解决这种问题了,所以整个链路中canal消费binlog数据就需要保证有序的放入MQ中,MQ保证顺序投递到Sync消费处理程序中,通过消费消息后ack告诉MQ消费成功,已经消费的消息保证所有数据全局有序。
我司的binlog处理,就是按照顺序通知给消费者实例进行消费,消费实例ack之后开始投递下一条消息,如果消费失败会进行重试,失败三次则进行告警通知,需要RD介入。
配置化同步
整个数据同步链路类似于logstash:
通过对组件进行抽象化,每个组件有对应的配置,由配置信息进行组件初始化,驱动组件去执行流程。
通过配置可以配置出任务,对于具体的任务逻辑可以采用groovy进行脚本编写,配置界面如下:
性能问题
ES同步多表时常出现性能问题:
- 性能瓶颈问题
- 失败堆积问题
性能问题:
大量写入情况下,Sync消费能力有限,智能针对于MQ中的分区进行消费,每个分区只有一个线程执行,消费速率和消费分区成正比,与消费RT成反比,尤其是大促场景下,常常会出现消费不过来的情况,数据堆积严重。
堆积问题:
因为需要进行顺序消费,只要某个分区某条消息消费失败,后续消息就会堆积,造成数据延迟。所以建议除非是业务量没有性能瓶颈的情况下采用顺序队列的场景。
可以借助HBase的字段级别版本号保证ES的顺序,所以对于订单这种对于顺序敏感的场景,采用HBase做一层代理,解决问题。
put写入数据之后,通过额外字段version做increment操作,两个写入完成之后,里面get拿到HBase的数据写入ES中。
扩展
目前订单同步采用加载配置文件方式,横向扩展的机器都需要加载同一份配置文件,但是存在以下问题:
- 我需要一台机器临时去消费数据解决线上问题;
- 有个量级很大但又不是很重要的任务,想不影响其他任务的进行;
- 要做对比,增量延迟对比或全量对比数据,但又不希望影响其他数据;
- 查询日志需要所有机器查看查询(当然,公司有内部日志系统,可直接上去查看) 如此,可以让同步系统无状态化,每个任务的配置加载有任务配置平台来进行配置,指定相关的机器做相关的处理,扩容也可以动态申请扩容,如图所示,可以自由分配机器处理不同的任务。
对于可能出现的问题,会采用数据对比的方式执行:
通过对比结果可以知道哪些数据不一致。