一、文档冲突
当我们使用 index API 更新文档 ,可以一次性读取原始文档,做我们的修改,然后重 新索引 整个文档 。 最近的索引请求将获胜:无论最后哪一个文档被索引,都将被唯一存 储在 Elasticsearch 中。如果其他人同时更改这个文档,他们的更改将丢失。
很多时候这是没有问题的。或者对于我们的业务来说偶尔丢失更改并不是很严重的问题。但有时丢失了一个变更就是 非常严重的 。比如:库存的扣减(虽然目前很多库存的扣减都是使用redis实现),如果丢失将会发生超卖的现象。
变更越频繁,读数据和更新数据的间隙越长,也就越可能丢失变更。
在数据库领域中,有两种方法通常被用来确保并发更新时变更不会丢失:
一、悲观并发控制
它假定有变更冲突可能发生,因此阻塞访问资源以 防止冲突。 一个典型的例子是读取一行数据之前先将其锁住,确保只有放置锁的线程能够 对这行数据进行修改。
二、乐观并发控制
Elasticsearch 中使用的这种方法假定冲突是不可能发生的,并且不会阻塞正在尝试的操 作。 然而,如果源数据在读写当中被修改,更新将会失败。应用程序接下来将决定该如何 解决冲突。 例如,可以重试更新、使用新的数据、或者将相关情况报告给用户。
二、乐观并发控制
Elasticsearch 是分布式的。当文档创建、更新或删除时, 新版本的文档必须复制到集 群中的其他节点。Elasticsearch 也是异步和并发的,这意味着这些复制请求被并行发送,并 且到达目的地时也许 顺序是乱的 。如果更改数据,就会产生旧版本覆盖新版本的可能。
当我们之前讨论 index ,GET 和 delete 请求时,我们指出每个文档都有一个 _version (版本)号,当文档被修改时版本号递增。 Elasticsearch 使用这个 version 号来确保变更 以正确顺序得到执行。如果旧版本的文档在新版本之后到达,它可以被简单的忽略。就有点类似于mysql的乐观锁控制。
我们可以利用 version 号来确保 应用中相互冲突的变更不会导致数据丢失。我们通过 指定想要修改文档的 version 号来达到这个目的。 如果该版本不是当前版本号,我们的请 求将会失败。
老的版本 es 使用 version,但是新版本不支持了,会报下面的错误,提示我们用 if_seq_no 和 if_primary_term
{
"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
}如果想使用version,可以中通过增加 version_type=external来进行使用。