

1、客户端写请求发送到协调节点(Coordinating Node)
2、协调节点路由写请求到活跃的shard中。路由规则:(实现类OperationRouting)
2.1 默认: hash(document_id)/(主shard数)
2.2 根据指定字段的值作为路由参数: hash(参数值)/(主shard数)。思考:分母为什么是主shard数?主要是因为写入时需要先写入主shard中。然后再同步到副shard中去。
3、数据先写入主分片的memory buffer中,然后再写入到transaction log(默认同步,也可配置为异步),当主分片中的请求全部返回成功后,再并行写入到副分片中。当主副本全部写入成功后即返回到客户端。此时数据是不能被搜索的。只能通过id在trans log中提取。
4、refresh阶段: memory buffer会周期性(默认1s)的做refresh操作。将内容写入到一个新的segment中。此阶段对应lucene的flush阶段。故此时数据可以被搜索。但并没有落盘持久化。
5、flush阶段: 每隔30分钟或者当trans log中的数据量太大时,会产生一次flush操作。该操作会清空内存缓冲区,从而产生一个新的segment,触发一个lucene的commit操作,落盘产生一个commit point点(就是备份)。此时trans log就可以被清除了。
6、segment合并阶段: lucene会定期merge一些小的segment至一个大的segment中。防止segment太多,占用太多文件句柄及降低查询效率。
refresh阶段主要是将之前写入缓冲区的数据,刷成一个新的segment。保证数据可搜索。这个刷新的频率,影响搜索的实时性。
具体过程如图:
1、数据写入内存缓冲区和translog

2、数据refresh成一个segment, 同时清空缓冲区的内容。此时的segment没有落盘。但同样是可搜索的

缓冲区属于节点级别的资源,节点上的所有shard共享。关于缓冲区大小的配置如下:
indices.memory.index_buffer_size 缓冲区大小。默认是节点总堆的10%。也可配置为绝对值。
indices.memory.min_index_buffer_size 如果index_buffer_size为百分比,则该参数可设置缓冲区最小值。默认48mb。
indices.memory.max_index_buffer_size 如果index_buffer_size为百分比,则该参数可设置缓冲区最大值。默认无界。
缓冲区刷新频率的配置:
refresh_interval 刷新频率。默认每秒刷新一次。 设置为-1为关闭刷新。
接口:
POST /blogs/_refresh 指定索引刷新
POST /_refresh 全部手动
PUT /my_logs/_settings 关闭自动刷新
{ "refresh\_interval": -1 }
PUT /my_logs/_settings 每秒刷新1次
{ "refresh_interval": "1s" }1、每30分钟或者当translog中的数据达到阈值后,会触发一次flush操作。产生一个point点。并落到磁盘。

2、commit point点产生,会清空内存缓冲区及translog数据

translog相关配置
index.translog.sync_interval 刷新频率。默认5s,不能低于100ms
index.translog.durability 刷新方式。默认request(同步), async 异步
index.translog.flush_threshold_size flush阶段的translog阈值。默认512mb。如果达到则会强制flush,否则需要等待30分钟
index.translog.retention.size 保留的translog大小。默认512mb
index.translog.retention.age 保留的translog时间。默认12h上面2个translog保留的配置可能会用于副本的恢复。不会影响写入性能。
index.translog.generation_threshold_size 单个独立translog的大小阈值,如果超过则生成新的translog,不flush。默认64mb。
flush api可以针对单个或者所有索引进行flush
POST /twitter/_flush/synced
POST /blogs/_flush
POST /_flush?wait_for_ongoing 同步刷新
异步,5s频率
PUT /my_index/_settings
{
"index.translog.durability": "async",
"index.translog.sync\_interval": "5s"
}1、将refresh和flush产生的segment进行合并,合并成一个大的segment。合并过程中的segment仍可以被搜索。如下图:

2、合并完成后会进行一个flush操作。产生一个新的commit point点。同时将已合并的segment删除。

配置汇总
index.merge.policy.floor_segment 最小参考的segment的大小,并非实际最小segment的大小。默认设置为2mb
index.merge.policy.max_merge_at_once 单次合并的最大segment数量。默认是10个
index.merge.policy.max_merged_segment 合并时的最大segment阈值,大于该阈值的正常不会合并。除非触发了第3种情况的合并规则。默认5gb
index.merge.policy.segments_per_tier 每层的segment数量
index.merge.policy.deletes_pct_allowed segment中文档删除百分比。取值范围:20~50。默认值是33.当达到该值时即使segment大于max_merged_segment大小也会发生merge
index.merge.scheduler.max_merge_count 最大merge次数
index.merge.policy.max_merge_at_once_explicit forceMerge或forceMergeDeletes方式时单次合并的最大segment数量。默认30es中的合并分为3种类型:
1)NATURAL: 常规合并。合并一些小于指定segment阈值以内的segment。使其成为一个大的segment。提高index效率。es自动完成。
2) FORCE_MERGE_DELETES:合并一些大于指定segment阈值且包含大量已删除文件的segment。也就是给大segment "瘦身" , es自动完成。
3)FORCE_MERGE: 手动强制合并。通过api接口调用。一般情况不需要使用。
注意:所有算法中,标注颜色的变量均是配置项,即可调优参数。
index.merge.policy.floor_segment 最小参考的segment的大小,并非实际最小segment的大小。默认设置为2mb
index.merge.policy.max_merge_at_once 单次合并的最大segment数量。默认是10个
index.merge.policy.max_merged_segment 合并时的最大segment阈值,大于该阈值的正常不会合并。除非触发了FORCE_MERGE_DELETES合并规则。默认5gb
index.merge.policy.segments_per_tier 每层的segment数量。
index.merge.policy.deletes_pct_allowed segment中文档删除百分比。取值范围:20~50。默认值是33.当达到该值时即使segment大于max_merged_segment大小也会发生merge
index.merge.scheduler.max_merge_count 最大merge次数 1、根据 segment大小倒序排列 并 剔除不符合条件的segment
1) 正在参与合并操作的segment
2) segment大小大于maxMergedSegmentBytes/2(maxMergedSegmentBytes默认5g)且segment中删除文档的比例较低的segment(segDelPct <=deletesPctAllowed)
2、计算触发merge条件的segment数(allowedSegCount),如果实际待merge的segment数小于该值则不会触发合并。具体算法:

假设如下配置: floorSegmentBytes = 2*1024*1024 , segsPerTier= 10, maxMergeAtOnce= 20,maxMergedSegmentBytes= 50*1024*1024
索引中最小: segment:minSegmentBytes = 1 1024 1024
索引大小:totIndexBytes = 500 1024 1024
则allowedSegCount = 26;
3、从待合并的segment列表中分层提取segment进行merge。直到待合并的segment列表中的元素小于 allowedSegCount 时,则中止此次合并。
1)每层中segment的大小总和不得超过maxMergedSegmentBytes
2)每层中segment的个数不得超过mergeFactor
`final int mergeFactor = (int) Math.min(maxMergeAtOnce,segsPerTier);` 3)层的个数不得超过max_merge_count
由于待合并的segment是倒序排列,则合并的原则总是优先合并满足条件的大的segment。
例如: maxMergedSegmentBytes = 5G, 则蓝色是可以合并,红色是不能合并的。如下图:

对segment中已删除文档的比例大于deletes_pct_allowed阈值的segment进行合并
index.merge.policy.deletes_pct_allowed segment中文档删除比例的阈值。取值范围:20~50。默认值是33.当达到该值时即使segment大于max_merged_segment大小也会发生merge。
index.merge.policy.max_merge_at_once_explicit forceMerge或forceMergeDeletes方式时单次合并的最大segment数量。默认301、查找所以segment中是否存在已删除的文档比例大于deletes_pct_allowed阈值且处于未合并状态的segment。如果有,则继续。没有,则返回。

2、对所有segment根据大小按照降序排序 并 剔除不符合的segment。
1)正在参与合并的segment
2) 已删除的文档比例小于 deletes_pct_allowed的segment
注意:这里没有剔除大于maxMergedSegmentBytes / 2的segment。这是和常规合并最大的区别。

3、从待合并的segment列表中分层提取segment进行merge。直到合并所有的待合并segment,则中止此次合并。这里的中止条件和常规合并的不一致。
1) 当前层中存在多个segment时,此层中segment的大小总和不得超过 maxMergedSegmentBytes。
2) 当前层中存在单个segment时,此层中的segment大小没有限制。可以大于maxMergedSegmentBytes,也可以小于maxMergedSegmentBytes。
3)每层中segment的个数不得超过 maxMergeAtOnceExplicit
注:由于待合并的segment是倒序排列,则合并的原则总是优先合并满足条件的大的segment。和常规合并的策略一致。
index.merge.policy.max_merge_at_once_explicit forceMerge或forceMergeDeletes方式时单次合并的最大segment数量。默认30
max_num_segments 最终合并的segment个数,通过api参数指定。
api 如下:
POST /test/_forcemerge?only_expunge_deletes=false&max_num_segments=100&flush=true1、对所有segment根据大小按照降序排序 并 剔除不符合的segment。
1) 正在合并中的segment
2) 大于mergeBytes的segment
2、计算合并后的单个segment大小上限(maxMergeBytes)。可以看到当指定只合并成1个segment时,maxMergeBytes基本是接近无限大的。**
最小也是maxMergedSegmentBytes的1.25倍。最大就看指定合并后的segment个数和总的待合并的大小

3、从待合并的segment列表中分层提取segment进行merge。直到合并所有的待合并segment,则中止此次合并。`这里的中止条件和常规合并的不一致。
1)单层合并
1、待合并的segment个数小于max_merge_at_once_explicit
2、只合并成1个segment。
3、待合并的segment总大小 小于 maxMergeBytes

2)分层合并
1) 当前层中存在多个segment时,此层中segment的大小总和不得超过 maxMergeBytes。
2) 每层中segment的个数不得超过 maxMergeAtOnceExplicit
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。