ES下零停机修改mapping数据迁移解决方案
ES是一个基于RESTful web接口并且构建在Apache Lucene之上的开源分布式搜索引擎,同时ES还是一个分布式文档数据库,其中每个字段均可被索引,而且每个字段的数据均可被搜索,能够横向扩展至数以百计的服务器存储以及处理PB级的数据,可以在极短的时间内存储、搜索和分析大量的数据。通常作为具有复杂搜索场景情况下的核心存储
ES就是为高可用和可扩展而生的
一方面可以通过升级硬件来完成系统扩展,称为垂直或向上扩展(Vertical Scale/Scaling Up)
另一方面,增加更多的服务器来完成系统扩展,称为水平扩展或者向外扩展(Horizontal Scale/Scaling Out)
尽管ES能够利用更强劲的硬件,但是垂直扩展毕竟还是有它的极限。真正的可扩展性来自于水平扩展,通过向集群中添加更多的节点来分担负载,增加可靠性。ES天生就是分布式的,它知道如何管理多个节点来完成扩展和实现高可用性。意味应用不需要做任何的改动
基于以上原因,es应用越来越广,今天介绍下怎么做es数据迁移,迁移优化及利用索引别名不停机切换索引
什么时候需要es数据迁移?
1、当你的数据量过大,而你的索引最初创建的分片数量不足,导致数据入库较慢的情况,此时需要扩大分片的数量
2、当数据的mapping需要修改,但是大量的数据已经导入到索引中了,重新导入数据到新的索引太耗时;但是在ES中,一个字段的mapping在定义并且导入数据之后是不能再修改的
以上场景的时候,我们只能重建索引,重新导入数据,如果是从其他数据源写入es的,那你需要重新跑你的脚本,如果是直接写入es的,那你是不是可能需要导出文档,再导入
不需要,es从2.3版本开始,就引入了 {ref}/docs-reindex.html[Reindex API],它能够对文档进行重建索引,而不需要引入插件或第三方工具
ES提供了_reindex这个API。相对于我们重新导入数据肯定会快不少,实测速度大概是bulk导入数据的5-10倍,具体要看系统性能
数据迁移怎么做?
查看源索引详细信息
查看新建的新索引
新索引创建完成后,开始从旧索引通过reindex进行数据迁移
通过post _reindex,指定源索引,目标索引
如果你是通过kibana的tools执行的,开始执行后,如果数据量大,肯定会在kibana返回504超时,不用管,后台迁移还在执行,这个504是因为kibana的超时时间到了,返回的,不影响,通过_cat/indices/index?v查看索引数据统计就可以
有时候会涉及到数据合并,那么可以设置version_type "version_type": "internal"或者不设置,则Elasticsearch强制性的将文档转储到目标中,覆盖具有相同类型和ID的任何内容:
有朋友会说,es的快照比reindex要快很多,确实,下次我们聊es的快照功能,但是快照无法实现mapping的修改,以及分片的修改,它只能作为数据备份恢复,既然说到reindex慢,那有没有办法优化?
reindex底层是scroll实现,scroll是什么呢?
scroll 可以理解为关系型数据库里的 cursor,因此,scroll 并不适合用来做实时搜索,而更适用于后台批处理任务,比如群发。
scroll 可以分为初始化和遍历两步,初始化时将所有符合搜索条件的搜索结果缓存起来,可以想象成快照,在遍历时,从这个快照里取数据,也就是说,在初始化后对索引插入、删除、更新数据都不会影响遍历结果。
from + size 和 scroll 都需要执行多次 fetch 阶段,但是相比于 from + size 方式,scroll 只做一次 query 阶段,一次将所有满足条件的结果都取出来,缓存到内存中,然后每次请求都是先在内存的快照中找到需要的 docid,然后去 shards 中获取数据。也就是说,from + size 会 query 多次,分页越深 query 的条数越多;而 scroll 一次会将全量数据取出,分页的深度对其没有影响
scroll虽然比frm+size的方式提高了效率,但是还是要完全遍历,性能还是不高,这也是reindex默认情况下慢的最大原因
所以提出了Sliced scroll的方式,也就是并行的scroll,通过传递slice参数,达到分块独立获取数据的目的
reindex支持sliced scroll以并行重建索引,举例:
slices的分片方式分两种,一种是手动分片,一种是自动分片,上图的方式是自动分片,手动分片见官方文档
slices大小设置注意事项:
1)slices大小的设置可以手动指定,或者设置slices设置为auto,auto的含义是:针对单索引,slices大小=分片数;针对多索引,slices=分片的最小值。
2)当slices的数量等于索引中的分片数量时,查询性能最高效。slices大小大于分片数,非但不会提升效率,反而会增加开销。
3)如果这个slices数字很大(例如500),建议选择一个较低的数字,因为过大的slices 会影响性能。
除了scroll并行的方式提升reindex的性能外,还有一个很重要的参数可以优化,那就是reindex批量操作的大小
默认情况下reindex使用1000进行批量操作,可以在source中通过size参数进行调整
批量大小值不是随便填写,具体如何做?
批量大小取决于数据、分析和集群配置,但一个好的起点是每批处理5-15 MB。
注意,这是物理大小。文档数量不是度量批量大小的好指标。例如,如果每批索引1000个文档:
1)每个1kb的1000个文档是1mb。
2)每个100kb的1000个文档是100 MB。
这些是完全不同的体积大小。
2、逐步递增文档容量大小的方式调优。
1)从大约5-15 MB的大容量开始,慢慢增加,直到你看不到性能的提升。然后开始增加批量写入的并发性(多线程等等)。
2)使用kibana、cerebro或iostat、top和ps等工具监视节点,以查看资源何时开始出现瓶颈。如果您开始接收EsRejectedExecutionException,您的集群就不能再跟上了:至少有一个资源达到了容量。
除了以上两种方式,还有两种方式,分别是禁用ES副本和增加refresh间隔
我们知道,ES在数据写入的时候,会写入多个副本,在进行大批量数据导入的时候,这个会严重影响写入速度,所以我们可以先关闭ES副本,导入后,再开启副本操作
对于refresh间隔时间,由于我们是做导入操作,所以不需要急于索引刷新操作,可以将索引的refresh_interval禁用,完成后开启
综合以上调优,reindex的速度能提升10倍以上。
解决了迁移的问题,那么迁移完后,正常我们可以修改调用索引,改为使用新索引,进行一个切换。有些时候,我们不想进行停机切换索引,怎么操作呢?
索引别名 _alias
在前面提到的,重建索引的问题是必须更新应用中的索引名称。索引别名就是用来解决这个问题的!
索引 别名 就像一个快捷方式或软连接,可以指向一个或多个索引,也可以给任何一个需要索引名的API来使用。别名 带给我们极大的灵活性,允许我们做下面这些:
在运行的集群中可以无缝的从一个索引切换到另一个索引
给多个索引分组 (例如, last_three_months)
给索引的一个子集创建 视图
怎样使用别名在零停机下从旧索引切换到新索引。
有两种方式管理别名: _alias 用于单个操作, _aliases 用于执行多个原子级操作。
假设你的应用有一个叫 my_index 的索引。事实上, my_index 是一个指向当前真实索引的别名。真实索引包含一个版本号:my_index_v1 , my_index_v2 等等。
首先,创建索引 my_index_v1 ,然后将别名 my_index 指向它:
创建索引 my_index_v1 。
PUT /my_index_v1
设置别名 my_index 指向 my_index_v1
PUT /my_index_v1/_alias/my_index
你可以检测这个别名指向哪一个索引:
GET /*/_alias/my_index
或哪些别名指向这个索引:
GET /my_index_v1/_alias/*两者都会返回下面的结果:
{
"my_index_v1" : {
"aliases" : {
"my_index" : { }
}
}
}
一个别名可以指向多个索引,所以我们在添加别名到新索引的同时必须从旧的索引中删除它。这个操作需要原子化,这意味着我们需要使用 _aliases 操作:
POST /_aliases
{
"actions": [
{ "remove": { "index": "my_index_v1", "alias": "my_index" }},
{ "add": { "index": "my_index_v2", "alias": "my_index" }}
]
}
你的应用已经在零停机的情况下从旧索引迁移到新索引了。
持续更新,欢迎扫码关注,敬请期待!
温馨提示
如果你喜欢本文,请分享到朋友圈,想要获得更多信息,请关注我。