Elasticsearch 介绍
Elasticsearch 是一个开源的搜索引擎,建立在一个全文搜索引擎库 Apache Lucene™ 基础之上。 Lucene 可以说是当下最先进、高性能、全功能的搜索引擎库—无论是开源还是私有。
但是 Lucene 仅仅只是一个库。为了充分发挥其功能,你需要使用 Java 并将 Lucene 直接集成到应用程序中。 更糟糕的是,您可能需要获得信息检索学位才能了解其工作原理。Lucene 非常复杂。
Elasticsearch 也是使用 Java 编写的,它的内部使用 Lucene 做索引与搜索,但是它的目的是使全文检索变得简单, 通过隐藏 Lucene 的复杂性,取而代之的提供一套简单一致的 RESTful API。
然而,Elasticsearch 不仅仅是 Lucene,并且也不仅仅只是一个全文搜索引擎。 它可以被下面这样准确的形容:
一个分布式的实时文档存储,每个字段可以被索引与搜索
一个分布式实时分析搜索引擎
能胜任上百个服务节点的扩展,并支持 PB 级别的结构化或者非结构化数据
写入数据流程
1、选择集群中的一个节点发送写入请求,接收到请求节点被称为协调节点 (coordinating node)
2、通过公式计算出处理写入请求的primary shard node
公式:shard = hash(routing) % number_of_primary_shards
routing
是一个可变值,默认是文档的_id
,也可以设置成一个自定义的值
3、主分片节点 primary shard node 处理写入成功后,将请求并行转发到所有的副本分片节点 replica shard node。
执行写操作之前,主分片会要求必须要有规定数量的分片副本处于活跃状态,才会允许执行写操作。
consistency 一致性
one:既只要主分片状态ok就允许执行写操作 (默认)
quorum:大多数分片副本状态没有问题才允许执行写操作 int( (primary + number_of_replicas) / 2 ) + 1
all:必须要所有的副本状态都没有问题才允许执行写操作
timeout
如果没有足够的副本分片,Elasticsearch会等待,希望有更多的分片出现。默认等待1分钟。
4、当所有的 replica shard 写入成功了,primary shard node 返回协调节点成功
如果某个replica shard执⾏失败,则primary shard会给master发请求remove该replica shard
写入阶段
此阶段写入数据分别在内存缓存区(memory buffer) 和 translog (事务日志)。此时文档搜索不到,也还没有构建倒排索引。
translog 用来保证数据可靠性,类似 MySQL 的 redolog 机制,以key value的形式进行存储,key = document_id,value = document。 默认是异步刷盘,每5秒进行一次刷盘。如果发生机房断电,会有5秒的数据丢失。如果希望数据不丢失,可配置为同步刷盘
Elasticsearch 的文档是不可变更的,所以执行 update 操作,实际的操作是检索-修改-重建索引的处理,这个过程发生在分片内部,可以避免多次请求的网络开销。Elasticsearch 可以部分更新,其原理是内部查询出现有的文档并进行合并生成新的文档
Update 操作会将旧文档标记为已删除,增加一个新的文档。尽管不能再对旧版本的文档进行访问,但它并不会立即消失。在merge阶段会进行清理
refresh 阶段
默认每隔1s 将内存缓存区(memory buffer)的文档刷新到文件系统缓存(filesystem cache) 新的段(segment) 中,清空内存缓存区。倒排索引在这个阶段生成的,经过这个阶段文档可以被搜索到了
# 在生产环境中,要建立一个大的新索引时,可以先关闭自动刷新,
# 待开始使用该索引时,再把它们调回来
PUT /my_logs/_settings
{ "refresh_interval": -1 }
PUT /my_logs/_settings
{ "refresh_interval": "1s" }
# 大量的索引新增场景(新索引构建, 全量同步数据),但是又不需要近实时搜索
# 可以设置refresh_interval 降低每个索引的刷新频率来提高搜索性能
PUT /my_logs
{
"settings": {
"refresh_interval": "30s"
}
}
merge 阶段
由于refresh阶段每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。 每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢
Elasticsearch通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。
段合并的时候会将那些旧的已删除文档从文件系统中清除。被删除的文档(或被更新文档的旧版本)不会被拷贝到新的大段中
index.merge.policy.max_merge_at_once:合并时一次允许的最大段数量,默认 10
index.merge.policy.max_merged_segment:合并的段的总大小不能超过这个值,默认 5G
index.merge.policy.floor_segment:小于这个大小的segment,优先被归并。默认值为2m
segments_per_tier:每层允许的段数量大小,默认值是10
indices.store.throttle.max_bytes_per_sec:控制合并的速率,防止段爆炸问题,影响搜索性能。默认值是 20 MB/s,对机械磁盘应该是个不错的设置。如果你用的是 SSD,可以考虑提高到 100–200 MB/s。批量导入完全不在意搜索的情况下,可以彻底关掉合并限流
PUT /_cluster/settings { "transient" : { "indices.store.throttle.type" : "none" } }
index.merge.scheduler.max_thread_count:默认线程数
Math.min(3, Runtime.getRuntime().availableProcessors() / 2)
,机械磁盘在并发 I/O 支持方面比较差,所以需要降低每个索引并发访问磁盘的线程数
flush 阶段
触发时机
index.translog.flush_threshold_period:无论 translog 大小如何,在触发刷新之前等待多长时间。默认为
30m
.index.translog.flush_threshold_size: translog 达到这个大小,就会发生触发 flush 操作。默认为
512mb
.
执行操作
创建新的translog
所有在内存缓存区的文档都被写入一个新的段(segment)
清空内存缓冲区
写入提交点(commit point)到磁盘
调用 fsync 将文件系统缓存(filesystem cache)刷到磁盘 (segment 落盘)
删除旧的translog
translog 也被用来提供实时 CRUD 。通过ID查询、更新、删除一个文档,它会在尝试从相应的段中检索之前, 首先检查 translog 任何最近的变更。这意味着它总是能够实时地获取到文档的最新版本
查询数据流程
选择集群中的一个节点发送写入请求,接收到请求节点被称为协调节点 (coordinating node)
query 阶段
查询会广播到索引中每一个分片上(主分片或者副本分片)。 每个分片在本地执行搜索并构建一个匹配文档的优先队列
优先队列仅仅是一个存有 top-n 匹配文档的有序列表。优先队列的大小取决于分页参数 from 和 size
具体执行如下:
1、协调节点接受到请求,在本地创建一个大小为
from + size
的空优先队列
2、协调节点将查询转发到索引的每个主分片或副本分片中。每个分片在本地执行查询并添加结果到大小为from + size
的本地有序优先队列中
3、每个分片返回各自优先队列中所有文档的 ID 和排序值给协调节点,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列
fetch 阶段
协调节点确认哪些文档需要取回,例如,如果我们的查询指定了 { "from": 90, "size": 10 }
,最初的90个结果会被丢弃,只有从第91个开始的10个结果需要被取回
协调节点给持有相关文档的每个分片创建一个 multi-get request ,并发送请求给同样处理查询阶段的分片副本
一旦协调节点接收到所有的结果文档,就会组装这些结果为单个响应返回给客户端
查询优化
如果业务可以根据路由查询,那么可以设置routing 进行优化,避免索引的所有分片参与搜索
bouncing results 问题,每次用户刷新页面,搜索结果表现是不同的顺序,查询中设置preference 参数,让同一个用户始终用同一个分片
使用source参数,返回需要的字段值
如果有深度分页的场景,使用scroll或者search_after
官方文档
查询相关
查询阶段 | Elasticsearch: 权威指南 | Elastic
取回阶段 | Elasticsearch: 权威指南 | Elastic
搜索选项 | Elasticsearch: 权威指南 | Elastic
游标查询 Scroll | Elasticsearch: 权威指南 | Elastic
写入相关
路由一个文档到一个分片中 | Elasticsearch: 权威指南 | Elastic
动态更新索引 | Elasticsearch: 权威指南 | Elastic
近实时搜索 | Elasticsearch: 权威指南 | Elastic