Elasticsearch 查询和数据同步 - 记一次技术实践

前言

前段时间与同事一起为产品接入了 Elasticsearch 框架技术。从参与方案会议到搭建开发上线过程中有很多讨论点,故产生本文,希望藉此总结和分享一些经验。

1. 业务模型

接触已有的业务时,数据模型是最早需要知道的信息。我和同事负责接入 Elasticsearch 的产品是一个业务繁多的通讯录,简化下来就是 3 个关键的模型,如下:

  • 部门(Department)
  • 人员(User)
  • 标签(Tag)

它们的用途和联系,就跟它们的词义一样。
由此产生的业务如下:

  • 通过 标签 查询 部门人员
  • 通过 部门 查询 人员
3个模型的简化联系.png

基于以上模型和业务,在典型的关系型数据库下,为了实现关联关系,自然会有额外的关联表

  • 部门人员关联表:每条记录包含1个部门,1个人员
  • 标签对象关联表:每条记录包含1个标签,1个部门或人员

2. 需求

Elasticsearch 的特点有全文检索、分布式、海量数据下近实时查询
当时为通讯录业务引入 Elasticsearch 的需求和目标如下:

  • 多字段的匹配或模糊查询。这些部门、人员、标签数据原本存储在 MySQL 中,如果要做匹配多个字段的模糊查询就比较吃力了,考虑一个常用功能 “输入姓名/手机号/拼音/首字母来查询人员”。而快速查询此类业务是 Elasticsearch 可以提供的。
  • 基础模块能力。其他业务模块也提出了类似全文检索的需求,因此在通讯录业务首次应用 es 时,要定义和提供好 es 的访问和工具方法,供其他模块在未来接入时,能复用一些实现,能保持一致的接口和命名风格等。

3. 索引设计

从原 MySQL 数据库表,到 Elasticsearch 的索引,数据模型的变化称为异构
Elasticsearch 适合解决在 MySQL 中多条件或连表这样比较慢的查询业务,因此除了原有的信息字段,我们会再附加 3 个模型的关联关系到 es 索引中。

索引 \ 字段 原有 关联关系
部门 部门名
完整部门路径名
(无)
人员 姓名
拼音
首字母
手机号
父部门Id
所有父级部门Id
标签Id
标签 标签名 部门Id
人员Id

(上表略去了一些无关本篇内容的字段,如 SaaS 平台的租户Id、每个对象的信息详情字段)

  • 是否需要添加关联关系的字段,是由业务需求决定的。拿人员索引的 “所有父级部门Id” 举例子,因为有查询部门下所有人员(包括直属、子部门下的)的业务需求,所以会设计这么一个字段。

  • 可以使用 Elasticsearch 的分词功能来记录关联关系的字段中。为该字段定义一个分隔模式为竖线 “|” 的分词器,把若干个关联Id存成一个拼接的字符串。

4. 版本选择

同事是个版本控,在选择版本时了解和考虑了非常多的信息。不过版本选择确实是为平台接入新技术时的一个重要考虑点。我们提出这个方案的当时(2018年4月),对比了主要使用的云服务提供商的几个版本,考虑项可以按优先级概括为:

  1. 稳定的
  2. 案例资料多的
  3. 时新程度,包括 Elasticsearch版本 和 Lucene版本
  4. 我们已经使用了某家云服务提供商,会偏向再用其提供的服务

几个版本对比

我们当时选择了 Elasticsearch 6.2.2 版本。

v5.6.4

  • 是 Spring 整合的各个框架中,支持数最多的版本
  • 市面使用人数较多,资料较多
  • 其依赖的 Lucene 大版本是v6,较旧

v6.2.2

  • 是当时稳定的版本中最新的,性能比 v5 好

v6.2.4

  • 是当时最新的版本,修复了许多 bug
  • 性能更好,是官方推荐的版本
  • 官方的技术文档部分还没更新,得看旧文档
  • 市面上找不到相应的人的使用资料

版本发展(于2019年4月

在写本篇文章时,我再去了解了和 Elasticsearch版本 相关的变更:

  • Elasticsearch稳定版本中最新的是 v7.0、v6.7
  • 依赖的Lucene版本分别为 v8.0、v7.2
  • Spring 的稳定支持程度为:v3.2.x 的 spring data elasticsearch 支持 v6.5.0 的 elasticsearch 版本,比最新版本低一些。

5. 导入已有数据

考虑到要使用 Elasticsearch 时,通常意味着已经有很多数据了。首次使用自然会有导入已有数据的过程,而且这些数据量都是很大的。
我们的方案是 JDBC 查询并提交给 es。设计要点有:

  • 分批。数据量之大已经无法一次存到内存中。数据按明确的边界划分而独立,会让多线程处理、日志记录、重试都变得轻松。按租户来划分就是一种好的方式。
  • 缓慢。避免影响线上的服务,同时适当给 JVM 回收和 Elasticsearch 处理留一点时间。
  • 异常。信息汇总和失败重试。

具体设计细节如下:

  1. 为 SaaS 系统的每个租户创建一个任务,提交到ExecutorCompletionService
  2. 在该租户的任务中:
    一次查询所有部门;
    分页查询所有人员、部门人员关联;
    一次查询所有标签,标签对象关联;
  3. 关联关系做成便于查询的数据结构,以用于添加 es 文档时的快速查询。
    例如,映射<人员,部门>可用于查询:人员所属的部门;
    例如,映射<部门,标签>可用于查询:部门所贴的标签;
    用到了 Guava 的 Multimap,以达到类似于 Map<String, Set<String>> 的效果。
  4. 建立新增 es 文档的批量请求BulkRequest。对于每个对象,都可以用上一步做好的结构快速获取其关联关系。
  5. 提交批量新增请求给 es。

6. 数据源同步

我们的 MySQL 数据同步到 Elasticsearch 的方案,是在应用层基于事件通知进行的。以人员对象为例,步骤如下:

  1. 人员的增删查改事件,都会通知给其他订阅者。这是已有的逻辑;
  2. 设计一个“记录人员变动”订阅者,被通知时,将变动储存起来;
  3. 设计一个“Es同步”定时任务,每天凌晨,取出变动记录,提交到 Es,之后删除变动记录;

看到这个方案,你可能会问为什么不使用像 Logstash 等成熟的框架或插件,而是自写一套同步方法?原因如下:

  • 我们选择的 MySQL 云服务提供商在当时没有提供 binlog 日志访问。这使我们无法选择一些基于日志的同步方案。
  • 部门、人员、标签的数据表原本没有像 update_time 这样的——能反映变更的列。故又可以排除基于时间去增量同步的方案。
  • 人员、标签表的数据量很大,如果要增加一列 update_time 并加上索引,带来的成本有:额外的储存空间(我们购买的云服务空间每增长百G每年的成本大约是1000元);新字段给应用层带来的维护成本
  • 设计出来的 Es 索引和 MySQL 表的字段不同。一些在 Es 索引中新增的字段,是需要在 MySQL 中做额外查询才能得到的。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,029评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,395评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,570评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,535评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,650评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,850评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,006评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,747评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,207评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,536评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,683评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,342评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,964评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,772评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,004评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,401评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,566评论 2 349