Mysql 数据同步到 ES 的技术方案选型和思考

4,518 阅读14分钟

MySQL 到 ES 数据同步本质上是数据去规范化的一种。本节我们展开 “MySQL 到 ES 数据迁移同步” 的技术解决方案,通过比较他们的优缺点和应用场景给读者提供一些思路。

去规范化

数据库规范化 是指关系数据库中通过一系列数据库范式来减少冗余、增强数据一致性的策略。

但是为什么要进行去规范化呢?

规范化在带来我们看得见的好处(利于事物操作性能、存储成本降低)的同时,伴随数据规模扩大、并发度提高、复杂度上升,他的弊端也慢慢展现。

这个时候通过数据库去规范化能够一定程度满足这些挑战,总体思路是通过一系列降低写入性能的操作例如更多的数据冗余、数据分组等来提升数据库读取的性能。

去规范化的时机

数据去规范化动机多样,当出现因数据复杂操作影响系统稳定性、业务响应/并发要求不满足等都是触发因素。

业务稳定性问题:面向 C 端的互联网应用特征是并发量较高,SQL 偏向点查点写,相对简单,但是沉淀下来的数据需要做运营往往涉及传统企业级应用对于数据库的操作特征。大范围数据删查、表关联、排序等实时操作,以及满足报表/BI 等更加复杂的数据库需求。通过去规范化和负载分离是较合理的选择。

复杂查询性能问题:企业级应用经常涉及表关联、聚合、多维筛选、排序等操作,并常常带来性能问题。通过去规范化的一些方式,如下文提到的数据冗余和预计算方式,显著改善性能。

去规范化的几种实现方式

列级处理 主查询表冗余字段

通过在主表冗余计算好的数据,可避免频繁重复计算数据。如下场景适合在主数据表内冗余数据:

  • 应用系统需要经常获取计算好的数据
  • 冗余的原始数据不经常变化

优点:方法简单,容易实现

缺点:侵入业务逻辑,拖慢业务代码性能的同时,长期迭代所产生的变化可能会有稳定性风险

表级处理 宽表预构建 / Cube 预构建

主要操作就是构建宽表,或者构建数据立方体(Data Cube)。构建好的宽表包含了用户查询时需要的所有维度、度量信息。

常见的表级处理包括:应用多写、数据库自身实现的物化视图、数据迁移同步。

应用多写

在主数据相同数据库内创建宽表,应用写入数据的同时也想宽表写入数据(事务保证一致性),复杂查询即可从该表进行。

优点:实现简单、低成本

缺点:对主数据库造成更大的读写压力,外加业务改造成本

RDBMS 物化视图

物化视图(快照)是包括一个查询结果的数据库只读对象,它是远程数据的本地副本,或者用来生成基于数据表求和的汇总表。通过数据冗余与预计算减少 join、聚合,从而提升查询性能。

优点:数据库引擎自身支持,使用成本较低

缺点:RDBMS 实现的方式有自己的局限性,比如生成物化视图的数据需要做一些业务紧相关变换就无法满足,或者某些数据库并没有完整实现该能力

数据迁移同步

借助数据同步工具,准实时将主数据表数据组织变换(包括按照业务逻辑变换)形成普通表或大宽表,写入第三方存储引擎。复杂查询直接在预构建好的表或者 cube 上执行,从而达到良好的性能。数据迁移工具的选择较多,总体上按照其侧重点,可以分为如下几类:

大数据类、流计算类、消息类、数据库类、云厂商类、专业数据迁移同步工具

优点

主库更稳定:异步化解耦业务系统事务查询和复杂查询,避免复杂查询对主数据库产生影响。

易运维、链路稳定:数据迁移同步链路有标准化产品支撑,和主业务系统、主库读写解耦。整体架构上职责清晰,易于维护和问题追踪。

缺点:需要对纷繁多样的数据迁移同步工具、承载复杂查询数据库产品选型。

MySQL 到 ES 数据实时同步技术架构

在此介绍 “MySQL 到 ES 数据迁移同步” 的技术解决方案

为什么选 Mysql?

高并发能力:MySQL 内核特征特别适合高并发简单 SQL 操作,链接轻量化(线程模式),优化器、执行器、事务引擎相对简单。

稳定性好:主数据库最大的要求就是稳定、不丢数据。MySQL 主备系统在应对崩溃的情况下快速切换,innodb 存储引擎也保障了 MySQL 下盘稳定。

操作便捷:良好、便捷的用户体验,容易上手,学习成本低。

开源生态:MySQL 开源,让上下游厂商围绕其构建工具相对简单,HA proxy、分库分表中间件让其实用性大大加强,同时开源的特质让其有大量的用户。

为什么是 ES?

ES 的几个显著特点,能有效补足 MySQL 在企业级数据操作场景的缺陷

文本搜索能力:ES 是基于倒排索引实现的搜索系统,配合多样的分词器,在文本模糊匹配搜索上表现得比较好,业务场景广泛。

多维筛选性能好:亿级规模数据使用宽表预构建(消除 join),配合全字段索引,使 ES 在多维筛选能力上具备压倒性优势,加上文本搜索能力,独此一家。

开源和商业并行:ES 开源生态非常活跃,具备大量的用户群体,同时其内后也有独立的商业公司支持,而这让用户根据自身特点有了更加多样、渐进的选择。

为什么是数据迁移同步方式?

稳定性好:迁移同步对主数据库的操作主要是进行数据和日志的顺序读取,同时并发小,对主数据库稳定性影响较小(较多的下游订阅可能在网络层面存在影响,一般用消息解决)。另外日志(Binlog/WAL/Redo 等)可重放特质,让下游丢数据的可能性大大减小(处理好幂等的情况下)

业务解耦:一般而言主数据库更多承载事务型操作,而下游数据系统承载运营等层面的业务。

业务侵入小:数据迁移同步对业务无侵入,双端对接标准数据库(源),可以便利地找到开源、商业、云等各个方向的成熟解决方案或产品。

业务适配性好:某些数据迁移同步产品能够嵌入业务逻辑,让下游获取到更加贴近业务的数据,从而让数据服务更加有效和便捷。

数据迁移同步模型选择

订阅消费

image.png 优点

堆积能力:由于引入了消息队列,所以整个链路是具备变更数据的堆积能力的。假设变更数据消费的比较慢,MySQL 本地较老的 binlog 文件由于磁盘空间的不足而被删除时,消息队列的数据依然存在,数据同步依然可以进行。

数据分发能力:引入消息队列后可以支持多方订阅。如果下游多个应用都依赖源端的变更数据,可以订阅同一份 topic 即可。

数据加工能力:由于变更数据是由下游消费者订阅,因此订阅后可以灵活的做一些数据加工。例如从外部调用微服务接口或者反查一些数据来做数据加工都是比较方便的。

缺点

运维成本相对较高:包含了较多的组件和应用,运维保障相对复杂。

稳定性风险较高:一环出问题会导致整个数据同步链路的稳定性收到影响。而且排查和定位问题也会比较困难。

端对端直连

image.png

优点

低延迟:端对端的直接同步,链路较短,延迟低

稳定性好:链路组件少,出问题概率较低,定位排查均比较容易。适合对数据精确性高的严苛场景。

功能拓展性强:对端写入消息系统,模拟订阅模式,可拓展性强

运维部署检点:链路组件少,部署运维更简单

数据迁移同步模型选择总结

如果没有众多的下游数据订阅,建议采用直连模式。数据同步链路往往置于在线业务中,随着业务规模以及重要性逐渐加大,链路稳定性更为重要些。

另外端到端模式只要支持对端数据源为消息中间件,可立即实现订阅模式,数据加工能力在某些数据迁移同步产品上可通过上传业务代码运行的方式解决。

数据架构在满足业务需求的同时,简洁和清晰能够让系统更加易于维护和排查,当遇到链路每天同步大量数据、偶尔丢几条需要排查,或同步链路卡住不同步等情况,端对端方式往往体现出相当大的优势。

MySQL 关联表在 ES 上的设计

关系型数据库中的表 join 关系在 ES 可以用几种数据类型来表达,包括 objected,nested,join 三种。

objected

object 类型可以存储嵌套结构。

优点:表示主 field 和 object 内部 field 之间的一对多关系,支持 doc 的 join 查询。由于所有查询时依赖的关联数据也都在一个文档内,避免了 ES 内部的 join,查询效率较高。

缺点:一对多关系只能保留一层,多于一层的会被打平,会丢失嵌套 field 内部的关联关系。

nested

nested 类型可以存储嵌套结构,表示一对多关系,是 object 类型的拓展。

优点

不会出现 object 的缺点,整个嵌套关系是完整维护的,子文档内部关联关系保存是完整的

关联数据通过实现上自然关联到主文档上,搜索时性能较好(相对于 join)

缺点

一个 nested field 只能属于一个主文档

在 nested 类型中,子文档和主文档之间强绑定,主文档更新的时候会强制更新子文档。在写多读少的场景,新能开销较大。

child 文档的查询必须通过父文档再找到子文档

子文档频繁修改的话会影响别的子文档和父文档,因为本质上在 lucene 实现上是父文档下的冗余存档

join

join 类型可以配置父子文档,通过父子文档来实现一对多的能力,一个索引只能建一个。相比 nested 类型,该类型更加灵活。父子文档之间通过 parentId 来关联,实际实现上他们就是独立的文档。

优点

子文档更新不影响父文档和其他子文档

一个子文档可以单独搜索

一个文档在作为子文档时可以自己选择属于哪个父文档。通过 relation 可以指定不同的 join 列

缺点

需要建个全局序数,用于服务于父子文档的关联关系,这个会影响搜索性能

join 和 nested 类型比较

join 适合写多读少场景,更加适合关注索引性能的场景。这意味着更新的生效会更快,但是搜索时的开销也相对大些

nested 适合读多写少的场景,更加关注搜索的性能

去规范化实现

下面将介绍几种数据同步去规范化的几种方式:

主表冗余数据

业务侧将一些查询时需要的关系数据提前冗余在源表的一个字段中。

image.png 优点:处理模式能应对各种一对多的关联关系,对数据同步工具的功能要求低,配置简单,只需要支持单同步到 ES 即可。

缺点

索引、搜索性能非最佳:提供给 ES 的不是构建好的宽表数据。这种实现方式会有索引、搜索性能方面的额外开销,不是性能最佳的实现方式。

业务系统入侵:业务系统写主数据的时候需要额外写入信息。

主数据库表冗余过多数据:关系型数据库表冗余了过多其他表的信息,可能存在存储和性能开销。

总结: 不太推荐该方式

多表订阅并预构建宽表数据

数据同步工具同时订阅搜索时依赖的所有表,先到的数据先进到 ES,没有数据过来的字段为空。

image.png

优点

数据同步工具配置同步任务较为简单,无业务入侵,不耦合业务系统逻辑。

对数据同步工具要求低,除了同步以外,不需要其他额外的功能特性。

基于预构建宽表的方式在 ES 上也有较好的索引和查询性能。

同步链路不会因为宽表某些列缺失数据阻塞整个数据链路的同步。

缺点:基于事实表主动触发式的方式来进行宽表的构建。源端订阅的表,如果更新很少或者从来不更新产生 binlog,则对端的文档中的列值可能一直不完整,导致时效性会比较差。搜索的时候有一些列的数据会缺少。

总结:

适合构成宽表的事实表数据写入有事务保证一起落盘的场景,这样可以避免对端 ES 搜素到不完整的数据。

适合构建宽表不需要业务加工处理的场景,构建宽表只是单数的将多张表的列拼接在一起,形成宽表。

同步过程回查预构建

数据同步工具订阅的表称为主表。数据同步过程中,反查数据库查询的表称为从表。利用数据同步工具自身的能力,在订阅主表期间,自动通过回查的方式,填补宽表中的列,形成完整的宽表行数据。

image.png

优点

基于反查的方式构建宽表灵活性好,可以在生成宽表前基于主表的数据对从表数据做一些轻度的数据加工。

一条主表的数据,通过反查生成宽表行,可以配合数据加工生成多条宽表行数据。

基于反查的方式可以比较轻松的实现跨实例的 join,从而生成宽表行。

基于宽表预构建的方式在 ES 有较好的索引、查询性能。

缺点

反查时数据可能没有准备好,导致数据确实

需要数据同步工具在数据反差、数据加工方面进行支持

总结

适合构建宽表涉及数据加工的场景

引用

MySQL 数据实时同步到 Elasticsearch 的技术方案选型和思考

物化视图和普通视图的区别