记录一下es丢失分片的问题。
5.4.3版本的es。3个节点分布在三台主机上,分片设置为5分片1副本的配置。因为压力测试,需要升级节点java堆内存,从2G升级到6G。因为是测试集群,在改了jvm.options配置之后(要改es软件目录下的才生效,配置目录下的不生效),挨个重启节点,每个节点相差几秒钟的样子。好了,在我一顿操作猛如虎之后,集群起来了,皆大欢喜,继续测试。过了10来天,开发找过来,说一个refresh操作需要执行超过10s,问题必现。拿到出问题的索引后,通过GET /_cluster/state 发现0和3分片unassigned。再继续通过explain:
GET /_cluster/allocation/explain
{
"index": "dcvs_nonmotorvehicle",
"shard": 3,
"primary": true
}
结果如下:
{
"index": "dcvs_nonmotorvehicle",
"shard": 3,
"primary": true,
"current_state": "unassigned",
"unassigned_info": {
"reason": "CLUSTER_RECOVERED",
"at": "2020-04-10T03:40:41.127Z",
"last_allocation_status": "no_valid_shard_copy"
},
"can_allocate": "no_valid_shard_copy",
"allocate_explanation": "cannot allocate because a previous copy of the primary shard existed but can no longer be found on the nodes in the cluster",
"node_allocation_decisions": [
{
"node_id": "TklXzLKySf-czdu8zZ5hyQ",
"node_name": "MYSQL2",
"transport_address": "10.45.156.202:9300",
"node_attributes": {
"cname": "202",
"rack_id": "rack_two"
},
"node_decision": "no",
"store": {
"found": false
}
},
{
"node_id": "WDaA85bmQhKZxvgq4ve0Kw",
"node_name": "MHA-MASTER",
"transport_address": "10.45.156.210:9300",
"node_attributes": {
"cname": "210",
"rack_id": "rack_three"
},
"node_decision": "no",
"store": {
"found": false
}
},
{
"node_id": "dAXXDGDyQaGcex6VcZP0eg",
"node_name": "MYSQL1",
"transport_address": "10.45.156.201:9300",
"node_attributes": {
"cname": "201",
"rack_id": "rack_one"
},
"node_decision": "no",
"store": {
"found": false
}
}
]
}
从这个结果来看,分片没有分配是因为在集群上没有找到对应分片的文件,但是这个有点扯,3个节点,一主一从的分片配置,怎么同时primary和replica都丢了。日志没有发现错误。cannot allocate because a previous copy of the primary shard existed but can no longer be found on the nodes in the cluster。
注意上面的store项,"found": false表示没有找到分片的任何segment文件。如果能找到分片较旧的segment,这里会显示对应陈旧的allocate id的内容。
"store": {
"found": false
}
说到较旧的分片,就不能不说in_sync_allocations。这其中包括了各个索引最新的primary分片以及副本的allocate id。不在此之内的,就是陈旧的了。关于allocate id的由来,可参考Allocate primary shard based on allocation IDs #14739 。这个特性是在5.0以后引入的,5.0以前的版本可能会因为index.number_of_replicas设置大于当前启动的节点数,而导致分片不能recover并处于unassigned状态,可参考Unassigned shards after complete cluster failure (All nodes down) #18393。
GET _cluster/state?filter_path=metadata.indices.dcvs_nonmotorvehicle.in_sync_allocations.*
response:
{
"metadata": {
"indices": {
"dcvs_nonmotorvehicle": {
"in_sync_allocations": {
"0": [
"jEUUKBeZR3qkoQRAGswKDw",
"vjwq3vkBTlG1Yyv1r52Jvw"
],
"1": [
"9KaFWzldRvihoyW29tEEeA",
"r3zovKQ-SdGx-22SaM0Akw"
],
"2": [
"C2gf_7P1QDylq9d8vSPvGg",
"qEFI9y72TFKQAZagr1_GbA"
],
"3": [
"G5iiaRxMR_OMbf6piZDFmQ",
"uxj0i2THQgSsU3WOaJjr5g"
],
"4": [
"Z-pnmvQ_QuGs3lUIXx2IdQ",
"nSj91FNnTwuQbF76cqsyZw"
]
}
}
}
}
}
临时的处理是对unassigned的分片重新分配了空的内容,但是这会使分片上原有的内容丢失。即使后来再通过任何方法把分片找回来,es也会将后来找到的内容delete并overwrite。因为es会认为,后来分配的空分片的内容是较新的。
重新分配分片使用reroute API。reroute接受两种操作allocate_stale_primary和allocate_empty_primary。这两种都会造成数据丢失,es出于提醒用户的目的,因此专门需要指定"accept_data_loss": true 。另外就是指定索引名称、要分配的分片id、和要将分片分配到的节点名称,这里只primary分片,replicat分片会自动找节点存储。
allocate_stale_primary:以集群内存在的陈旧的分片内容,再次分配。
allocate_empty_primary:分配空内容的分片
例如:
POST /_cluster/reroute
{
"commands" : [
{
"allocate_stale_primary" : {
"index" : "dcvs_aps", "shard" : 3,
"node" : "MYSQL2",
"accept_data_loss": true
}
}
]
}
这里简单说下索引在磁盘上的存储结构:比如下面这个,
data/nodes/0/indices/dVPzxUgxRoubKRDEb4Qktg/0/index
data/nodes/0/indices都是一样的,dVPzxUgxRoubKRDEb4Qktg就是索引的唯一id,后面的0表示是分片id=0,再后面的index文件夹下面,就是segment文件了,如下是整个树形结构。中间省略了一大部分。
[elasticsearch@mysql2 indices]$ pwd
/bigdata/cluster5.4/data/nodes/0/indices
[elasticsearch@mysql2 indices]$ cd ..
[elasticsearch@mysql2 0]$ ls
indices node.lock _state
[elasticsearch@mysql2 0]$ tree -l -N
.
├── indices
│ ├── 00iymGs4R9iuuxVCbdWanQ
│ │ ├── 0
│ │ │ ├── index
│ │ │ │ ├── segments_e
│ │ │ │ └── write.lock
│ │ │ ├── _state
│ │ │ │ └── state-1.st
│ │ │ └── translog
│ │ │ ├── translog-1.tlog
│ │ │ └── translog.ckp
│ │ ├── 1
│ │ │ ├── index
│ │ │ │ ├── segments_f
│ │ │ │ └── write.lock
│ │ │ ├── _state
│ │ │ │ └── state-1.st
│ │ │ └── translog
│ │ │ ├── translog-1.tlog
│ │ │ └── translog.ckp
│ │ ├── 2
│ │ │ ├── index
│ │ │ │ ├── _0.cfe
│ │ │ │ ├── _0.cfs
│ │ │ │ ├── _0.si
│ │ │ │ ├── segments_f
│ │ │ │ └── write.lock
│ │ │ ├── _state
│ │ │ │ └── state-1.st
│ │ │ └── translog
│ │ │ ├── translog-1.tlog
│ │ │ └── translog.ckp
│ │ └── _state
│ │ └── state-98.st
...
├── node.lock
└── _state
├── global-8603.st
└── node-11.st
1460 directories, 5702 file
临时的处理过后,继续寻找原因中。
每一次出现问题都是进步的机会,出现问题使我烦恼,解决问题使我快乐。