写点什么

Elasticsearch 乐观锁并发控制

用户头像
escray
关注
发布于: 2021 年 01 月 24 日
Elasticsearch 乐观锁并发控制

文字内容整理自 B 站中华石杉的 Elasticsearch 顶尖高手系列课程核心知识篇


先构造一条数据出来



PUT /test_index/test_type/7{ "test_field": "test 7"}
{ "_index" : "test_index", "_type" : "test_type", "_id" : "7", "_version" : 1, "result" : "created", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 10, "_primary_term" : 1}
复制代码


模拟两个客户端,都获取到了同一条数据(开两个浏览器的 tab 页就可以,或者不放心的话,也可以开两个浏览器,甚至是两个不同的浏览器)


GET test_index/test_type/7
{ "_index" : "test_index", "_type" : "test_type", "_id" : "7", "_version" : 1, "_seq_no" : 10, "_primary_term" : 1, "found" : true, "_source" : { "test_field" : "test 7" }}
复制代码


其中一个客户端,先更新了一下这个数据


同时带上数据的版本号,确保说,Elasticsearch 中的数据的版本号,跟客户端中的数据的版本号是相同的,才能修改


注意,这里问题来了,按照教程中带 version 参数的更新方式,得到了一个报错信息。然后按照提示,使用了 if_seq_no 和 if_primary_term 两个参数,才更新成功。


PUT test_index/test_type/7?version=1{  "test_field":"update from client 1 for verion 1"}
{ "error" : { "root_cause" : [ { "type" : "action_request_validation_exception", "reason" : "Validation Failed: 1: internal versioning can not be used for optimistic concurrency control. Please use `if_seq_no` and `if_primary_term` instead;" } ], "type" : "action_request_validation_exception", "reason" : "Validation Failed: 1: internal versioning can not be used for optimistic concurrency control. Please use `if_seq_no` and `if_primary_term` instead;" }, "status" : 400}
PUT test_index/test_type/7?if_seq_no=10&if_primary_term=1{ "test_field":"update from client 1 for verion 1"}
{ "_index" : "test_index", "_type" : "test_type", "_id" : "7", "_version" : 2, "result" : "updated", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 11, "_primary_term" : 1}
复制代码


另外一个客户端,尝试基于 version=1 的数据去进行修改,同样带上 version 版本号,进行乐观锁的并发控制。


可以看到同样的错误提示,大概是因为 7.10.1 版本与 5.2 版本的差别。


# 7.10.1PUT test_index/test_type/7?if_seq_no=10&if_primary_term=1{  "test_field":"update from client 1 for verion 1"}
{ "error" : { "root_cause" : [ { "type" : "version_conflict_engine_exception", "reason" : "[7]: version conflict, required seqNo [10], primary term [1]. current document has seqNo [11] and primary term [1]", "index_uuid" : "zJ1EzrvMTIeZgBYwUX5u2A", "shard" : "0", "index" : "test_index" } ], "type" : "version_conflict_engine_exception", "reason" : "[7]: version conflict, required seqNo [10], primary term [1]. current document has seqNo [11] and primary term [1]", "index_uuid" : "zJ1EzrvMTIeZgBYwUX5u2A", "shard" : "0", "index" : "test_index" }, "status" : 409}
# 5.2 PUT /test_index/test_type/7?version=1 { "test_field": "test client 2" } { "error": { "root_cause": [ { "type": "version_conflict_engine_exception", "reason": "[test_type][7]: version conflict, current version [2] is different than the one provided [1]", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "3", "index": "test_index" } ], "type": "version_conflict_engine_exception", "reason": "[test_type][7]: version conflict, current version [2] is different than the one provided [1]", "index_uuid": "6m0G7yx7R1KECWWGnfH1sw", "shard": "3", "index": "test_index" }, "status": 409 }
复制代码


在乐观锁成功阻止并发问题之后,尝试正确的完成更新


GET test_index/test_type/7
{ "_index" : "test_index", "_type" : "test_type", "_id" : "7", "_version" : 2, "_seq_no" : 11, "_primary_term" : 1, "found" : true, "_source" : { "test_field" : "update from client 1 for verion 1" }}
复制代码


基于最新的数据和版本号,去进行修改,修改后,带上最新的版本号,可能这个步骤会需要反复执行好几次,才能成功,特别是在多线程并发更新同一条数据很频繁的情况下


查了一下官方文档,大概是在 Elasticsearch 6.7 版本的时候,使用 version 关键字进行乐观锁的内部版本控制就已经取消了,转而使用 if_seq_no 和  if_primary_term 来指定版本。


Indexing changes


Deprecated usage of internal versioning for optimistic concurrency control


internal version may not uniquely identify a document’s version if an indexed document wasn’t fully replicated when a primary fails. As such it is unsafe to use for optimistic concurrency control, is deprecated and the option will no longer be available in Elasticsearch 7.0.0. Please use the if_seq_no and if_primary_term parameters instead. See Optimistic concurrency control for more details.


https://www.elastic.co/guide/en/elasticsearch/reference/6.8/breaking-changes-6.7.html


The sequence number is increased with each operation and thus newer operations are guaranteed to have a higher sequence number than older operations. Elasticsearch can then use the sequence number of operations to make sure a newer document version is never overridden by a change that has a smaller sequence number assigned to it.


The sequence number and the primary term uniquely identify a change.


https://www.elastic.co/guide/en/elasticsearch/reference/current/optimistic-concurrency-control.html


另外需要注意的是 if_seq_no 和  if_primary_term 必须同时使用。


PUT test_index/test_type/7?if_seq_no=11{  "test_field":"test update from client 2"}
{ "error" : { "root_cause" : [ { "type" : "action_request_validation_exception", "reason" : "Validation Failed: 1: ifSeqNo is set, but primary term is [0];" } ], "type" : "action_request_validation_exception", "reason" : "Validation Failed: 1: ifSeqNo is set, but primary term is [0];" }, "status" : 400}
PUT test_index/test_type/7?if_seq_no=11&if_primary_term=1{ "test_field":"test update from client 2"}
{ "_index" : "test_index", "_type" : "test_type", "_id" : "7", "_version" : 3, "result" : "updated", "_shards" : { "total" : 2, "successful" : 2, "failed" : 0 }, "_seq_no" : 12, "_primary_term" : 1}
复制代码


发布于: 2021 年 01 月 24 日阅读数: 28
用户头像

escray

关注

Let's Go 2017.11.19 加入

在学 Elasticsearch 的项目经理

评论

发布
暂无评论
Elasticsearch 乐观锁并发控制