Elasticsearch和数据库一样,在多线程并发访问修改的情况下,会有一个锁机制来控制每次修改的均为最新的文档。大体上主要有乐观锁和悲观锁两类。
乐观锁
在Elasticsearch通过_version来记录文档的版本,在文档创建时会有一个初始version,默认为1。在对文档进行修改和删除时,version会递增,也可以由用户指定。只有当版本号大于当前版本时,才会修改删除成功,否则失败。当并发请求时,先修改成功的,version会增加,这个时候其他请求就会犹豫version不匹配从而修改失败。
由于segment时不能被修改的,所以当对一个文档执行DELETE之后,在插入相同id的文档,version版本不会是0,而是在DELETE操作的version上递增。
外部版本号和内部版本号区别
对于内在_version=1,只有在后续请求满足?_version=1的时候才能够更新成功;对于外部_version=1,只有在后续请求满足?_version>1才能够修改成功。
es提供了一个外部版本号的乐观控制方案来替代内部的_version。
?version=1&version_type=external
悲观锁
悲观锁类似于数据库中的锁。当线程1在修改或删除doc时,会对数据上锁,这个时候其它线程不能对数据进行操作的。这种方式保证了只有一个线程在同时操作数据。这种方式的缺点是对系统性能有影响,会降低整个系统并发能力,因为其他线程要等待。
悲观锁主要有以下几种方式:
全局锁
对整个index上锁,类似数据库的表锁。
当对文档进行操作时,会对整个index。
上锁
##上锁
PUT /fs/lock/global/_create
{}
##释放锁
DELETE /fs/lock/global
文档锁
在文档级别上锁,类似数据库的行锁。
create上锁
PUT /fs/lock/_bulk
{ "create": { "_id": 1}}
{ "process_id": 123 }
{ "create": { "_id": 2}}
{ "process_id": 123 }
update上锁,需要用脚本。
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
}
}
如果update文档不存在,则走上面的create。如果文档存在,脚本会查看文档中的process_id是否和要修改的process_id匹配,如果匹配不会执行update,但是会返回为成功。如果不匹配即上锁失败。
树锁
参考https://www.elastic.co/guide/cn/elasticsearch/guide/current/concurrency-solutions.html
更多:Elasticsearch深入理解专栏
——————————————————————————————————
作者:桃花惜春风
转载请标明出处,原文地址:
https://blog.csdn.net/xiaoyu_BD/article/details/81941631
如果感觉本文对您有帮助,请留下您的赞,您的支持是我坚持写作最大的动力,谢谢!