从MongoDB迁移到ES后,我们减少了80%的服务器

2020 年 4 月 19 日

从MongoDB迁移到ES后,我们减少了80%的服务器

本文由 dbaplus 社群授权转载。

序言

图示:MongoDB 与 Elasticsearch 热度排名

本文内容涉及到 MongoDB 与 Elasticsearch 两大阵营,可能会引起口水之争,仅代表个人经验之谈,非阵营之说,围绕两个话题展开:

  • 为什么要从 MongoDB 迁移到 Elasticsearch?
  • 如何从 MongoDB 迁移到 Elasticsearch?

现状背景

MongoDB 本身定位与关系型数据库竞争,但工作中几乎没有见到哪个项目会将核心业务系统的数据放在上面,依然选择传统的关系型数据库。

1、项目背景项目背景

公司所在物流速运行业,业务系统复杂且庞大,用户操作者很多,每日有大量业务数据产生,同时业务数据会有很多次流转状态变化,为了便于记录追踪分析,系统操作日志记录项目应运而生,考虑到原有的日均数据量,操作日志数据基于 MongoDB 存储。

操作日志记录系统需要记录两种数据,如下说明:

1)变更主数据,什么人在什么时间在系统哪个模块做了什么操作,数据编号是什么,操作跟踪编号是什么。

复制代码
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operateTime": "2019-11-11 12:12:12",
"operationId": 100,
"operationName": " 张三 ",
"departmentId": 1000,
"departmentName": " 客户部 ",
"operationContent": " 拜访客户。。。"
}

2)变更从数据,实际变更数据的变化前后,此类数据条数很多,一行数据多个字段变更就记录多条。

复制代码
[
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operateTime": "2019-11-11 12:12:12",
"operationId": 100,
"operationName": " 张三 ",
"departmentId": 1000,
"departmentName": " 客户部 ",
"operationContent": " 拜访客户 ",
"beforeValue": "20",
"afterValue": "30",
"columnName": "customerType"
},
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operateTime": "2019-11-11 12:12:12",
"operationId": 100,
"operationName": " 张三 ",
"departmentId": 1000,
"departmentName": " 客户部 ",
"operationContent": " 拜访客户 ",
"beforeValue": "2019-11-02",
"afterValue": "2019-11-10",
"columnName": "lastVisitDate"
}
]

2、项目架构项目背景

项目架构描述如下:

  • 业务系统新增或者编辑数据,产生操作日志记录发送到 Kafka 集群,基于 dataid 字段作为 key;
  • 新增或编辑数据实际存储到 MySQL 数据库;
  • canal 集群订阅 MySQL 集群,按照业务系统模块配置监控的数据库与表;
  • canal 将监控到的变更业务数据发送到 Kafka 集群,基于 dataid 字段作为 key;
  • 操作日志系统从 Kafka 获取主记录数据与从记录数据;
  • 操作日志系统写入数据到 MongoDB,同时需要反查询。

图示:操作日志记录业务流程说明

3、MongoDB 架构项目背景

集群架构说明:

  • 服务器配置 8c/32gb/500gb ssd;
  • Router 路由服务器部署了 3 个节点;
  • Config 配置服务器部署了 3 个节点;
  • Shard 分片服务器部署了 9 个节点;
  • 主操作记录设计 3 个分片;
  • 从操作记录设计 3 个分片。

问题说明

MongoDB 的信徒们可能怀疑我们没有使用好,或者我们的运维能力欠缺,或者认为我们有 Elasticsearch 的高手在。不是这样的,弃用 MongoDB 选择 Elasticsearch 其实并非技术偏见问题,而是我们的实际场景需求,原因如下:

1、搜索查询项目背景

  • MongoDB 内部采用 B-Tree 作为索引结构,此索引基于最左优先原则,且必须保证查询顺序与索引字段的顺序一致才有效,这个即是优点,但在现在复杂业务场景也是致命的;
  • 业务系统查询操作日志记录会有很多过滤条件,且查询条件是任意组合的,现有 MongoDB 是不支持的,或者说所有关系型数据库都不支持,如果要支持,得创建好多组合的 B+ 数索引,想法很不理智,这个我们已经在《DB 与 ES 混合之应用系统场景分析探讨》文中探讨过,详细可以阅读;
  • 同时主记录与从记录中有很多字符类的数据,这些数据查询即要支持精确查询,也要支持全文检索,这几个方面 MongoDB 功能很单一,性能也很糟糕,业务系统查询时经常超时,反倒是 Elasticsearch 非常合适。

2、技术栈成熟度项目背景

  • 分片与副本实现问题,MongoDB 集合数据在设计时是需要绑定到具体的机器实例的,哪些分片分布在哪些节点上,哪些副本分布在哪些节点上,这些都需要在配置集群时就要绑定死,跟传统的关系型数据库做分库分表本质上没有什么两样,其实现在很多数据产品的集群还是这种模式偏多,比如 Redis-cluster,ClickHouse 等。而 Elasticsearc 的集群与分片和副本没有直接的绑定关系,可以任意的平衡调整,且节点的性能配置也可以很容易差异化;
  • 操作日志数据量增加很快,单日写入超过千万条,不用多久,运维人员就需要对服务器进行扩容,且相对 Elasticsearch 复杂很多;
  • MongoDB 单集合数据量超过 10 亿条,此情况下即使简单条件查询性能也不理想,不如 Elasticsearch 倒排索引快;
  • 公司对于 ES 与 MongoDB 技术栈的经验积累不同,Elasticsearc 在很多项目中运用,非常核心的项目也是大量运用,对于其技术与运维经验更丰富,而 MongoDB 如果除去核心业务场景,几乎找不到合适的切入口,实际没有人敢在核心项目中使用 MongoDB,这就很尴尬。

3、文档格式相同项目背景

MongoDB 与 Elasticsearch 都属于文档型数据库 ,Bson 类同与 Json,_objectid 与 _id 原理一样,所以主数据与从数据迁移到 Elasticsearch 平台,数据模型几乎无需变化。

迁移方案

异构数据系统迁移,主要围绕这两大块内容展开:

  • 上层应用系统迁移,原来是针对 MongoDB 的语法规则,现在要修改为面向 Elasticsearch 语法规则;
  • 下层 MongoDB 数据迁移到 Elasticsearch。

1、Elastic 容量评估项目背景

原有 MongoDB 集群采用了 15 台服务器,其中 9 台是数据服务器,迁移到 Elastic 集群需要多少台服务器?我们采取简单推算办法,如假设生产环境上某个 MongoDB 集合的数据有 10 亿条数据, 我们先在测试环境上从 MongoDB 到 ES 上同步 100 万条数据,假设这 100 万条数据占用磁盘 10G,那生产上环境上需要 1 个 T 磁盘空间,然后根据业务预期增加量扩展一定冗余。根据初步评估,Elastic 集群设置 3 台服务器, 配置 8c/16g 内存 /2T 机械磁盘。服务器数量一下从 15 台缩减到 3 台,且配置也降低不少。

2、Elastic 索引规则项目背景

系统操作日志是时序性数据,写完整后基本上无需再次修改。操作日志记录查询主要是当月的居多,后续的历史性数据查询频率很低,根据评估,核心数据索引按月创建生成, 业务查询时候必须带上操作时间范围,后端根据时间反推需要查询哪些索引,Elastic-Api 支持多索引匹配查询,完美利用 Elastic 的特性解决跨多个月份的查询合并。对于非核心数据索引,按年创建索引生成足以。

图示:Elastic 操作日志索引创建规则

3、核心实现逻辑设计项目背景

Elasticsearch 不是关系型数据库,不具备事务的机制。操作日志系统的数据来源都是 Kafka,消费数据是有顺序机制的,有 2 种场景特别注意,如下:

  • 主数据先到操作日志系统,从数据后到,从数据写的时候先拼凑主数据记录和 Binlog 字段数据;
  • 从数据先到操作日志系统,主数据后到,主数据更新从索引的相关的索引字段。

Elasticsearch 索引数据更新是近实时的刷新机制,数据提交后不能马上通过 Search-Api 查询到,主记录的数据如何更新到从记录呢?而且业务部门不规范的使用,多条主记录的 dataId 和 tracId 可能一样。

由于主数据与从数据关联字段是 dataId 和 traceId。如果主数据与从数据在同时达到操作日志系统,基于 update_by_query 命令肯定失效不 准确, 主从数据也可能是多对多的关联关系,dataId 和 traceId 不能唯一决定一条记录。

Elasticsearch 其实也是一个 NoSQL 数据库, 可以做 key-value 缓存。这时新建一个 Elastic 索引作为中间缓存, 原则是主数据与从数据谁先到缓存谁,索引的 _id=(dataId+traceId) , 通过这个中间索引可以找到主数据记录的 Id 或者从记录 Id, 索引数据模型多如下,detailId 为从索引的 _id 的数组记录。

复制代码
{
"dataId": 1,
"traceId": "abc",
"moduleCode": "crm_01",
"operationId": 100,
"operationName": " 张三 ",
"departmentId": 1000,
"departmentName": " 客户部 ",
"operationContent": " 拜访客户 ",
"detailId": [
1,
2,
3,
4,
5,
6
]
}

前面我们讲过主记录和从记录都是一个 Kafka 的分区上,我们拉一批数据的时候,操作 ES 用的用到的核心 API:

复制代码
#批量获取从索引的记录
_mget
#批量插入
bulk
#批量删除中间临时索引
_delete_by_query

迁移过程

1、数据迁移项目背景

选择 DataX 作为数据同步工具由以下几个因素:

  • 历史型数据。操作日志记录数据属于历史性的数据,记录产生之后几乎无需二次修改,等同于离线数据;
  • 非持续性迁移。项目全部完工之后,原有的 MongoDB 集群会全部销毁,不会有二次迁移需求;
  • 数据量问题。原有 MongoDB 操作日志数据量有几十亿条,迁移过程不能太快也不能太慢,速度太快,MongoDB 集群会出现性能问题,速度太慢,项目周期太长,增加运维的成本与复杂度。否则可以选择 Hadoop 作为中转平台的迁移;
  • DataX 源码特定场景改造。如日期类型的转换、索引主键 _id 的生成、索引主键 _id 映射,支持重复同步;
  • 多实例多线程并行。主数据同步部署多个实例,从数据同步也部署多个实例,单实例中配置多个 Channel。

图示:DataX 同步数据示意图

2、迁移索引设置项目背景

临时修改索引的一些设置,当数据同步完之后再修改回来,如下:

复制代码
"index.number_of_replicas": 0,
"index.refresh_interval": "30s",
"index.translog.flush_threshold_size": "1024M"
"index.translog.durability": "async",
"index.translog.sync_interval": "5s"

3、应用迁移项目背景

操作日志项目采用 Springboot 构建,增加了自定义配置项,如下:

复制代码
#应用写入 mongodb 标识
writeflag.mongodb: true
#应用写入 elasticsearch 标识
writeflag.elasticsearch: true

项目改造说明:

  • 第一次上线的时候,先将 2 个写入标识设置为 true,双写 MongoDB 和 ES;
  • 对于读,提供 2 个不同接口,前端自由的切换;
  • 等数据迁移完,没有差异的时候,重新更改 flag 的值。

图示:应用平衡迁移

结语

1、迁移效果项目背景

弃用 MongoDB 使用 ElasticSearch 作为存储数据库,服务器从原来的 15 台 MongoDB,变成了 3 台 ElasticSearch,每月为公司节约了一大笔费用。同时查询性能提高了 10 倍以上,而且更好的支持了各种查询,得到了业务部门的使用者,运维团队和领导的一致赞赏。

2、经验总结项目背景

整个项目前后历经几个月,多位同事参与,设计、研发,数据迁移、测试、数据验证、压测等各个环节。技术方案不是一步到位,中间也踩了很多坑,最终上线了。ES 的技术优秀特点很多,灵活的使用,才能发挥最大的威力。

作者介绍

李猛 (ynuosoft),Elastic-stack 产品深度用户,ES 认证工程师,2012 年接触 Elasticsearch,对 Elastic-Stack 开发、架构、运维等方面有深入体验,实践过多种 Elasticsearch 项目,最暴力的大数据分析应用,最复杂的业务系统应用;业余为企业提供 Elastic-stack 咨询培训以及调优实施。

原文链接

https://mp.weixin.qq.com/s?__biz=MzI4NTA1MDEwNg==&mid=2650787182&idx=1&sn=d3543f9a62ec56c58fe72a0d63e35999&chksm=f3f978fbc48ef1ed23736de22fd812ca195acdb16c3869ddab8b2c29aa3ca50f0f35042f5d71&scene=27#wechat_redirect

2020 年 4 月 19 日 14:06 6436

评论 2 条评论

发布
用户头像
换es能省的应该就mongos和config server的部署..
20 小时前
回复
用户头像
你这个es的机器是不是没算备份的机器?? 每台2个备份也就9台机器了.. 你说个..
20 小时前
回复
没有更多评论了
发现更多内容

架构师训练营 - 第四周命题作业

牛牛

极客大学架构师训练营 作业

《机器学习理论导引》阅读攻略

华章IT

机器学习 周志华

“信息茧房”里的人

架构精进之路

自我思考 程序员成长

架构师训练营第 4 周 总结

时来运转

Linux系统查询端口命令

打鱼小王子

以应用为中心:开放应用模型(OAM)初探

郭旭东

Kubernetes OAM

架构师训练营第四章作业

饶军

为什么美国程序员工作比中国程序员工作轻松、加班少?

程序员生活志

程序员 加班

HTTP 的15个常见知识点复习

pingan8787

JavaScript 前端 Web HTTP

架构5班3-4组优秀作业

tracy

项目域名配置流程

打鱼小王子

使用 Prometheus-Operator 监控 Calico

米开朗基杨

Prometheus calico

第四周总结

石印掌纹

第四周作业

南宫煌

极客大学架构师训练营

万字长文,让 Java 程序员入门小众语言 Ruby

Phoenix

Java ruby 个人成长 编程语言

拿着锤子的人,哪里都是钉子

Neco.W

思维方式 思考力

设计模式

Jeff

深入浅出Shiro系列

程序员的时光

架构师训练营第四章作业

叮叮董董

架构 技术方案 解决手段 互联网架构

架构师训练营第四章总结

叮叮董董

总结 架构师 训练营

漫画通信:惊呆了,手机登录还可以这么玩!

巨侠说

云通信 通信 通信云

计算机操作系统基础(六)---作业管理之进程调度

书旅

Java php 多线程 操作系统 进程

围绕 Office 365 的那些 CLI

手艺人杨柳

Office 365

程序员不得不知的十大职场误区

陆陆通通

程序员 职场 架构师 工资 误区

week04 学习总结 互联网面临挑战和架构模式

Z冰红茶

大型互联网应用技术方案

石印掌纹

架构师训练营第4周作业

时来运转

重学 Java 设计模式:实战备忘录模式「模拟互联网系统上线过程中,配置文件回滚场景」

小傅哥

Java 设计模式 小傅哥 重构 备忘录模式

一个典型的大型互联网应用系统使用了哪些技术方案和手段,主要解决什么问题?请列举描述。

Carlos

互联网产品架构成长

superman

极客大学架构师训练营 互联网架构

Prometheus 存储层的演进

伴鱼技术团队

性能优化 系统架构 Prometheus 存储 时序数据库

从MongoDB迁移到ES后,我们减少了80%的服务器-InfoQ