Elasticsearch架构原理
原理
本书作为 Elastic Stack 指南,关注于 在⽇志和数据分析场景的应⽤,并不打算对底层的 Lucene 原理或者 Java 编程做详细的介绍,但是Elasticsearch 层⾯上的⼀些架构设计,对我们做性能调优,故障处理,具有⾮常重要的影响。
所以,作为 ES 部分的起始章节,先从数据流向和分布的层⾯,介绍⼀下 ES 的⼯作原理,以及相关的可控项。各位读者可以跳过这节先⾏阅读后⾯的运维操作部分,但作为性能调优的基础知识,依然建议⼤家抽时间返回来了解。
带着问题学习
1. 写⼊的数据是如何变成elasticsearch⾥可以被检索和聚合的索引内容的?
2. lucene如何实现准实时索引?
3. 什么是segment?
4. 什么是commit?
5. segment的数据来⾃哪⾥?
6. segment在写⼊磁盘前就可以被检索,是因为利⽤了什么?
7. elasticsearch中的refresh操作是什么?配置项是哪个?设置的命令是什么?
8. refresh只是写到了⽂件系统缓存,那么实际写⼊磁盘是由什么控制呢?,如果这期间发⽣错误和故障,数据会不会丢失?
9. 什么是translog⽇志?什么时候会被清空?什么是flush操作?配置项是什么?怎么配置?
10.什么是段合并?为什么要段合并?段合并线程配置项?段合并策略?怎么forcemerge(optimize)?
10. routing的规则是什么样的?replica读写过程?wait_for_active_shards参数timeout参数 ?
11. reroute 接⼝?
12. 两种 ⾃动发现⽅式?
⽬录
segment、buffer和translog对实时性的影响
既然介绍数据流向,⾸先第⼀步就是:写⼊的数据是如何变成 Elasticsearch ⾥可以被检索和聚合的索引内容的?
以单⽂件的静态层⾯看,每个全⽂索引都是⼀个词元的倒排索引,具体涉及到全⽂索引的通⽤知识,这⾥不单独介绍,有兴趣的读者可以阅读《 in Action》等书籍详细了解。
动态更新的 Lucene 索引
以在线动态服务的层⾯看,要做到实时更新条件下数据的可⽤和可靠,就需要在倒排索引的基础上,再做⼀系列更⾼级的处理。
其实总结⼀下 Lucene 的处理办法,很简单,就是⼀句话:新收到的数据写到新的索引⽂件⾥。
Lucene 把每次⽣成的倒排索引,叫做⼀个段(segment)。然后另外使⽤⼀个 commit ⽂件,记录索引内所有的 segment。⽽⽣成segment 的数据来源,则是内存中的 buffer。也就是说,动态更新过程如下:
1. 当前索引有 3 个 segment 可⽤。索引状态如图 2-1;
图 2-1
2. 新接收的数据进⼊内存 buffer。索引状态如图 2-2;
图 2-2
3. 内存 buffer 刷到磁盘,⽣成⼀个新的 segment,commit ⽂件同步更新。索引状态如图 2-3。
图 2-3
利⽤磁盘缓存实现的准实时检索
既然涉及到磁盘,那么⼀个不可避免的问题就来了:磁盘太慢了!对我们要求实时性很⾼的服务来说,这种处理还不够。所以,在第 3 步的处理中,还有⼀个中间状态:
curl是什么命令1.
内存 buffer ⽣成⼀个新的 segment,刷到⽂件系统缓存中,Lucene 即可检索这个新 segment。索引状态如图 2-4。
图 2-4
2. ⽂件系统缓存真正同步到磁盘上,commit ⽂件更新。达到图 2-3 中的状态。
这⼀步刷到⽂件系统缓存的步骤,在 Elasticsearch 中,是默认设置为 1 秒间隔的,对于⼤多数应⽤来说,⼏乎就相当于是实时可搜索了。Elasticsearch 也提供了单独的 /_refresh 接⼝,⽤户如果对 1 秒间隔还不满意的,可以主动调⽤该接⼝来保证搜索可见。注:5.0 中还提供了⼀个新的请求参数:refresh=wait_for ,可以在写⼊数据后不强制刷新但⼀直等到刷新才返回。
不过对于 Elastic Stack 的⽇志场景来说,恰恰相反,我们并不需要如此⾼的实时性,⽽是需要更快的写⼊性能。所以,⼀般来说,我们反⽽会通过 /_settings 接⼝或者定制 template 的⽅式,加⼤ refresh_interval 参数:
如果是导⼊历史数据的场合,那甚⾄可以先完全关闭掉:
在导⼊完成以后,修改回来或者⼿动调⽤⼀次即可:
【声明:转载请注明出处
独⽴:
简书:
CSDN:】
translog 提供的磁盘同步控制# curl -XPOST 127.0.0.1:9200/logstash-2015.06.21/_settings -d'{ "refresh_interval": "10s" }'
1
2
3# curl -XPUT 127.0.0.1:9200/logstash-2015.05.01 -d'{ "settings" : { "refresh_interval": "-1" }}'
1
2
3
4
5
6# curl -XPOST 127.0.0.1:9200/logstash-2015.05.01/_refresh
1
既然 refresh 只是写到⽂件系统缓存,那么第 4 步写到实际磁盘⼜是有什么来控制的?如果这期间发⽣主机错误、硬件故障等异常情况,数据会不会丢失?
这⾥,其实有另⼀个机制来控制。Elasticsearch 在把数据写⼊到内存 buffer 的同时,其实还另外记录了⼀个 translog ⽇志。也就是说,第 2 步并不是图 2-2 的状态,⽽是像图 2-5 这样:
图 2-5
在第 3 和第 4 步,refresh 发⽣的时候,translog ⽇志⽂件依然保持原样,如图 2-6:
图 2-6
也就是说,如果在这期间发⽣异常,Elasticsearch 会从 commit 位置开始,恢复整个 translog ⽂件中的记录,保证数据⼀致性。
等到真正把 segment 刷到磁盘,且 commit ⽂件进⾏更新的时候, translog ⽂件才清空。这⼀步,叫做 flush。同样,Elasticsearch 也提供了 /_flush 接⼝。
对于 flush 操作,Elasticsearch 默认设置为:每 30 分钟主动进⾏⼀次 flush,或者当 translog ⽂件⼤⼩⼤于 512MB (⽼版本是200MB)时,主动进⾏⼀次 flush。这两个⾏为,可以分别通过 anslog.flush_threshold_period 和 anslog.flush_threshold_size 参数修改。如果对这两种控制⽅式都不满意,Elasticsearch 还可以通过 anslog.flush_threshold_ops 参数,控制每收到多少条数据后 flush ⼀次。
translog 的⼀致性
索引数据的⼀致性通过 translog 保证。那么 translog ⽂件⾃⼰呢?
默认情况下,Elasticsearch 每 5 秒,或每次请求操作结束前,会强制刷新 translog ⽇志到磁盘上。
后者是 Elasticsearch 2.0 新加⼊的特性。为了保证不丢数据,每次 index、bulk、delete、update 完成的时候,⼀定触发刷新 translog 到磁盘上,才给请求返回 200 OK。这个改变在提⾼数据安全性的同时当然也降低了⼀点性能。
如果你不在意这点可能性,还是希望性能优先,可以在 index template ⾥设置如下参数:
Elasticsearch 分布式索引
⼤家可能注意到了,前⾯⼀段内容,⼀直写的是”Lucene 索引”。这个区别在于,Elasticsearch 为了完成分布式系统,对⼀些名词概念作了变动。索引成为了整个集级别的命名,⽽在单个主机上的Lucene 索引,则被命名为分⽚(shard)。⾄于数据是怎么识别到⾃⼰应该在哪个分⽚,请阅读稍后有关 routing 的章节。
segment merge 对写⼊性能的影响
通过上节内容,我们知道了数据怎么进⼊ ES 并且如何才能让数据更快的被检索使⽤。其中⽤⼀句话概括了 Lucene 的设计思路就是”开新⽂件”。从另⼀个⽅⾯看,开新⽂件也会给服务器带来负载压⼒。因为默认每 1 秒,都会有⼀个新⽂件产⽣,每个⽂件都需要有⽂件句柄,内存,CPU 使⽤等各种资源。⼀天有 86400 秒,设想⼀下,每次请求要扫描⼀遍 86400 个⽂件,这个响应性能绝对好不了!为了解决这个问题,ES 会不断在后台运⾏任务,主动将这些零散的 segment 做数据归并,尽量让索引内只保有少量的,每个都⽐较⼤的,segment ⽂件。这个过程是有独⽴的线程来进⾏的,并不影响新 segment 的产⽣。归并过程中,索引状态如图 2-7,尚未完成的较
⼤的 segment 是被排除在检索可见范围之外的:
图 2-7
当归并完成,较⼤的这个 segment 刷到磁盘后,commit ⽂件做出相应变更,删除之前⼏个⼩ segment,改成新的⼤ segment。等检索请求都从⼩ segment 转到⼤ segment 上以后,删除没⽤的⼩ segment。这时候,索引⾥ segment 数量就下降了,状态如图 2-8 所⽰:{ "anslog.durability": "async"}
1
2
3
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论