简介
Elasticsearch 是基于 Lucene 实现的,Lucene 中引入了按段搜寻的概念,每一个段自身就是一个倒排索引。索引在 Lucene 中除示意所有段的汇合外,还减少了提交点(Commit point)的概念,一个列出了所有已知段的文件的形容如下图:一个 Lucene 索引蕴含一个提交点和三个段。
生成
新的文档首先被增加到内存索引缓存中(In-memory buffer)。
Elasticsearch 的主动刷新每隔 1s 进行一次,一个新的段被增加到提交点并清空内存索引缓存。
当一个查问被触发,所有已知的段按程序被查问。词项统计会对所有段的后果进行聚合,以保障每个词和每个文档的关联都被精确计算。
删除 & 更新
段是不可扭转的,所以既不能把文档从旧的段中移除,也不能批改旧的段来对文档进行更新。取而代之的是,每个提交点会蕴含一个 .del 文件,文件中会列出这些被删除文档的段信息。
当一个文档被“删除”时,它实际上只是在 .del 文件中被 标记删除 。一个被标记删除的文档依然能够被查问匹配到,但它会在最终后果被返回前 从后果集中移除。
文档更新也是相似的操作形式:当一个文档被更新时,旧版本文档被标记删除,文档的新版本被索引到一个新的段中。可能两个版本的文档都会被一个查问匹配到,但被删除的那个旧版本文档在后果集返回前就曾经被移除。
合并
主动刷新流程每秒会创立一个新的段,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。每一个段都会耗费文件句柄、内存和 cpu 运行周期。更重要的是,每个搜寻申请都必须轮流查看每个段;所以段越多,搜寻也就越慢。
Elasticsearch 通过在后盾进行段合并来解决这个问题。小的段被合并到大的段,而后这些大的段再被合并到更大的段。
段合并的时候会将那些旧的已删除文档从文件系统中革除。被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中。
启动段合并不须要用户做任何事。进行索引和搜寻时会主动进行。段合并的流程:
- 当索引的时候,刷新(refresh)操作会创立新的段并将段关上以供搜寻应用。
- 合并过程抉择一小部分大小类似的段,在后盾将它们合并到更大的段中且不会中断索引和搜寻。
两个已提交(存在于磁盘上)的段和一个未提交(存在于文件系统缓存中)的段合并到一个更大段,如图形容:
合并实现后,生成的大段(已排除被标记删除的文档)被关上用来搜寻,较小的段被删除,如图形容:
性能优化
段合并的计算量宏大,可能会吃掉大量磁盘 I/O。段合并可能要很长时间能力实现,尤其是比拟大的段,所以合并在 后盾定期操作。个别状况下段合并都不会有什么影响,因为大规模段合并的概率是很小的。
不过有时候合并会连累写入速率。如果这个真的产生了,Elasticsearch 会主动 限度索引申请到单个线程里。单线程能够缩小段文件的生成速度,防止出现数以百计的段在被合并之前就生成进去。如果 Elasticsearch 发现合并连累索引了,它会记录一个申明有 now throttling indexing 的 INFO 级别信息。
Elasticsearch 的默认设置在这块比拟激进:不心愿搜寻性能被后盾合并影响。不过有时候(尤其是 SSD,或者日志场景)限流阈值太低了。
这个限流阈值默认值是 20 MB/s,对机械磁盘应该是个不错的设置。如果应用的是 SSD,能够思考进步到 100–200 MB/s。测试验证对你的零碎哪个值适合:
PUT /_cluster/settings
{
"persistent" : {"indices.store.throttle.max_bytes_per_sec" : "100mb"}
}
如果在做批量导入,齐全不在意搜寻,能够彻底关掉合并限流。这样让索引速度跑到你磁盘容许的极限:
PUT /_cluster/settings
{
"transient" : {"indices.store.throttle.type" : "none"}
}
设置限流类型为 none 彻底敞开合并限流。等实现了导入,须要改回 merge 从新关上限流。
通过批改 index.translog.flush_threshold_size 设置,从默认的 512 MB 到更大一些的值,比方 1 GB。这能够在一次清空触发的时候在事务日志里积攒出更大的段。
这样以来,清空的频率变低,大段合并的频率也变低(生成了更大的段也就意味着缩小了小段合并成大段的频率)。这样会有更少的磁盘 I/O 开销和更好的索引速率。当然,批改这个配置须要对应量级的 heap 内存用以积攒更大的缓冲空间,调整这个设置的时候须要关注这点。
optimize API
强制合并 API。会将一个分片强制合并到 max_num_segments 参数指定大小的段数目。这样做的用意是缩小段的数量(通常缩小到一个),来 晋升搜寻性能。
值得注意的是,optimize API 不应该被用在一个沉闷的索引————一个更新频繁索引。后盾合并流程曾经能够很好地实现工作。optimizing 会妨碍这个过程。
在特定状况下,应用 optimize API 颇有好处。例如在日志这种用例下,每天、每周、每月的日志被存储在一个索引中。老的索引本质上是只读的;它们也并不太可能会发生变化。
在这种状况下,应用 optimize 优化老的索引,将每一个分片合并为一个独自的段就很有用了;这样既能够节俭资源,也能够使搜寻更加疾速:
POST /logstash-2014-10/_optimize?max_num_segments=1
示意合并索引中的每个分片为一个独自的段
最初须要理解下,应用 optimize API 触发段合并的操作 不会受到任何资源上的限度。这可能会消耗掉你节点上全副的 I / O 资源, 使其没有余裕来解决搜寻申请,从而有可能使集群失去响应。
如果想要对索引执行 optimize,最好先应用分片调配把索引移到一个平安的节点,再执行。
参考
https://www.elastic.co/guide/…
https://www.elastic.co/guide/…