学习/软件编程等

021.Elasticsearch索引管理高级篇

2020-07-15  本文已影响0人  CoderJed

1. 索引别名

在开发中,随着业务需求的迭代,较老的业务逻辑就要面临更新甚至是重构,而对于ES来说,为了适应新的业务逻辑,可能就要对原有的索引做一些修改,比如对某些字段做调整,甚至是重建索引,而做这些操作的时候,可能会对业务造成影响,甚至需要停机调整,由此,ES引入了索引别名来解决这些问题,索引别名就像一个快捷方式或是软链接,可以指向一个或多个索引,也可以给任意一个需要索引别名的API来使用,别名的应用为程序提供了极大的灵活性。

2. 索引重建

Elasticsearch的索引在创建好之后其数据结构和一些固有设置是不能修改的,如果一定要修改其数据结构和某些设置例如主分片的个数,那么就必须重建索引,ES提供了一些辅助工具来支持索引重建。

索引重建步骤:

案例:

# 创建index_old
PUT index_old
{
  "mappings": {
    "_doc": {
      "properties": {
        "id": {"type": "long"},
        "name": {"type": "text"}
      }
    }
  }
}

POST /_bulk
{"index":{"_index":"index_old","_type":"_doc","_id":"1"}}
{"id": 1001, "name": "张三丰"}
{"index":{"_index":"index_old","_type":"_doc","_id":"2"}}
{"id": 1002, "name": "张无忌"}
{"index":{"_index":"index_old","_type":"_doc","_id":"3"}}
{"id": 1003, "name": "虚竹"}
{"index":{"_index":"index_old","_type":"_doc","_id":"4"}}
{"id": 1004, "name": "云中鹤"}
{"index":{"_index":"index_old","_type":"_doc","_id":"5"}}
{"id": 1005, "name": "杨过"}

# 此时我们要把name字段的类型由text修改为keyword,就必须重建索引
# 1.index_old取一个别名index_service,index_service对外提供服务
POST /_aliases
{
  "actions": [
    {
      "add": {
        "index": "index_old",
        "alias": "index_service"
      }
    }
  ]
}

# 2.新创建一个索引index_new,数据结构与index_old一样,但是name字段的类型为keyword
PUT index_new
{
  "mappings": {
    "_doc": {
      "properties": {
        "id": {"type": "long"},
        "name": {"type": "keyword"}
      }
    }
  }
}

# 3.将index_old的数据同步到index_new
# ES6.X需要指定旧索引的type和新索引的type
POST /_reindex?wait_for_completion=false
{
  "source": {
    "index": "index_old", 
    "type": "_doc"
  },
  "dest": {
    "index": "index_new", 
    "type": "_doc"
  }
}
# ES7.X不需要指定type
POST /_reindex?wait_for_completion=false
{
  "source": {
    "index": "index_old"
  },
  "dest": {
    "index": "index_new"
  }
}
# wait_for_completion=true,同步执行,会一直等待直到同步完成或者报错,默认
# wait_for_completion=false,异步执行,返回taskId,然后后台进行同步,数据量大的情况下建议使用

# 4.将index_old的别名删除,index_new的别名设置为index_service
POST /_aliases
{
  "actions": [
    {
      "remove": {
        "index": "index_old",
        "alias": "index_service"
      }
    },
    {
      "add": {
        "index": "index_new",
        "alias": "index_service"
      }
    }
  ]
}

# 5.删除index_old
DELETE /index_old

3. refresh、flush和merge

3.1 document写入原理一

3.2 document写入原理二:refresh

上述流程是有问题的,从写入一条document到OS Cache将segment刷写到磁盘,并且该segment被打开允许搜索这个过程是有延迟的,可能达到min级别,这就不是近实时的搜索了,上述流程的主要瓶颈在于OS Cache将segment刷写到磁盘的过程,于是,我们想,只要数据被写入OS Cache中了,就可以被搜索,而不用刷写到磁盘后才能搜索,这样就可以提高搜索效率,索引刷新(refresh)功能就是让某条数据在写入OS Cache后就可以被搜索。

refresh默认时间间隔是1s,也就是说每隔一秒,将buffer中的数据写入到OS Cache中,并且允许该数据被搜索。

# 数据写入就强制刷新
PUT /index_name/type_name/id?refresh
{
  "data": "..."
}

# 设置index的刷新时间
PUT /index_name/_settings
{
  "index": {
    "refresh_interval": "5s"
  }
}

3.3 document写入原理三:translog和flush

在原理二的优化之后,ES就可以满足近实时的查询效率,但是还有一个问题是可靠性,因为document在真正的写入磁盘之前都是在内存中的,那么ES宕机就可能会丢失数据,Translog文件可以解决这个问题:

改进后得流程如下:

(1) document写入buffer缓冲,同时写入Translog日志文件

(2) 每隔1s,buffer中的数据被写入新的segment,并进入OS Cache,此时segment被打开并可以用于搜索

(3) buffer被清空

(4) 重复(1)-(3),新的segment不断添加,buffer不断被清空,而translog中的数据不断累加

(5) 当translog的大小达到一定程度,触发flush操作:

​ (5-1) buffer中的所有数据写入一个新的segment,并写入OS Cache,segment被打开并可以用于搜索

​ (5-2) buffer被清空

​ (5-3) 一个commit ponit文件被写入磁盘,其中标明了index当前所有的segment有哪些

​ (5-4) OS Cache中的所有segment缓存数据,被强行刷写到磁盘上

​ (5-5) 现有的translog被清空,创建一个新的translog

基于Translog如何进行数据恢复?

ES宕机之后,内存中的数据全部丢失,重启之后,上一次flush之后的全部数据都在Translog中保存着,将这些数据重新加载到内存buffer中并形成一个个segment然后写入OS Cache中即可。

相关设置参数如下:

index.translog.durability:新增、删除,更新或批量操作之后是否写入Translog并触发flush操作

index.translog.sync_interval:写数据请求提交到Translog并触发flush操作的时间间隔,默认5s,最小不能低于100ms

index.translog.flush_threshold_size:Translog触发flush操作的文件大小阈值,默认512mb

PUT /index_name/_settings
{
    "index.translog.durability": "async",
    "index.translog.sync_interval": "5s"
}

# 手动触发flush操作
POST /index_name/_flush

3.4 document写入原理四:segment merge

在上述写入流程中,每秒生成一个segment,segment数量太多,每次search都要搜索所有的segment,性能不好,ES默认会在后台执行segment merge操作,在merge的时候,被标记为deleted的document也会被彻底物理删除,每次merge操作的执行流程:

手动执行merge的API:

# max_num_segments指定了合并之后的segments个数
POST /index_name/_optimize?max_num_segments=1
上一篇 下一篇

猜你喜欢

热点阅读