Fork me on GitHub

Elasticsearch 重建索引 (Modify Mappings)

Es重建索引是个比较麻烦的事情,过程繁琐且迁移数据的过程也很漫长,一下将介绍如何rebuild index

software version
elasticsearch 6.4.2

由于es 的mapping结构无法直接更改,所以如果需要修改mapping结构,则必须rebuild一个索引,利用alias机制将新建索引与老索引关联,然后做数据迁移

基本概念

  1. Es别名机制不再赘述,规定索引名为indexName-日期,如test_index-190807
  2. 两个alias分别为indexNameindexName$,其中indexName是每个索引都有的alias,用于提供read操作;indexName$用于提供write操作(即做到只write当前alias索引,其他alias索引均可提供read)

Alias规则如何确定,可根据实际业务需要确定

思路描述

例如indexName=test_index-old

1.按新schema结构建立索引test_index-new(新索引结构必须与旧的兼容,否则数据迁移会出问题)

2.暂停test_index-old数据写入

3.移除test_index-old的test_index$ alias;添加test_index-new的test_index$ alias,然后恢复数据持续写入(目的是让当前写服务能迁移到新的索引,且alias的操作非常快/秒级,此过程几乎可以看做服务不中断)

此方法在数据迁移时会查出double的重复数据,想要线上业务完全不受影响,可以将当前 write/read 全部转到一个新的index,alias指向新索引;此时将旧索引当做静态数据,数据迁移完成后瞬间切换alias(即创建两个新索引,一个用于持续读写,另一个用于迁移数据)

4.test_index-old 数据迁移至 test_index-new(此过程缓慢)

5.移除test_index-old的test_index alias,添加test_index-new的test_index alias

6.至此test_index-old 的数据已经 迁移到 test_index-new,完成index的rebuild,可删除test_index-old

操作步骤

新建索引

通常用curl或者kibana devtools就可以实现,但是如果mappings、settings比较复杂建议用程序先获取old index info,再此基础上做改动,然后再新建;此步骤必须保证新索引结构可以完全兼容旧索引

1
2
3
4
5
6
7
8
9
// 通过java rest client

LowLevelClient().performRequest(method, endpoint, requsetBody);

// 1. 使用GET方法获取index info
// 2. 解析response 获取settings、mappings,并修改
// 3. 建立新索引

CreateIndexResponse resp = HighLevelClient().indices().create(new CreateIndexRequest(index).mapping("data", mappings).settings(settings));

迁移index$ Write Alias

此操作前必须停止索引写入

1
2
3
4
5
6
7
8
9
10
// 移除Alias
POST /_aliases
{
"actions": [{
"remove": {
"index": "test_index-old",
"alias": "test_index$"
}
}]
}
1
2
3
4
5
6
7
8
9
10
11
12
// 添加Alias
POST /_aliases
{
"actions": [
{
"add": {
"index": "test_index-new",
"alias": "test_index$"
}
}
]
}

执行结束后开启写索引

数据迁移

1
2
3
4
5
6
7
8
9
POST _reindex?wait_for_completion=false
{
"source": {
"index": "test_index-old"
},
"dest": {
"index": "test_index-new"
}
}

此命令会返回taskId,可根据Id查询运行状态

1
GET _tasks/{taskId}

中途遇到什么问题可以终止task

1
PUT _tasks/{taskID}/cancel

迁移index Read Alias

1
2
3
4
5
6
7
8
9
10
11
12
// 添加Alias
POST /_aliases
{
"actions": [
{
"add": {
"index": "test_index-new",
"alias": "test_index"
}
}
]
}
1
2
3
4
5
6
7
8
9
10
// 移除Alias
POST /_aliases
{
"actions": [{
"remove": {
"index": "test_index-old",
"alias": "test_index"
}
}]
}

此时test_index-old 已经被重建为 test_index-new

调优

Elasticsearch 的数据迁移过程十分缓慢,通过以下方法可以进行调优(实测:3个Es nodes,30G+数据,60m+ Docs,Task需要30—40min左右结束)

1.source中调整batch_size(defailt: 1000)

批量大小取决于数据、分析和集群配置,但一个好的起点是每批处理5-15MB

1
2
3
4
"source": {
"index": "sourceIndex",
"size": 5000
}

2.slicing 配置

1
POST _reindex?slices=5&refresh

【slices大小设置注意事项】

  • slices大小的设置可以手动指定,或者设置slices设置为auto,auto的含义是:针对单索引,slices大小=分片数;针对多索引,slices=分片的最小值
  • 当slices的数量等于索引中的分片数量时,查询性能最高效。slices大小大于分片数,非但不会提升效率,反而会增加开销
  • 如果这个slices数字很大(例如500),建议选择一个较低的数字,因为过大的slices 会影响性能

3.关闭刷新和副本

在数据迁移过程中关闭refresh_interval、number_of_replicas可以大幅提升性能,迁移完成后恢复默认值

1
2
3
4
5
PUT indexName/_settings
{
"refresh_interval": "-1",
"number_of_replicas": "0"
}

转载请注明出处:https://github.com/imperio-wxm


Thank you for your support.