ES写入过程和写入原理调优及如何保证数据的写一致性(上)

本文涉及的产品
检索分析服务 Elasticsearch 版,2核4GB开发者规格 1个月
日志服务 SLS,月写入数据量 50GB 1个月
简介: ES写入过程和写入原理调优及如何保证数据的写一致性

1、ES 的写入过程

1.1 ES支持四种对文档的数据写操作

  • create:如果在PUT数据的时候当前数据已经存在,则数据会被覆盖,如果在PUT的时候加上操作类型create,此时如果数据已存在则会返回失败,因为已经强制指定了操作类型为create,ES就不会再去执行update操作。比如:PUT /pruduct/_create/1/ ( 老版本的语法为 PUT /pruduct/_doc/1/_create )指的就是在索引product中强制创建id为1的数据,如果id为1的数据已存在,则返回失败。
  • delete:删除文档,ES对文档的删除是懒删除机制,即标记删除。
  • index:在ES中,写入操作被称为Index,这里Index为动词,即索引数据为将数据创建在ES中的索引,后面章节中均称之为“索引数据”。


1.2 写流程

ES中的数据写入均发生在Primary Shard,当数据在Primary写入完成之后会同步到相应的Replica Shard。下图演示了单条数据写入ES的流程:

b1e3e6256172f9a1f1d02a8512fa1ac3.png

以下为数据写入的步骤:


  1. 客户端发起写入请求至node 4
  2. node 4通过文档 id 在路由表中的映射信息确定当前数据的位置为分片0,分片0的主分片位于node 5,并将数据转发至node 5。
  3. 数据在node 5写入,写入成功之后将数据的同步请求转发至其副本所在的node 4和node 6上面,等待所有副本(具体等待多少副本取决于wait_for_active_shards的配置值)数据写入成功之后node 5 将结果报告node 4,并由 node 4 将结果返回给客户端,报告数据写入成功。


在这个过程中,接收用户请求的节点是不固定的,上述例子中,node 4 发挥了协调节点和客户端节点的作用,将数据转发至对应节点和接收以及返回用户请求。


数据在由 node4 转发至 node5的时候,是通过以下公式来计算,指定的文档具体在那个分片的

微信截图_20221118084623.png其中,_routing 的默认值是文档的 id。


1.3 写一致性策略

ES 5.x 之后,一致性策略由 wait_for_active_shards 参数控制:

即确定客户端返回数据之前必须处于active 的分片分片数(包括主分片和副本),默认为 wait_for_active_shards = 1,即只需要主分片写入成功,设置为 all或任何正整数,最大值为索引中的分片总数 ( number_of_replicas + 1 )。如果当前 active 状态的副本没有达到设定阈值,写操作必须等待并且重试,默认等待时间30秒,直到 active 状态的副本数量超过设定的阈值或者超时返回失败为止。


执行索引操作时,分配给执行索引操作的主分片可能不可用。造成这种情况的原因可能是主分片当前正在从网关恢复或正在进行重定位。默认情况下,索引操作将在主分片上等待最多 1 分钟,然后才会失败并返回错误。


2、ES 的写入原理

2.1 图解文档的写入原理

054793f47bf24f30914cbbb676ed4449.png


2.2 Translog

对索引的修改操作在会 Lucene 执行 commit 之后真正持久化到磁盘,这个过程是非常消耗资源的,因此不可能在每次索引操作或删除操作后执行。Lucene 提交的成本太高,无法对每个单独的更改执行,因此每个分片副本还将操作写入其 事务日志,也就是 translog 。所有索引和删除操作在被内部 Lucene 索引处理之后但在它们被确认之前写入到 translog。如果发生崩溃,当分片恢复时,已确认但尚未包含在最后一次 Lucene 提交中的最近操作将从 translog 中恢复。


Elasticsearch Flush 是Lucene 执行 commit 并开始写入新的 translog 的过程。刷新是在后台自动执行的,以确保 translog 不会变得太大,这将导致在恢复期间重放其操作需要相当长的时间。手动执行刷新的能力也通过 API 公开,但是一般并不需要。


translog 中的数据仅在 translog 被执行 fsync 和 commit 时才会持久化到磁盘。如果发生硬件故障或操作系统崩溃或 JVM 崩溃或分片故障,自上次 translog 提交以来写入的任何数据都将丢失。


默认情况下,index.translog.durability设置为意味着 Elasticsearch 仅在 translog在主分片和每个副本上 request 成功编辑并提交后,才会向客户端报告索引、删除、更新或批量请求的成功。fsync 如果 index.translog.durability 设置为 async then Elasticsearch fsync并仅提交 translog index.translog.sync_interval,这意味着当节点恢复时,在崩溃之前执行的任何操作都可能丢失。


以下可动态更新的每个索引设置控制 translog 的行为:


index.translog.sync_interval


无论写入操作如何,translog 默认每隔 5s 被 fsync 写入磁盘并 commit 一次,不允许设置小于 100ms 的提交间隔。


index.translog.durability


是否 fsync在每次索引、删除、更新或批量请求后提交事务日志。此设置接受以下参数:


request(默认):fsync并在每次请求后提交。如果发生硬件故障,所有确认的写入都已经提交到磁盘。

async:fsync 并在后台提交每个 sync_interval`. 如果发生故障,自上次自动提交以来所有确认的写入都将被丢弃。

index.translog.flush_threshold_size


translog 存储所有尚未安全保存在 Lucene 中的操作(即,不是 Lucene 提交点的一部分)。尽管这些操作可用于读取,但如果分片停止并必须恢复,则需要重播它们。此设置控制这些操作的最大总大小,以防止恢复时间过长。一旦达到最大大小,就会发生刷新,生成一个新的 Lucene 提交点。默认为 512mb.


2.3 Refresh

2.3.1 概念和原理

内存索引缓冲区(图 1)中的文档被写入新段(图 2)。新段首先写入文件系统缓存(这个过程性能消耗很低),然后才刷新到磁盘(这个过程则代价很低)。但是,在文件进入缓存后,它可以像任何其他文件一样打开和读取。

74db9a3910cc429cafd1ad8b750abcd6.png


Lucene 允许写入和打开新的段,使它们包含的文档对搜索可见,而无需执行完整的提交。这是一个比提交到磁盘更轻松的过程,并且可以经常执行而不会降低性能。

a37b82fae94b4ec79f2f3e5672da350b.png

在 Elasticsearch 中,这个写入和打开新段的过程称为 刷新 。刷新使自上次刷新以来对索引执行的所有操作都可用于搜索。


2.3.2 设置刷新间隔

index.refresh_interval:多久执行一次刷新操作,这使得对索引的最近更改对搜索可见。默认为 1s. 可以设置 -1 为禁用刷新。


并不是所有的情况都需要每秒刷新。比如 Elasticsearch 索引大量的日志文件,此时并不需要太高的写入实时性, 可以通过设置 refresh_interval ,增大刷新间隔来降低每个索引的刷新频率,从而降低因为实时性而带来的性能开销。进而提升检索效率。

POST <index_name>
{
  "settings": {
    "refresh_interval": "30s"
  }
}


2.3.3 强制对索引刷新

POST <target>/_refresh
GET <target>/_refresh
POST /_refresh
GET /_refresh


2.4 Flush

刷新数据流或索引是确保当前仅存储在 Traslog 中的任何数据也永久存储在 Lucene 索引中的过程。重新启动时,Elasticsearch 会将所有未刷新的操作从事务日志重播到 Lucene 索引,以使其恢复到重新启动前的状态。Elasticsearch 会根据需要自动触发刷新,使用启发式算法来权衡未刷新事务日志的大小与执行每次刷新的成本。


一旦每个操作被刷新,它就会永久存储在 Lucene 索引中。这可能意味着不需要在事务日志中维护它的额外副本。事务日志由多个文件组成,称为 generation ,一旦不再需要,Elasticsearch 将删除任何生成文件,从而释放磁盘空间。


也可以使用刷新 API 触发一个或多个索引的刷新,尽管用户很少需要直接调用此 API。如果您在索引某些文档后调用刷新 API,则成功响应表明 Elasticsearch 已刷新在调用刷新 API 之前索引的所有文档。


2.5 Merge

由于自动刷新流程每秒会创建一个新的段 ,这样会导致短时间内的段数量暴增。而段数目太多会带来较大的麻烦。 每一个段都会消耗文件句柄、内存和cpu运行周期。更重要的是,每个搜索请求都必须轮流检查每个段;所以段越多,搜索也就越慢。


Elasticsearch通过在后台进行段合并来解决这个问题。小的段被合并到大的段,然后这些大的段再被合并到更大的段。

db6f11f6b1504cc09bdab04983d77580.png


Elasticsearch 中的一个 shard 是一个 Lucene 索引,一个 Lucene 索引被分解成段。段是存储索引数据的索引中的内部存储元素,并且是不可变的。较小的段会定期合并到较大的段中,并删除较小的段

1a98ef5c54f64062a89e0ff77c2154c4.png


合并大的段需要消耗大量的I/O和CPU资源,如果任其发展会影响搜索性能。Elasticsearch在默认情况下会对合并流程进行资源限制,所以搜索仍然 有足够的资源很好地执行。

相关实践学习
使用阿里云Elasticsearch体验信息检索加速
通过创建登录阿里云Elasticsearch集群,使用DataWorks将MySQL数据同步至Elasticsearch,体验多条件检索效果,简单展示数据同步和信息检索加速的过程和操作。
ElasticSearch 入门精讲
ElasticSearch是一个开源的、基于Lucene的、分布式、高扩展、高实时的搜索与数据分析引擎。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr(也是基于Lucene)。 ElasticSearch的实现原理主要分为以下几个步骤: 用户将数据提交到Elastic Search 数据库中 通过分词控制器去将对应的语句分词,将其权重和分词结果一并存入数据 当用户搜索数据时候,再根据权重将结果排名、打分 将返回结果呈现给用户 Elasticsearch可以用于搜索各种文档。它提供可扩展的搜索,具有接近实时的搜索,并支持多租户。
相关文章
|
4月前
|
供应链 负载均衡 数据库
软件架构一致性问题之分析代码修改的 Scalability如何解决
软件架构一致性问题之分析代码修改的 Scalability如何解决
54 1
|
6月前
|
缓存 负载均衡 算法
C++如何实现一致性算法
一致性哈希是一种用于分布式系统的负载均衡算法,旨在减少服务器增减导致的数据迁移。当有N台服务器时,通过哈希环将请求均匀分布到每台服务器,每台处理N/1的请求。若使用缓存如Redis,可进一步处理高并发场景。算法将哈希值空间视为环形,服务器和请求哈希后定位到环上,按顺时针方向找到第一台服务器作为负载目标。提供的C++代码实现了MD5哈希函数,以及一致性哈希算法的物理节点、虚拟节点和算法本身,以实现节点的添加、删除和请求映射。
47 1
C++如何实现一致性算法
|
4月前
|
消息中间件 算法
分布式篇问题之“最终一致性”问题如何解决
分布式篇问题之“最终一致性”问题如何解决
|
4月前
|
消息中间件
分布式篇问题之通过本地消息表实现分布式事务的最终一致性问题如何解决
分布式篇问题之通过本地消息表实现分布式事务的最终一致性问题如何解决
185 0
|
4月前
|
存储 缓存 NoSQL
架构设计篇问题之在数据割接过程中,多线程处理会导致数据错乱和重复问题如何解决
架构设计篇问题之在数据割接过程中,多线程处理会导致数据错乱和重复问题如何解决
|
4月前
|
设计模式 安全 Java
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
Java面试题:如何实现一个线程安全的单例模式,并确保其在高并发环境下的内存管理效率?如何使用CyclicBarrier来实现一个多阶段的数据处理任务,确保所有阶段的数据一致性?
62 0
|
5月前
|
canal 缓存 关系型数据库
高并发场景下,6种方案,保证缓存和数据库的最终一致性!
在解决缓存一致性的过程中,有多种途径可以保证缓存的最终一致性,应该根据场景来设计合适的方案,读多写少的场景下,可以选择采用“Cache-Aside结合消费数据库日志做补偿”的方案,写多的场景下,可以选择采用“Write-Through结合分布式锁”的方案,写多的极端场景下,可以选择采用“Write-Behind”的方案。
1273 0
|
6月前
|
监控 NoSQL Redis
RedisShake如何处理数据同步过程中的冲突和一致性问题
RedisShake保障数据同步一致性,支持全量和增量同步,处理并发冲突(利用乐观锁机制),并进行数据校验。遇到故障能自动恢复和重试,保证不间断同步。同时,提供监控和日志功能,便于识别和解决问题,确保数据完整性。
223 0
|
6月前
|
SQL 安全 算法
在高并发情况下,如何做到安全的修改同一行数据?
在高并发情况下,如何做到安全的修改同一行数据?
|
6月前
|
存储 分布式计算 数据管理
HDFS中的数据一致性是如何保证的?请解释数据一致性的概念和实现方式。
HDFS中的数据一致性是如何保证的?请解释数据一致性的概念和实现方式。
253 0