PB 级的 ES 准实时索引构建之道
该如何解决呢?仔细观察上面两个问题,其实都是同一个问题,如果我们能实时监听到 db 的字段变更,再将变更的内容实时同步到 ES 和宽表中不就解决了我们的问题了。
怎么才能实时监听到表字段的变更呢?
答案:binlog
来一起复习下 MySQL 的主从同步原理
- MySQL master 将数据变更写入二进制日志( binary log, 其中记录叫做二进制日志事件binary log events,可以通过 show binlog events 进行查看)
- MySQL slave 将 master 的 binary log events 拷贝到它的中继日志(relay log)
- MySQL slave 重放 relay log 中事件,将数据变更反映它自己的数据
可以看到主从复制的原理关键是 Master 和 Slave 遵循了一套协议才能实时监听 binlog 日志来更新 slave 的表数据,那我们能不能也开发一个遵循这套协议的组件,当组件作为 Slave 来获取 binlog 日志进而实时监听表字段变更呢?阿里的开源项目 Canal 就是这个干的,它的工作原理如下:
- canal 模拟 MySQL slave 的交互协议,伪装自己为 MySQL slave ,向 MySQL master 发送dump 协议
- MySQL master 收到 dump 请求,开始推送 binary log 给 slave (即 canal )
- canal 解析 binary log 对象(原始为 byte 流)
这样的话通过 canal 就能获取 binlog 日志了,当然 canal 只是获取接收了 master 过来的 binlog,还要对 binlog 进行解析过滤处理等,另外如果我们只对某些表的字段感兴趣,该如何配置,获取到 binlog 后要传给谁? 这些都需要一个统一的管理组件,阿里的 otter 就是干这件事的。
什么是 otter
Otter 是由阿里提供的基于数据库增量日志解析,准实时同步到本机房或异地机房 MySQL 数据库的一个分布式数据库同步系统,它的整体架构如下:
注:以上是我司根据 otter 改造后的业务架构,与原版 otter 稍有不同,不过大同小异
主要工作流程如下
- 在 Manager 配置好 zk,要监听的表 ,负责监听表的节点,然后将配置同步到 Nodes 中
- node 启动后则其 canal 会监听 binlog,然后经过 S(select),E(extract),T(transform),L(load) 四个阶段后数据发送到 MQ
- 然后业务就可以订阅 MQ 消息来做相关的逻辑处理了
画外音:zookeeper 主要协调节点间的工作,如在跨机房数据同步时,可能要从 A 机房的节点将数据同步到 B 机房的节点,要用 zookeeper 来协调,
大家应该注意到了node 中有 S,E,T,L 四个阶段,它们的主要作用如下
Select 阶段
: 为解决数据来源的差异性,比如接入 canal 获取增量数据,也可以接入其他系统获取其他数据等。Extract阶段
: 组装数据,针对多种数据来源,mysql,oracle,store,file等,进行数据组装和过滤。Transform 阶段
: 数据提取转换过程,把数据转换成目标数据源要求的类型Load 阶段
: 数据载入,把数据载入到目标端,如写入迁移后的数据库, MQ,ES 等
以上这套基于阿里 otter 改造后的数据服务我们将它称为 DTS(Data Transfer Service),即数据传输服务。
搭建这套服务后我们就可以通过订阅 MQ 来实时写入 ES 让索引实时更新了,而且也可以通过订阅 MQ 来实现宽表字段的更新,解决了上文中所说的宽表字段更新与原表紧藕合的问题,基于 DTS 服务的索引改进架构如下:
注意:「build 数据 」这一模块对实时索引更新是透明的,这个模块主要用在更新或插入 MySQL 宽表,因为对于宽表来说,它是几个表数据的并集,所以并不是监听到哪个字段变更就更新哪个,它要把所有商品涉及到的所有表数据拉回来再更新到宽表中。
于是,通过 MySQL 宽表全量更新+基于 DTS 的实时索引更新我们很好地解决了索引延迟的问题,能达到秒级的 ES 索引更新!
这里有几个问题可能大家比较关心,我简单列一下
需要订阅哪些字段
对于 MySQL 宽表来说由于它要保存商品的完整信息,所以它需要订阅所有字段,但是对于红框中的实时索引更新而言,它只需要订阅库存,价格等字段,因为这些字段如果不及时更新,会对销量产生极大的影响,所以我们实时索引只关注这些敏感字段即可。
有了实时索引更新,还需要全量索引更新吗
需要 ,主要有两个原因:
- 实时更新依赖消息机制,无法百分百保证数据完整性,需要全量更新来支持,这种情况很少,而且消息积压等会有告警,所以我们一天只会执行一次全量索引更新
- 索引集群异常或崩溃后能快速重建索引
全量索引更新的数据会覆盖实时索引吗
会,设想这样一种场景,你在某一时刻触发了实时索引,然后此时全量索引还在执行中,还未执行到实时索引更新的那条记录,这样在的话当全量索引执行完之后就会把之前实时索引更新的数据给覆盖掉,针对这种情况一种可行的处理方式是如果全量索引是在构建中,实时索引更新消息可以延迟处理,等全量更新结束后再消费。也正因为这个原因,全量索引我们一般会在凌晨执行,由于是业务低峰期,最大可能规避了此类问题。
总结
本文简单总结了我司在 PB 级数据下构建实时 ES 索引的一些思路,希望对大家有所帮助,文章只是简单提到了 ES,canal,otter 等阿里中间件的应用,但未对这些中间件的详细配置,原理等未作过多介绍,这些中间件的设计非常值得我们好好研究下,比如 ES 为了提高搜索效率、优化存储空间做了很多工作,再比如 canal 如何做高可用,otter 实现异地跨机房同步的原理等,建议感兴趣的读者可以之后好好研究一番,相信你会受益匪浅。
巨人的肩膀
- Elasticsearch简介及与MySQL查询原理对比:https://www.jianshu.com/p/116cdf5836f2
- https://www.cnblogs.com/zhjh256/p/9261725.html
- otter安装之otter-node安装(单机多节点安装):https://blog.csdn.net/u014642915/article/details/96500957
- MySQL和Lucene索引对比分析: https://developer.aliyun.com/article/50481
- 10 分钟快速入门海量数据搜索分析引擎 Elasticearch: https://www.modb.pro/db/29806
- ElasticSearch和Mysql查询原理分析与对比:https://www.pianshen.com/article/4254917942/
- 带你走进神一样的Elasticsearch索引机制:https://zhuanlan.zhihu.com/p/137574234