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

栏目: 后端 · 发布时间: 7年前

内容简介:前段时间与同事一起为产品接入了 Elasticsearch 框架技术。从参与方案会议到搭建开发上线过程中有很多讨论点,故产生本文,希望藉此总结和分享一些经验。接触已有的业务时,它们的用途和联系,就跟它们的词义一样。

前言

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

1. 业务模型

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

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

它们的用途和联系,就跟它们的词义一样。

由此产生的业务如下:

  • 通过 标签 查询 部门人员
  • 通过 部门 查询 人员

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

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

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

2. 需求

Elasticsearch 的特点有 全文检索、分布式、海量数据下近实时查询

当时为通讯录业务引入 Elasticsearch 的需求和目标如下:

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

3. 索引设计

从原 MySQL 数据库表,到 Elasticsearch 的索引,数据模型的变化称为 异构

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

索引 字段 原有 关联关系
部门 部门名<br/>完整部门路径名 (无)
人员 姓名<br/>拼音<br/>首字母<br/>手机号 父部门Id<br/>所有父级部门Id<br/>标签Id
标签 标签名 部门Id<br/>人员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
Lucene
spring data 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 中做额外查询才能得到的。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

An Introduction to the Analysis of Algorithms

An Introduction to the Analysis of Algorithms

Robert Sedgewick、Philippe Flajolet / Addison-Wesley Professional / 1995-12-10 / CAD 67.99

This book is a thorough overview of the primary techniques and models used in the mathematical analysis of algorithms. The first half of the book draws upon classical mathematical material from discre......一起来看看 《An Introduction to the Analysis of Algorithms》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具