分析测试百科网

搜索

喜欢作者

微信支付微信支付
×

Elasticsearch性能优化指南(三)

2020.9.28
头像

王辉

致力于为分析测试行业奉献终身

es 第一是准实时的,数据写入 1 秒后可以搜索到;可能会丢失数据的。有 5 秒的数据,停留在 buffer、translog os cache、segment file os cache 中,而不在磁盘上,此时如果宕机,会导致 5 秒的数据丢失。

总结一下,数据先写入内存 buffer,然后每隔 1s,将数据 refresh 到 os cache,到了 os cache 数据就能被搜索到(所以我们才说 es 从写入到能被搜索到,中间有 1s 的延迟)。每隔 5s,将数据写入 translog 文件(这样如果机器宕机,内存数据全没,最多会有 5s 的数据丢失),translog 大到一定程度,或者默认每隔 30mins,会触发 commit 操作,将缓冲区的数据都 flush 到 segment file 磁盘文件中。

数据写入 segment file 之后,同时就建立好了倒排索引。

一个segment是一个完备的lucene倒排索引,而倒排索引是通过词典 (Term Dictionary)到文档列表(Postings List)的映射关系,快速做查询的。由于词典的size会很大,全部装载到heap里不现实,因此Lucene为词典做了一层前缀索引(Term Index),这个索引在Lucene4.0以后采用的数据结构是FST (Finite State Transducer)。这种数据结构占用空间很小,Lucene打开索引的时候将其全量装载到内存中,加快磁盘上词典查询速度的同时减少随机磁盘访问次数。

每个segment都有会一些索引数据驻留在heap里。因此segment越多,瓜分掉的heap也越多,并且这部分heap是无法被GC掉的

删除/更新数据底层原理

如果是删除操作,commit 的时候会生成一个 .del 文件,里面将某个 doc 标识为 deleted 状态,那么搜索的时候根据 .del 文件就知道这个 doc 是否被删除了。

如果是更新操作,就是将原来的 doc 标识为 deleted 状态,然后新写入一条数据。

buffer 每 refresh 一次,就会产生一 个 segment file ,所以默认情况下是 1 秒钟一个 segment file ,这样下来 segment file 会越来越多,此时会定期执行 merge。每次 merge 的时候,会将多个 segment file 合并成一个,同时这里会将标识为 deleted 的 doc 给物理删除掉,然后将新的 segment file 写入磁盘,这里会写一个 commit point ,标识所有新的 segment file ,然后打开 segment file 供搜索使用,同时删除旧的 segment file 。

通用建议

不要返回大结果集

Elasticsearch被设计为搜索引擎,使其非常适合检索与查询匹配的最前面的文档。但是,对于属于数据库域的工作负载(如检索匹配特定查询的所有文档),效果不佳。如果需要执行此操作,请确保使用Scroll API。

避免大文档

假设默认的http.max_content_length设置为100MB,Elasticsearch将拒绝索引任何大于此值的文档。您可能决定增加该特定设置,但是Lucene仍然有大约2GB的限制。

即使不考虑硬性限制,大型文档通常也不实用。大型文档给网络,内存使用和磁盘带来了更大的压力,即使对于不要求_source的搜索请求也是如此,因为Elasticsearch在所有情况下都需要获取文档的_id,并且由于 文件系统缓存的工作方式,大型文档获取此字段的成本更高。索引此文档使用的内存量是该文档原始大小的数倍。近似搜索(例如phrase查询)和高亮显示开销也变得更加昂贵,因为它们的成本直接取决于原始文档的大小。

重新考虑信息单位有时是有用的。例如,您想使书籍可搜索,并不一定意味着文档应包含整本书。最好将章节或段落用作文档,这些文档中具有一个属性,以标识它们属于哪本书。这不仅避免了大文档的问题,还使搜索体验更好。例如,如果用户搜索foo和bar这两个词,则匹配的结果跨不同章节可能体验非常差,而匹配结果落入同一段落中就可能很不错。


互联网
文章推荐