ElasticSearch:版本冲突处理(事务控制)

ElasticSearch6.7使用_delete_by_query产生版本冲突(version conflict)问题 环境:ElasticSearch6.7 问题产生的原因: 对某个index的数据进行删除,删除的数据量在千万级别。删除过程中产生版本冲突。 删除脚本如下: POST /ads_lading_trade_brief_es_02/_delete_by_query { "query": { "bool": { "must": [ { "match": { "country": "CR" } }, 阅读详情

处理冲突

当你使用索引API来更新一个文档时,我们先看到了原始文档,然后修改它,最后一次性地将整个新文档进行再次索引处理。Elasticsearch会根据请求发出的顺序来选择出最新的一个文档进行保存。但是,如果在你修改文档的同时其他人也发出了指令,那么他们的修改将会丢失。

很长时间以来,这其实都不是什么大问题。或许我们的主要数据还是存储在一个关系数据库中,而我们只是将为了可以搜索,才将这些数据拷贝到Elasticsearch中。或许发生多个人同时修改一个文件的概率很小,又或者这些偶然的数据丢失并不会影响到我们的正常使用。

但是有些时候如果我们丢失了数据就会出大问题。想象一下,如果我们使用Elasticsearch来存储一个网店的商品数量。每当我们卖出一件,我们就会将这个数量减少一个。

突然有一天,老板决定来个大促销。瞬间,每秒就产生了多笔交易。并行处理,多个进程来处理交易:

无并发控制的后果

web_1库存量的变化丢失的原因是web_2并不知道它所得到的库存量数据是是过期的。这样就会导致我们误认为还有很多货存,最终顾客就会对我们的行为感到失望。

当我们对数据修改得越频繁,或者在读取和更新数据间有越长的空闲时间,我们就越容易丢失掉我们的数据。

以下是两种能避免在并发更新时丢失数据的方法:

悲观并发控制(PCC)

这一点在关系数据库中被广泛使用。假设这种情况很容易发生,我们就可以阻止对这一资源的访问。典型的例子就是当我们在读取一个数据前先锁定这一行,然后确保只有读取到数据的这个线程可以修改这一行数据。

乐观并发控制(OCC)

Elasticsearch所使用的。假设这种情况并不会经常发生,也不会去阻止某一数据的访问。然而,如果基础数据在我们读取和写入的间隔中发生了变化,更新就会失败。这时候就由程序来决定如何处理这个冲突。例如,它可以重新读取新数据来进行更新,又或者它可以将这一情况直接反馈给用户。

乐观并发控制

Elasticsearch是分布式的。当文档被创建、更新或者删除时,新版本的文档就会被复制到集群中的其他节点上。Elasticsearch即是同步的又是异步的,也就是说复制的请求被平行发送出去,然后可能会混乱地到达目的地。这就需要一种方法能够保证新的数据不会被旧数据所覆盖。

我们在上文提到每当有索引put删除的操作时,无论文档有没有变化,它的_version都会增加。Elasticsearch使用_version来确保所有的改变操作都被正确排序。如果一个旧的版本出现在新版本之后,它就会被忽略掉。

我们可以利用_version的优点来确保我们程序修改的数据冲突不会造成数据丢失。我们可以按照我们的想法来指定_version的数字。如果数字错误,请求就是失败。

我们来创建一个新的博文:

PUT /website/blog/1/_create
{
  "title": "My first blog entry",
  "text":  "Just trying this out..."
}

反馈告诉我们这是一个新建的文档,它的_version1。假设我们要编辑它,把这个数据加载到网页表单中,修改完毕然后保存新版本。

首先我们先要得到文档:

GET /website/blog/1

返回结果显示_version1

{
  "_index" :   "website",
  "_type" :    "blog",
  "_id" :      "1",
  "_version" : 1,
  "found" :    true,
  "_source" :  {
      "title": "My first blog entry",
      "text":  "Just trying this out..."
  }
}

现在,我们试着重新索引文档以保存变化,我们这样指定了version的数字:

PUT /website/blog/1?version=1 <1>
{
  "title": "My first blog entry",
  "text":  "Starting to get the hang of this..."
}
  1. 我们只希望当索引中文档的_version1时,更新才生效。

请求成功相应,返回内容告诉我们_version已经变成了2

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "1",
  "_version": 2
  "created":  false
}

然而,当我们再执行同样的索引请求,并依旧指定version=1时,Elasticsearch就会返回一个409 Conflict的响应码,返回内容如下:

{
  "error" : "VersionConflictEngineException[[website][2] [blog][1]:
             version conflict, current [2], provided [1]]",
  "status" : 409
}

这里面指出了文档当前的_version数字是2,而我们要求的数字是1

我们需要做什么取决于我们程序的需求。比如我们可以告知用户已经有其它人修改了这个文档,你应该再保存之前看一下变化。而对于上文提到的库存量问题,我们可能需要重新读取一下最新的文档,然后显示新的数据。

所有的有关于更新或者删除文档的API都支持version这个参数,有了它你就通过修改你的程序来使用乐观并发控制。

使用外部系统的版本

还有一种常见的情况就是我们还是使用其他的数据库来存储数据,而Elasticsearch只是帮我们检索数据。这也就意味着主数据库只要发生的变更,就需要将其拷贝到Elasticsearch中。如果多个进程同时发生,就会产生上文提到的那些并发问题。

如果你的数据库已经存在了版本号码,或者也可以代表版本的时间戳。这是你就可以在Elasticsearch的查询字符串后面添加version_type=external来使用这些号码。版本号码必须要是大于零小于9.2e+18(Java中long的最大正值)的整数。

Elasticsearch在处理外部版本号时会与对内部版本号的处理有些不同。它不再是检查_version是否与请求中指定的数值相同,而是检查当前的_version是否比指定的数值小。如果请求成功,那么外部的版本号就会被存储到文档中的_version中。

外部版本号不仅可以在索引和删除请求时使用,还可以在创建时使用。

例如,创建一篇使用外部版本号为5的博文,我们可以这样操作:

PUT /website/blog/2?version=5&version_type=external
{
  "title": "My first external blog entry",
  "text":  "Starting to get the hang of this..."
}

在返回结果中,我们可以发现_version5

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 5,
  "created":  true
}

现在我们更新这个文档,并指定version10

PUT /website/blog/2?version=10&version_type=external
{
  "title": "My first external blog entry",
  "text":  "This is a piece of cake..."
}

请求被成功执行并且version也变成了10

{
  "_index":   "website",
  "_type":    "blog",
  "_id":      "2",
  "_version": 10,
  "created":  false
}

如果你再次执行这个命令,你会得到之前的错误提示信息,因为你所指定的版本号并没有大于当前Elasticsearch中的版本号。

Elasticsearch并发写入版本冲突解决方案 阅读详情

相关推荐

SAP CO02工单组件批量操作:从BAPI到增强函数的实战解析

本文深入解析SAP CO02工单组件的批量操作技术,对比传统BAPI与增强函数的优劣,提供新增、删除、修改和重读四大操作的实战代码示例。通过性能优化和错误处理技巧,帮助用户高效处理批量工单组件维护,特别适合生产制造领域需要频繁更新BOM的场景。

weixin_30731305的博客 654

Elasticsearch:解决并发写入导致版本冲突异常version_conflict_engine_exception

数据同步中,在使用阿里云Elasticsearch7.10.0版本的集群作为目标数据源时,在连续写入同一文档(document)出现版本冲突问题。

智者千虑,必有一失;愚者千虑,必有一得。 1万+

使用两阶段提交实现 Elasticsearch 中的事务功能

然而,通过使用两阶段提交(Two-Phase Commit,简称 2PC)协议,我们可以在 Elasticsearch 中模拟事务功能。使用以上提供的示例代码,您可以开始在 Elasticsearch 中实现事务功能,并根据需要进行自定义扩展和改进行自定义扩展和改进。然后,将所有需要参与事务的操作(例如索引、更新或删除文档)添加到参与者列表中,并将参与者列表更新到 Elasticsearch 中。在准备阶段,我们首先生成一个唯一的事务 ID,并将其保存到 Elasticsearch 中。

JieLun_C的博客 427

ElasticSearch

ElasticSearch

hnhroot的博客 1567

JdbcTemplate的事务控制

前言 JdbcTemplate是spring-jdbc提供的数据库核心操作类,那对JdbcTemplate进行事务控制呢? 我的环境:spring-boot-2.1.3,druid-1.1.3。 原生Jdbc的事务控制 即,批处理+自动提交的控制方式, public static void demo(String[] args) throws SQLException, ClassNo...

天天向上 2万+

ElasticSearch _bulk 使用与实战:批量操作、查询、冲突(模拟电商下单/查询)

针对如上命令,本例简单的使用 POSTMAN 的 RUNNER 命令,同时开了4个RUNNER,每个 RUNNER 设置循环 500次,按计划最终得到的 counter 应该为 2000, 但是实际的执行结果 counter = 1989,_bulk 的请求体内部分为多行,其中连续的两行数据构成了一次操作,第一行是操作类型可以index,create,update,或者delete,第二行就是我们的可选的数据体。本文所描述的示例,仅是为了对概念进行解释,方便理解,部分示例可能并不完美,特此说明。

alexgaoyihang的专栏 1341

elasticsearch-hadoop 向elasticsearch 导数,丢失数据的问题排查

实际这是很久之前的问题了,当时没时间记录 这里简单回顾 项目基于 数据架构不方便说太细,最精简的 somedata-> [kafka]->spark-stream->elasticsearch 在 spark-streaming 引用了elasticsearch-hadoop(实际用的是为支持upsert doc自已打包的,见elasticsea...

weixin_30702413的博客 393

7个高效Sequel批量操作技巧:让Ruby数据处理速度提升10倍的终极指南

Sequel作为Ruby的强大数据库工具包,提供了丰富的批量数据处理功能,帮助开发者轻松应对大量数据操作场景。本文将分享7个实用技巧,让你在使用Sequel处理批量数据时更加高效、简洁。 ## 1. 使用import方法实现快速批量插入 Sequel的`import`方法是处理批量插入的首选方案,它能够将多条记录一次性插入数据库,大幅减少数据库交互次数。基本语法如下: ```ruby DB[

gitblog_00984的博客 605

《深入浅出MySQL学习笔记-事务控制、锁定语句及分布式事务》

默认情况下,行锁和表锁都是自动获得,不需要额外的命令,但有些情况用户需要明确的进行锁表或者事务控制,以保证整个事务完整性。 引擎 锁 特点 MyISAM、MEMORY 表级锁 开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 BDB 页级锁定 开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 InnoDB 行级锁定 ...

HuYingJie_1995的博客 332

PyMySQL并发事务终极指南:5种方法彻底解决数据库锁冲突

PyMySQL作为Python开发者首选的MySQL数据库连接库,在处理高并发场景时经常面临事务冲突和锁竞争问题。本文将系统介绍使用PyMySQL处理并发事务的核心技术,帮助开发者彻底解决数据库锁冲突难题,提升应用性能与稳定性。 ## 一、理解PyMySQL事务基础 PyMySQL通过`Connection`对象提供完整的事务管理功能。在[`pymysql/connections.py`](h

gitblog_01103的博客 1038

TiKV 源码解析系列文章(十一)Storage - 事务控制

作者:张金鹏 背景知识 TiKV 是一个强一致的支持事务的分布式 KV 存储。TiKV 通过 raft 来保证多副本之间的强一致,事务这块 TiKV 参考了 Google 的 Percolator 事务模型,并进行了一些优化。 当 TiKV 的 Service 层收到请求之后,会根据请求的类型...

chigangdou7652的博客 511

《Kingbase护城河》——深度解密数据库行锁冲突与等待事件架构

今天,我们就用金仓数据库里面那些现成的内部监控视图,还有诊断函数,带你在那一堆并发连接里面,把那个拿着锁不撒手的家伙给揪出来

倔强的石头的博客 1万+

解决分布式存储并发难题:MinIO锁机制与事务全解析

你是否在分布式环境中遇到过文件覆盖冲突?是否因并发写入导致数据一致性问题?本文将深入解析MinIO如何通过精妙的锁机制与事务控制,保障海量对象存储的并发安全。读完本文你将掌握: - MinIO两种锁机制的工作原理 - 分布式环境下的锁冲突解决方案 - 事务控制在对象存储中的实践方式 - 性能优化配置与最佳实践 ## 锁机制:并发控制的核心防线 MinIO通过分层锁机制实现细粒度的并发控制,从本...

gitblog_00119的博客 875

Java全栈面试实录:从Spring Boot到AI大模型,互联网大厂求职者的技术洗礼

Elasticsearch啊,就是索引数据,然后用RestHighLevelClient发搜索请求……:Kafka啊,就是生产者发消息到Topic,消费者用Spring Kafka监听……:WebSocket,Spring WebSocketHandler……:Spark SQL读取HDFS数据,然后用DataFrame计算……:OpenAI API,Spring RestTemplate调用……:docker-compose build,然后启动……:Flink啊,就是DataStream API……

m0_75125940的博客 747

auto-novel并发控制:Kotlin协程与MongoDB事务处理实践

在轻小说机翻网站auto-novel的开发过程中,并发控制是确保系统稳定性和数据一致性的关键环节。本文将详细介绍项目如何利用Kotlin协程实现高效的异步处理,以及结合MongoDB事务保证数据操作的原子性,解决多用户同时操作带来的数据冲突问题。 ## 技术栈概览 auto-novel后端基于Kotlin构建,采用分层架构设计,主要涉及以下核心技术组件: - **异步处理**:Kotlin协...

gitblog_00126的博客 283
上一篇: ElasticSearch:从[FIELDDATA]Data too large错误看FieldData配置
下一篇: Nginx自定义模块编写:根据post参数路由到不同服务器
昕玫
博客等级 码龄15年 286粉丝 105原创
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值