Elasticsearch由浅入深(四)ES并发冲突、悲观锁与乐观锁、_version乐观锁并发
ES并发冲突
举个例子,比如是电商场景下,假设说,我们有个程序,工作的流程是这样子的:
- 读取商品信息(包含了商品库存)
- 用户下单购买
- 更新商品信息(主要是将库存减1)
我们比如咱们的程序就是多线程的,所以可能有多个线程并发的去执行上述的3步骤流程
有一个牙膏,库存100件,现在,同时有两个人都过来读取了牙育的数据,然后下单购买了这管牙膏,此时两个线程并发的服务于两个人,同时在进行商品库存数据的修改
总有一个线程是先到的,假设就是线程A ,此时线程A就会先将牙育的库存设置为99件,然后线程B再次将牙育的库存设置为99件,此时结果就已经错了
正确的情况下,我们期望的,应该是说,线程A将库存-1,设置为99件;然后线程B接着这个99件,将库存-1,变为98件,然后设置到ES中。最终ES中应该库存是98件才对啊.
普通的ES操作流程:
- 先get document数据,商品信息,显示到网页上,同时在内存中缓存该document的数据
- 当网页发生了购买之后,直接基于内存中的数据,进行计算和操作
- 将计算后的结果写回ES中
上面说的这个流程和过程,其实就是ES中的并发冲突问题,会导致数据不准确:
- 有些场景下,其实是无所谓的,不care这个数据不正确的事情,比如说,我们如果就只是简单的将数据写入ES ,无论数据是什么样的,都可以;还有些情况下,即使是算错了,也可以
- 当并发操作ES的线程越多,或者并发请求越多;或者是读取一份数据,供用户查阅和操作的时间越长,因为这段时间里很可能数据在ES中已经被修改了,那么我们拿到的就是旧数据,基于 1旧数据去操作,后面结果肯定就错了
悲观锁与乐观锁
优缺点:
- 悲观锁
优点:方便,直接加锁,对应用程序来说,透明,不需要做额外的操作;
缺点:并发能力很低,同一时间只能有一条线程操作数据, - 乐观锁
优点:并发能力很高,不给数据加锁,大量线程并发操作;
缺点:麻烦,每次更新的时候,都要先比对版本号,然后可能需要重新加载数据,再次修改,再写;这个过程,可能要重复好几次
悲观锁并发控制机制
悲观锁并发控制方案,就是在各种情况下,都上锁。上锁之后,就只有一个线程可以操作这一条数据了,当然,不同的场景下,上的敏不同,行级锁,表级锁,读锁,写锁。
乐观锁并发控制机制
乐观锁是不加锁的, ,每个线程都可以任意操作
线程B去判断,当前数据的版本号,version=1,与es中的数据的版本号, version=2,是否相同?明显是不同的。版本号不同,说明数据已经被其他人修改过了。此时用户B不会用99去更新。而是重新去es中读取最新的数据版本,99件,再次减 1,变为98件,再执行上述流程,就可以写入
基于_version进行乐观锁并发控制
示例数据:
PUT /test_index/test_type/
{
"test_field": "test test"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "",
"_version": 1,
"result": "created",
"_shards": {
"total": ,
"successful": ,
"failed":
},
"created": true
}
第一次创建一个document的时候,它的_version内部版本号就是1;以后,每次对这个document执行修改或者删除操作,都会对这个_version版本号自动加1;哪怕是删除,也会对这条数据的版本号加1
{
"found": true,
"_index": "test_index",
"_type": "test_type",
"_id": "",
"_version": ,
"result": "deleted",
"_shards": {
"total": ,
"successful": ,
"failed":
}
}
我们会发现,在删除一个document之后,可以从一个侧面证明,它不是立即物理删除掉的,因为它的一些版本号等信息还是保留着的。先删除一条document,再重新创建这条document,其实会在delete version基础之上,再把version号加1
ES后台同步:知识点: es的后台,很多的这种类似于replica同步请求,都是多线程异步的,也就是说,多个修改请求之间,是乱序的,没有顺序的,可能后修改的先到,先修改的后到
假设es内部没有乐观锁并发控制机制:
- 后修改的先到了,此时version=2, field-test3
- 然后先修改的后到了,此时如果不基于version进行版本控制,直接将field-test2盖过去,此时数据就错了
- 因为按照顺序来说,应该是数据从field=test1 ,先变为 frield-test2,再变为field-test3
es内部的多线程异步并发修改时,是基于自己的_version版本号进行,在后修改先到时,那么field-test3, version=2,先修改后到时,先修改的field=test2 , version-1 ,此时会比较一下version号,是否相等,如果不相等的话,那么就直接将 field-test2这条数据给扔掉,就不需要了,这样的话,结果就会保持为一个正确的状态, field-test3
Elasticsearch由浅入深(四)ES并发冲突、悲观锁与乐观锁、_version乐观锁并发的更多相关文章
- 分布式缓存重建并发冲突和zookeeper分布式锁解决方案
如果缓存服务在本地的ehcache中都读取不到数据. 这个时候就意味着,需要重新到源头的服务中去拉去数据,拉取到数据之后,赶紧先给nginx的请求返回,同时将数据写入ehcache和redis中 分布 ...
- asp.net core 系列之并发冲突
本文介绍如何处理多个用户并发更新同一实体(同时)时出现的冲突 . 主要是两种:一种,检查属性并发冲突,使用 [ConcurrencyCheck] ;另一种,检测行的并发冲突,使用 rowversion ...
- es之文档更新过程中并发冲突问题
1:乐观锁控制 ES是分布式的,也是异步并发的,我们的复制请求是并行发送的:这就意味着请求到达目的地的顺序是不可控制的,是乱序的: 如果是乱序的方式,很有可能出现这样的一个问题,新version的文档 ...
- Elasticsearch由浅入深(五)_version乐观锁、external version乐观锁、partial update、groovy脚本实现partial update
基于_version进行乐观锁并发控制 先构造一条数据出来 PUT /test_index/test_type/ { "test_field": "test test&q ...
- 并发-AtomicInteger源码分析—基于CAS的乐观锁实现
AtomicInteger源码分析—基于CAS的乐观锁实现 参考: http://www.importnew.com/22078.html https://www.cnblogs.com/mantu/ ...
- 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!
网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
- 写文章 通俗易懂 悲观锁、乐观锁、可重入锁、自旋锁、偏向锁、轻量/重量级锁、读写锁、各种锁及其Java实现!
网上关于Java中锁的话题可以说资料相当丰富,但相关内容总感觉是一大串术语的罗列,让人云里雾里,读完就忘.本文希望能为Java新人做一篇通俗易懂的整合,旨在消除对各种各样锁的术语的恐惧感,对每种锁的底 ...
- MySQL事物(一)事务隔离级别和事物并发冲突
数据库的操作通常为写和读,就是所说的CRUD:增加(Create).读取(Read).更新(Update)和删除(Delete).事务就是一件完整要做的事情.事务是恢复和并发控制的基本单位.事务必须始 ...
- Linq to Sql并发冲突及处理策略
0. 并发冲突的示例 单用户的系统现在应该比较罕见了,一般系统都会有很多用户在同时进行操作:在多用户系统中,涉及到的一个普遍问题:当多个用户“同时”更新(修改或者删除)同一条记录时,该如何更新呢? ...
随机推荐
- Linux 搭建邮件服务器
一.概述: 在配置邮件服务器之前,先解释几个概念. 1.SMTP:简单邮件传输协议 (Simple Mail Transfer Protocol, SMTP) 通常使用Email都很容易,但是Inte ...
- Python 简单爬虫案例
Python 简单爬虫案例 import requests url = "https://www.sogou.com/web" # 封装参数 wd = input('enter a ...
- springboot只能一个main方法解决办法
pom.xml修改properties,增加这行 <start-class>com.eshore.main.SpringBootStarter</start-class> 或者 ...
- linq,创建数据库,插入数据,newDB.CreateDatabase();newDB.tb2.InsertOnSubmit(stu); newDB.SubmitChanges();
using System.Data.Linq;using System.Data.Linq.Mapping; namespace ConsoleApplication1388{ class Progr ...
- GitHub中文社区
今天在打开GitHub的时候,使用了bing.com搜索,输入GitHub进行搜索链接,排名第一的为GitHub中文社区,点击去发现这个社区还可以,我们看看GitHub中文社区有哪些好的地方 GitH ...
- RSA应用指数与模生成公钥(ArcGIS Server)
参考: https://www.cnblogs.com/luo30zhao/p/10515594.html https://blog.csdn.net/skiof007/article/details ...
- Winform中实现设置ZedGraph的GraphPane的大小匹配ZedGraphControl
场景 Winforn中设置ZedGraph曲线图的属性.坐标轴属性.刻度属性: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/10 ...
- IIS创建文件服务器(WebDAV)
1.安装IIS,选择安装WEBDAV组件.然后新建站点,站点目录不需要额外设置任何权限 安装完成后组件: 2.配置WebDAV: 添加创作规则:允许某用户写入,其他所有用户读取.(写入规则必须要放在第 ...
- 【Java】简体中文、繁体中文转换
项目中用到繁体中文语言适配,目前已经有开源的框架可以将简体中文转换成繁体中文,在此基础上封装了一个工具类,可以直接将简体中文的strings.xml转换成繁体中文的strings.xml. 引用Jar ...
- [小程序]微信小程序获取input并发送网络请求
1. 获取输入框数据wxml中的input上增加bindinput属性,和方法值在js部分定义与之对应的方法,只要在输入的时候,数据就会绑定调用到该方法,存入data属性变量中 2. 调用get请求发 ...