l老师我总结了一下,帮忙看看有没有错误之处和遗漏的地方:
1)客户端发起数据写入请求,对你写的这条数据根据_routing规则选择发给哪个Shard。
确认Index Request中是否设置了使用哪个Filed的值作为路由参数,
如果没有设置,则使用Mapping中的配置,
如果mapping中也没有配置,则使用_id作为路由参数,然后通过_routing的Hash值选择出Shard,最后从集群的Meta中找出出该Shard的Primary节点。
2)写入请求到达Shard后,先把数据写入到内存(buffer)中,同时会写入一条日志到translog日志文件中去。
当写入请求到shard后,首先是写Lucene,其实就是创建索引。
索引创建好后并不是马上生成segment,这个时候索引数据还在缓存中,这里的缓存是lucene的缓存,并非Elasticsearch缓存,lucene缓存中的数据是不可被查询的。
3)执行refresh操作:从内存buffer中将数据写入os cache(操作系统的内存),产生一个segment file文件,buffer清空。
写入os cache的同时,建立倒排索引,这时数据就可以供客户端进行访问了。
默认是每隔1秒refresh一次的,所以es是准实时的,因为写入的数据1秒之后才能被看到。
buffer内存占满的时候也会执行refresh操作,buffer默认值是JVM内存的10%。
通过es的restful api或者java api,手动执行一次refresh操作,就是手动将buffer中的数据刷入os cache中,让数据立马就可以被搜索到。
若要优化索引速度, 而不注重实时性, 可以降低刷新频率。
4)translog会每隔5秒或者在一个变更请求完成之后,将translog从缓存刷入磁盘。
translog是存储在os cache中,每个分片有一个,如果节点宕机会有5秒数据丢失,但是性能比较好,最多丢5秒的数据。。
可以将translog设置成每次写操作必须是直接fsync到磁盘,但是性能会差很多。
可以通过配置增加transLog刷磁盘的频率来增加数据可靠性,最小可配置100ms,但不建议这么做,因为这会对性能有非常大的影响。
5)每30分钟或者当tanslog的大小达到512M时候,就会执行commit操作(flush操作),将os cache中所有的数据全以segment file的形式,持久到磁盘上去。
第一步,就是将buffer中现有数据refresh到os cache中去。
清空buffer 然后强行将os cache中所有的数据全都一个一个的通过segmentfile的形式,持久到磁盘上去。
将commit point这个文件更新到磁盘中,每个Shard都有一个提交点(commit point), 其中保存了当前Shard成功写入磁盘的所有segment。
把translog文件删掉清空,再开一个空的translog文件。
flush参数设置:
index.translog.flush_threshold_period:
index.translog.flush_threshold_size:
#控制每收到多少条数据后flush一次
index.translog.flush_threshold_ops:
6)Segment的merge操作:
随着时间,磁盘上的segment越来越多,需要定期进行合并。
Es和Lucene 会自动进行merge操作,合并segment和删除已经删除的文档。
我们可以手动进行merge:POST index/_forcemerge。一般不需要,这是一个比较消耗资源的操作。
作者回复: 非常棒的总结。你是听了课查了文档总结的吗?
当数据从hot移动到warm,官方建议手工执行一下_forcemerge