Elasticsearch 读写原理

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

持久化变更 | Elasticsearch: 权威指南 | Elastic

段合并 | Elasticsearch: 权威指南 | Elastic

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
elasticsearch 简单介绍 在分布式系统中,单机无法存储规模巨大的数据,水平扩容增加机器来提高扩展能力,因此,需要把数据分成若干小块分配到各个机器上,然后通过某种策略找到某个数据块所在的位置 在分布式系统中,会把数据复制成多个副本,放置到不同的机器中,增加系统的可用性,同时数据副本还可以使度操作并发执行,分担集群压力。但多副本带来的问题是数据一致性 ES 将数据副本分成主从两份,主分片和副分片,恢复阶段以主分片为准 分片是底层的基本读写单元,分片的目的是分割巨大索引,让读写可以并行操作,分片是数据的容器,文档保存在分片内,不会跨分片存储。分片又被分配到集群内的各个节点里。当集群规模扩大或缩小时,ES 会自动在各节点中迁移分片,使数据仍然均匀分布在集群 一个 ES 索引包含很多分片,一个分片是一个 Lucene 的索引,它本生就是一个完整的搜索引擎,可以独立执行建立索引和搜索任务。Lucene 索引又由很多分段组成,每个分段都是一个倒排索引。ES 每次 “refresh” 都会生成一个新的分段,其中包含若干文档的数据。在每个分段内部,文档的不同字段被单独建立索引。每个字段的值由若干词(Term)组成,Term 是原文本内容经过分词器处理和语言处理后的最终结果(例如,去除标点符号和转换为词根)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值