前言

我们使用Elasticsearch索引文档时,最理想的情况是文档JSON结构是确定的,数据源源不断地灌进来即可,但实际情况中,没人能够阻拦需求的变更,在项目的某个版本,可能会对原有的文档结构造成冲击,增加新的字段还好,如果要修改原有的字段,只能重建索引了。

概要

本篇以实战方式讲解如何零停机完成索引重建的三种方案。

外部数据导入方案

整体介绍

系统架构设计中,有关系型数据库用来存储数据,Elasticsearch在系统架构里起到查询加速的作用,如果遇到索引重建的操作,待系统模块发布新版本后(若重建索引不是因为客户端修改导致的,可以不停机发版,直接操作),可以从数据库将数据查询出来,重新灌到Elasticsearch即可。

执行步骤

建议的功能方案:数据库 + MQ + 应用模块 + Elasticsearch,可以在MQ控制台发送MQ消息来触发重导数据,按批次对数据进行导入,整个过程异步化处理,请求操作示意如下所示:

详细操作步骤:

  1. 通过MQ的web控制台或cli命令行,发送指定的MQ消息
  2. MQ消息被微服务模块的消费者消费,触发ES数据重新导入功能
  3. 微服务模块从数据库里查询数据的总数及批次信息,并将每个数据批次的分页信息重新发送给MQ消息,分页信息包含查询条件和偏移量,此MQ消息还是会被微服务的MQ消息者接收处理。
  4. 微服务根据接收的查询条件和分页信息,从数据库获取到数据后,根据索引结构的定义,将数据组装成ES支持的JSON格式,并执行bulk命令,将数据发送给Elasticsearch集群。

这样就可以完成索引的重建工作。

方案特点

MQ中间件的选型不做具体要求,常见的rabitmq、activemq、rocketmq等均可。

在微服务模块方面,提供MQ消息处理接口、数据处理模块需要事先开发的,一般是创建新的索引时,配套把重建的功能也一起做好。整体功能共用一个topic,针对每个索引,有单独的结构定义和MQ消息处理tag,代码尽可能复用。处理的批次大小需要根据实际的情况设置。

微服务模块实例会部署多个,数据是分批处理的,批次信息会一次性全部先发送给MQ,各个实例处理的数据相互不重叠,利用MQ消息的异步处理机制,可以充分利用并发的优势,加快数据重建的速度。

方案缺点

  1. 对数据库造成读取压力,短时间内大量的读操作,会占用数据库的硬件资源,严重时可能引起数据库性能下降。
  2. 网络带宽占用多,数据毕竟是从一个库传到另一个库,虽说是内网,但大量的数据传输带宽占用也需要注意。
  3. 数据重建时间稍长,跟迁移的数据量大小有关。

基于scroll+bulk+索引别名方案

整体介绍

利用Elasticsearch自带的一些工具完成索引的重建工具,当然在方案实际落地时,可能也会依赖客户端的一些功能,比如用Java客户端持续的做scroll查询、bulk命令的封装等,但与上一方案相比,最明显的区别就是:数据完全自给自足,不依赖其他数据源。

执行步骤

假设原索引名称是music,新的索引名称为musicnew,Java客户端使用别名musicalias连接Elasticsearch,该别名指向原索引music。

  1. 若Java客户端没有使用别名,需要给客户端分配一个:PUT /music/_alias/music_alias
  2. 新建索引music_new,将mapping信息,settings信息等按新的要求全部定义好。
  3. 使用scroll api将数据批量查询出来
GET /music/_search?scroll=1m
{"query": {"match_all": {}},"sort": ["_doc"],"size":  1000
}

  1. 采用bulk api将scoll查出来的一批数据,批量写入新索引
POST /_bulk
{ "index":  { "_index": "music_new", "_type": "children", "_id": "1" }}
{ "name":    "wake me, shake me" }

  1. 反复执行步骤3和步骤4,查询一批导入一批,可以借助Java Client或其他语言的API支持。
  2. 切换别名musicalias到新的索引musicnew上面,此时Java客户端仍然使用别名访问,也不需要修改任何代码,不需要停机。
POST /_aliases
{"actions": [{ "remove": { "index": "music", "alias": "music_alias" }},{ "add":    { "index": "music_new", "alias": "music_alias" }}]
}

  1. 验证别名查询的是否为新索引的数据

方案特点

在数据传输上基本自给自足,不依赖于其他数据源,Java客户端不需要停机等待数据迁移,网络传输占用带宽较小。

只是scroll查询和bulk提交这部分,数据量大时需要依赖一些客户端工具。

补充一点

在Java客户端或其他客户端访问Elasticsearch集群时,使用别名是一个好习惯。

Reindex API方案

Elasticsearch v6.3.1已经支持Reindex API,它对scroll、bulk做了一层封装,能够 对文档重建索引而不需要任何插件或外部工具。

最基础的命令:

POST _reindex
{"source": {"index": "music"},"dest": {"index": "music_new"}
}

响应结果:

{"took": 180,"timed_out": false,"total": 4,"updated": 0,"created": 4,"deleted": 0,"batches": 1,"version_conflicts": 0,"noops": 0,"retries": {"bulk": 0,"search": 0},"throttled_millis": 0,"requests_per_second": -1,"throttled_until_millis": 0,"failures": []
}

注意:如果不手动创建新索引music_new的mapping信息,那么Elasticsearch将启动自动映射模板对数据进行类型映射,可能不是期望的类型,这点要注意一下。

version_type 属性

使用reindex api也是创建快照后再执行迁移的,这样目标索引的数据可能会与原索引有差异,version_type属性可以决定乐观锁并发处理的规则。

reindex api可以设置version_type属性,如下:

POST _reindex
{"source": {"index": "music"},"dest": {"index": "music_new""version_type": "internal"}
}

version_type属性含义如下:

  • internal:直接拷贝文档到目标索引,对相同的type、文档ID直接进行覆盖,默认值
  • external:迁移文档到目标索引时,保留version信息,对目标索引中不存在的文档进行创建,已存在的文档按version进行更新,遵循乐观锁机制。

op_type 属性和conflicts 属性

如果op_type设置为create,那么迁移时只在目标索引中创建ID不存在的文档,已存在的文档,会提示错误,如下请求:

POST _reindex
{"source": {"index": "music"},"dest": {"index": "music_new","op_type": "create"}
}

有错误提示的响应,节选部分:

{"took": 11,"timed_out": false,"total": 5,"updated": 0,"created": 1,"deleted": 0,"batches": 1,"version_conflicts": 4,"noops": 0,"retries": {"bulk": 0,"search": 0},"throttled_millis": 0,"requests_per_second": -1,"throttled_until_millis": 0,"failures": [{"index": "music_new","type": "children","id": "2","cause": {"type": "version_conflict_engine_exception","reason": "[children][2]: version conflict, document already exists (current version [17])","index_uuid": "dODetUbATTaRL-p8DAEzdA","shard": "2","index": "music_new"},"status": 409}]
}

如果加上"conflicts": "proceed"配置项,那么冲突信息将不展示,只展示冲突的文档数量,请求和响应结果将变成这样:

请求:

POST _reindex
{"conflicts": "proceed","source": {"index": "twitter"},"dest": {"index": "new_twitter","op_type": "create"}
}

响应:

{"took": 12,"timed_out": false,"total": 5,"updated": 0,"created": 1,"deleted": 0,"batches": 1,"version_conflicts": 4,"noops": 0,"retries": {"bulk": 0,"search": 0},"throttled_millis": 0,"requests_per_second": -1,"throttled_until_millis": 0,"failures": []
}

query支持

reindex api支持数据过滤、数据排序、size设置、_source选择等,也支持脚本执行,这里提供一个简单示例:

POST _reindex
{"size": 100, "source": {"index": "music","query": {"term": {"language": "english"}},"sort": {"likes": "desc"}},"dest": {"index": "music_new"}
}

小结

本篇介绍了零停机索引重建操作的三个方案,从自研功能、scroll+bulk到reindex,我们作为Elasticsearch的使用者,三个方案的参与度是逐渐弱化的,但稳定性却是逐渐上升的,我们需要清楚地去了解各个方案的优劣,适宜的场景,然后根据实际的情况去权衡,哪个方案更适合我们的业务模型,仅供参考,谢谢。

专注Java高并发、分布式架构,更多技术干货分享与心得,请关注公众号:Java架构社区

imp 只导入索引_Elasticsearch系列---实战零停机重建索引相关推荐

  1. imp 只导入索引_使用imp导入表和索引至不同表空间方法

    在以前我的blog中,曾经记录过使用expdp/impdp方式将表和索引导入至不同表空间的方法,这里再提一下: 导出: expdp test/test directory=dump_dir dumpf ...

  2. elasticsearch 索引_Elasticsearch系列---索引管理

    概要 Elasticsearch让索引创建变得非常简单,只要索引一条新的数据,索引会自动创建出来,但随着数据量的增加,我们开始有了索引优化和搜索优化的需求之后,就会发现自动创建的索引在某些方面不能非常 ...

  3. mysql索引_mysql系列:深入理解mysql 索引特性(屡试不爽的mysql索引总结)

    原标题:mysql系列:深入理解mysql 索引特性(屡试不爽的mysql索引总结) mysql为什么使用B+ Tree索引,不使用B- Tree索引? 索引顺序如何生效? 什么是覆盖索引? orde ...

  4. Oracle索引梳理系列(四)- Oracle索引种类之位图索引

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

  5. Oracle索引梳理系列(二)- Oracle索引种类及B树索引

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

  6. Oracle索引梳理系列(五)- Oracle索引种类之表簇索引(cluster index)

    版权声明:本文发布于http://www.cnblogs.com/yumiko/,版权由Yumiko_sunny所有,欢迎转载.转载时,请在文章明显位置注明原文链接.若在未经作者同意的情况下,将本文内 ...

  7. Oracle索引梳理系列(六)- Oracle索引种类之函数索引

    函数索引 1.1 概述 在实际应用中,当条件列使用函数运算进行数据匹配时,即使该列建立了索引,索引也不会被使用. 如下示例,其中在owner列上建立一个普通b-tree索引,观 察两种查询方式(不使用 ...

  8. ★Oracle imp/impdp 导入dmp文件到数据库

    使用EXPDP和IMPDP时应该注意的事项: EXP和IMP是客户端工具程序,它们既可以在客户端使用,也可以在服务端使用.        EXPDP和IMPDP是服务端的工具程序,他们只能在ORACL ...

  9. Elasticsearch 2.3.0 重建索引

    2019独角兽企业重金招聘Python工程师标准>>> 重建索引是2.3.0新增加的接口.这个接口是实验性质的,在未来有可能会改变. 重建索引的最基本的功能是拷贝文件从一个索引到另一 ...

最新文章

  1. python的功能模块_Python的功能模块[1] - struct - struct 在网络编程中的使用
  2. oracle逻辑结构包含,在Oracle中,逻辑结构由哪几个部分组成?
  3. 服务器备份文件格式,证书服务器,备份,还原
  4. Towards Efficient Privacy-Preserving Inspection of TLS Encrypted Traffic
  5. 图片素材网站|找素材、提升审美力就靠它了!
  6. SDN期末作业——负载均衡
  7. Javascript——Math对象
  8. emq数据储存到mysql,规则引擎示例 - 保存数据到 MySQL - 《EMQ X Enterprise v4.0 中文文档》 - 书栈网 · BookStack...
  9. JqueryEasyUI $.Parser
  10. libyuv NV12裁剪
  11. Spring Boot 开发微信公众号后台
  12. 初中中考计算机考试,中考信息技术考试
  13. Delphi 读取注册表REG_MULTI_SZ类型,注意事项
  14. python平方上标怎么输出,plot绘图同样适用
  15. jQuery使用ajaxSubmit()提交表单示例(转)
  16. Web前端-Ajax(下)
  17. 顶会论文笔记:联邦学习——ATPFL: Automatic Trajectory Prediction Model Design under Federated Learning Framework
  18. 简单停车位管理系统(C语言版)
  19. 第一章Python概述
  20. 国内外数据安全治理框架介绍与分析

热门文章

  1. Java 蓝桥杯 算法 和为T
  2. Java 蓝桥杯 分解质因数
  3. scrapy导入配置文件setting.py,防止运行时找不到文件
  4. scrapy通过item类直接创建数据库中的数据表
  5. 解决python读取pickle报错ValueError: unsupported pickle protocol: 5
  6. pandas后台导出excel_pandas导出Excel表格,银行卡号、身份证号无法正常显示的问题,该怎么解决?...
  7. python两个基本的库管理工具_Python多版本共存管理工具之pyenv
  8. grafana官方使用文档_5. Centos7 下部署使用 nmon2influxdb
  9. oracle 9i standby,Oracle 9I dataguard(standby)
  10. java基础之-I/O流和File类解析