Elasticsearch-对并发冲突的解决(乐观锁、悲观锁)
来源:互联网 发布:淘宝店铺直播招人 编辑:程序博客网 时间:2024/06/05 04:05
多个线程去同时访问es中的一份数据,然后各自去修改之后更新到es,由于线程的先后顺序不同,可能会导致后续的修改覆盖掉之前的修改,显然一些场景下我们是不允许发生这种并发冲突的问题,例如电商库存的修改等
在es中,如何能够解决这种并发冲突的问题?
- 通过_version版本号的方式进行乐观锁并发控制
在es内部第次一创建document的时候,它的_version默认会是1,之后进行的删除和修改的操作_version都会增加1。可以看到删除一个document之后,再进行同一个id的document添加操作,版本号是加1而不是初始化为1,从而可以说明document并不是正真地被物理删除,它的一些版本号信息一样会存在,而是会在某个时刻一起被清除。
在es后台,有很多类似于replica同步的请求,这些请求都是异步多线程的,对于多个修改请求是乱序的,因此会使用_version乐观锁来控制这种并发的请求处理。当后续的修改请求先到达,对应修改成功之后_version会加1,然后检测到之前的修改到达会直接丢弃掉该请求;而当后续的修改请求按照正常顺序到达则会正常修改然后_version在前一次修改后的基础上加1(此时_version可能就是3,会基于之前修改后的状态)。
es提供了一个外部版本号的乐观控制方案来替代内部的_version。例如:
?version=1&version_type=external
和内在的_version的区别在于。对于内在_version=1,只有在后续请求满足?_version=1的时候才能够更新成功;对于外部_version=1,只有在后续请求满足?_version>1才能够修改成功。
- 通过悲观锁的方式进行乐观锁并发控制
1.全局锁,通过doc来进行对整个index上锁
一个线程进行操作之前创建一个锁,例如:
PUT /lockindex/locktype/global/_create{}
同时如果有另一个线程要进行相关更新操作,那么同样执行上述代码是会报错。在上述线程执行完DELETE对应doc之后,该线程就可以重新获取到doc的锁从而执行自己的一些列操作。
这种方式,操作很简单,但是锁住了整个index,导致整个系统的并发能力很低。
2.document锁,粒度更细的锁
需要通过脚本来实现:
POST /fs/lock/1/_update{ "upsert": { "process_id": 123 }, "script": "if ( ctx._source.process_id != process_id ) { assert false }; ctx.op = 'noop';" "params": { "process_id": 123 }}
process_id,很重要,会在lock中,设置对对应的doc加锁的进程的id,这样其他进程过来的时候,才知道,这条数据已经被别人给锁了
assert false,不是当前进程加锁的话,则抛出异常
ctx.op=’noop’,不做任何修改
params,里面有个process_id,是你的要执行增删改操作的进程的唯一id
对于同一个process_id的进程是都可以来修改doc,但是用不同的process_id去修改已经上锁的其他process_id是会assert false抛错。
3.共享锁与排它锁
共享锁:数据是共享的,多个线程可以获取同一个数据的共享锁,然后对这个数据执行读操作
排它锁:只能有一个线程获取排它锁,然后执行更新操作
共享锁与排他锁是互斥的特性,如果有一个线程想要去修改一个数据,也就是获取一个排它锁,此时需要等待其他所有的共享锁先释放掉才能够进行操作,反之亦然。
首先添加共享锁,其他线程也可以来读取数据:
judge-lock-2.groovy: if (ctx._source.lock_type == 'exclusive') { assert false }; ctx._source.lock_count++POST /fs/lock/1/_update { "upsert": { "lock_type": "shared", "lock_count": 1 }, "script": { "lang": "groovy", "file": "judge-lock-2" }}
如果其他线程也需要获取共享锁,那么执行上述同样的代码即可,最终只是lock_count加1了:
GET /fs/lock/1{ "_index": "fs", "_type": "lock", "_id": "1", "_version": 3, "found": true, "_source": { "lock_type": "shared", "lock_count": 3 }}
当添加排他锁的时候:
PUT /fs/lock/1/_create{ "lock_type": "exclusive" }
则会报错
对共享锁进行解锁:
POST /fs/lock/1/_update{ "script": { "lang": "groovy", "file": "unlock-shared" }}
添加过多少个共享锁,对应的执行解锁操作相应次数即可完全解锁。每次解锁lock_count对应减1,当为0的时候就将/fs/lock/1删除
对应的解除排它锁:
DELETE /fs/lock/1
- Elasticsearch-对并发冲突的解决(乐观锁、悲观锁)
- Hibernate乐观锁与悲观锁的使用(并发)
- 乐观锁和悲观锁 对多并发处理
- 悲观锁和乐观锁解决hibernate并发
- 悲观锁和乐观锁解决hibernate并发
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- (13) 悲观锁和乐观锁解决hibernate并发(转)
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 乐观锁与悲观锁——解决并发问题
- 一个程序员的成长漫长之路
- poj 1005 I Think I Need a Houseboat
- java基础随笔
- Python中NumPy简介及使用举例
- 第五十七篇:VS2015建立一个完整的c++工程:头文件.h 源文件.cpp,自动生成类
- Elasticsearch-对并发冲突的解决(乐观锁、悲观锁)
- 【JZOJ 5390】【NOIP2017提高A组模拟9.26】逗气
- 2017 ACM-ICPC 亚洲区(南宁赛区)网络赛 A Weather Patterns
- 正则表达式语法
- 获取软键盘高度
- C语言难点
- http和socket之长连接和短连接区别
- HDOJ2029
- 软件测试-测试分类/用例/报告/框架概述