目录
Elasticsearch本身是分布式搜索引擎。它的高可用、高性能就是通过分片
实现的。
每个文档都有唯一的文档ID,一个文档经过分析器变成一组词条。
倒排索引:记录词条以及词条出现的文档ID的数据结构,同时倒排索引还会记录词条在文档中出现的频率。
示例引用自《Elasticsearch实战》。
在文档加入倒排索引之前,需要经过分析器执行分析,转换成一组词条(Term)。
以下是文档“share your experience with Nosql & big data technologies”的分析过程。
&
转换成and
保存文档是写入主分片,然后,同步到副本分片;搜索文档是根据轮询算法,从主分片或副本分片读取。
文档ID
的哈希值,决定文档的目标分片。如果文档的目标分片不在当前节点,将文档转发到目标分片的节点。说明:
协调节点使用round-robin随机循环算法,将请求转发到包含完整数据集合的分片集合(包括主分片和副本分片)。
协调节点收集各节点的返回结果,将结果返回客户端:
2.1 查询阶段(Query Phase):每个分片将自己的搜索结果的文档ID
返回给协调节点,协调节点进行数据的合并、排序、分页,得到最终结果。
2.2 拉取阶段(Fetch Phase):协调节点根据文档ID
取各个节点上拉取文档数据,最终返回给客户端。
Elasticsearch会将数据先写入内存的缓冲区,这时数据并不能用于查询。
数据刷新负责将缓冲区的数据写入段文件。段文件实际上就Lucene索引。出于性能考虑,数据并不是直接写入磁盘的,而是默认每隔1秒,数据从缓冲区写入系统缓存(OS Cache),变成段文件。之后,就可以通过搜索接口查询到对应的数据了。因为,数据都是在内存中的,所以一旦宕机,数据会丢失。ES通过事务日志保存了数据,所以,能够保证数据的恢复。
ES是接近实时的(Near Real-time)
因为,数据是每1秒刷新的系统缓存,之后才可以访问,所以是接近实时的。
为了防止数据丢失,数据在写入缓冲区的同时写入事务日志文件。事务日志同样是先写入系统缓存(OS Cache),然后刷新到磁盘。
index.translog.durability
参数- 刷盘策略
index.translog.durability
取值:
数据丢失
因为事务日志的默认刷盘方式是每隔5秒fsync一次,所以如果ES宕机,最多可能丢失5秒的数据。
ES中的索引数据会持久化到磁盘中,查询的时候,索引数据从磁盘加载到系统缓存中。
这里的filesystem cache就是上文的OS cache,都是指系统缓存。
ES搜索性能非常依赖于系统缓存,因为系统缓存是在内存中的。如果查询走系统缓存,可以达到几毫秒到几百毫秒不等的查询效率;但是,查询走磁盘的话,搜索性能就要达到秒级。
最佳的情况下,机器的内存要达到容纳总数据量的一半。
ES + HBase
为了减少ES的数据量,可以仅在ES索引中保存用于检索的几个字段,将完整的记录保存在HBase中。查询时,先通过ES获取doc id
,然后,根据doc id
到HBase获取完整的数据。
开启定时任务,定时加载一些频繁被访问的热点数据。如:电商系统中,如iphone,后台开个任务,每隔1分钟访问一次相关数据,刷新到系统缓存中。
ES尽量不要使用复杂的操作,如:join(关联)/nested/parent-child,对性能影响很大。
可以在Java应用里完成关联,将关联好的数据写入ES中。
如果要取第100页的10条数据,那么ES的分页流程如下:
所以,ES的分页越深,查询越慢。
有两种优化方案:
部分图片引用自:advanced-Java