一 分片和副本
- 分片特性
分片存储部分数据,可以分布任意节点上;
分片在创建索引时指定且不许更改,默认为5个;
分片有主副之分,四线数据高可用;
副本分片的数据由主分片同步,提高读取吞吐量; - 实例操作
集群设置:
node1/node2/node3,且node1为主节点;
创建索引:
PUT test_index
{
"settings":{
"number_of_shards":3, ##分片数为3
"number_of_replicas":1 ##副本数为1
}
}
分片和副本分布:
node1-p0 r1 node2-p1 r2 node3-p2 r0
- 问题
1-在上述的分布式环境中,增加节点数是否提高test_index的数据容量?
不能,因为只有3个分片,且已经分布在3台节点上,新增节点无法使用;
2-增加副本数是否可以提高test_index的读取吞吐量?
不能,新增的副本依然分布在三个节点上,利用同样资源;
3-建议:
分片数过小,无法通过新增节点实现水平扩容;
分片数过大,导致一个节点上存在多个分片,造成资源浪费;
二 集群状态
- 集群状态
Green:健康状态,所有主副分片正常分配;
Yellow:主分片分配正常,但是副本分片分配不正常;
Red:存在主分片未分配; - 故障转移
集群设置:
node1/node2/node3,且node1为主节点;
主分片数为3,副本数为1,
故障转移:
1-主副分片分布为:node1-p0 r1 node2-p1 r2 node3-p2 r0,当前集群为Green状态;
2-node1宕机,node2/node3发现node1宕机后,发起master选举,假设node2为新主节点,
此时主副分片分布为:node2-p1 r2 node3-p2 r0,集群为Red状态;
3-由于主分片p0未分配,新主节点node2将node3上的r0副分片提升为主分片p0,
此时主副分片分布为:node2-p1 r2 node3-p2 p0,集群为Yellow状态;
4-node2为p0和p1生成新的副本,
此时主副分片分布为:node2-p1 r2 r0 node3-p2 p0 r1,集群为Green状态;
三 文档分布式存储
- 文档到分片的映射
文档在分片中尽量分布均匀,充分利用资源;
文档映射算法:
shard = hash(routing) % number_of_primary_shards
1-hash算法保证数据均匀分布在分片中;
2-routing是关键参数,默认是文档id,也可自行指定;
3-算法与主分片数有关,分片数确定后不可更改的原因;
四 脑裂问题
- 脑裂
同一个集群中两个master,维护不同的cluster state,网络恢复后无法选择正确的master; - 实例操作
集群设置:
node1/node2/node3,且node1为主节点;
脑裂发生:
1-node1与node2和node3间的网络发生隔离;
2-node2与node3自己选举新主节点node2,node2维护新的cluster state;
3-node1自己组成集群后,更新自己的cluster state;
4-网络恢复后,一个集群两个master,两个cluster state,无法恢复统一;
解决方案:
可选举的master-eligible节点数大于quorum时进行master选举,
quorum = master-eligible/2 + 1
在以上问题中,node1数目小于quorum2,无法进行master选举;
设定discovery.zen.minumum_master_nodes为quorum即可避免脑裂;
五 文档搜索实时性
- refresh
segment写入磁盘耗时,借助文件系统缓存特性,将segment缓存并开放搜索实时性,称为refresh;
refresh之前将文档存储到一个buffer中,refresh时将buffer中的文档清空生成segment;
refresh发生时机:
1-间隔时间到达,通过index.settings.refresh_interval来设定,默认时1秒;
2-index.buffer满时,其大小通过indices.memory.index_buffer_size设置,默认为JVM heap的10%,所有shard共享;
3-flush发生时发生;
translog
解决内存中segment未写入磁盘就发生宕机问题;
文档写入buffer时,同时将请求操作写入translog,6.x默认每个请求都落盘;
Es启动时检查translog文件,并从中恢复数据;flush
负责将内存中的segmet写入磁盘;
将index buffer清空,其中的文档生成一个新的segment,相当于一个refresh操作;
更新commit point并写入磁盘;
执行fsync操作,将内存中的segment写入磁盘;
删除旧的translog日志;
flush发生时机:
1-间隔时间到达时,默认时间时30分钟,5.x之前通过index.translog.flush_threshold_period修改;
2-translog占满时,大小通过index.translog.flush_threshold_size控制,默认时512m;
- 删除与更新文档
segment一旦创建就不能更改,如何删除与更新文档呢?
删除:
1-维护一个.del文件,记录所有删除文档的id,查询时过滤.del中的所有文档;
更新:
1-首先删除文档,后新建文档;
- segment merge
Es会定时在后台进行segment merge操作,减少segment的数量;
通过force_merge api实现手动强制做segment merge;