今天在分析ES的索引的创建过程中看到了些和version相关的变量(例如:versionForIndexing)。这些个变量是干什么的呢?
答:用于冲突处理的。
在ES的应用场景中,使用index API更新文档,可以一次性读取原始文档,做修改,然后重新索引整个文档,最近的索引请求将获胜:无论最后哪一个文档被索引,都将唯一存储在ElasticSearch中,如果其他人同时更改了这个文档,他们的更改将丢失。
很多时候丢失信息是没问题的。也许我们的主数据存储是一个关系型数据库,我们只是将数据复制到ElasticSearch中并使其可被搜索;也许两个人同时更改文档的几率很小 。或者对于某些业务来说偶尔丢失更改并不是很严重的问题。
但,有时候丢失一个变更就是非常严重的。试想我们使用ElasticSearch存储我们网上商城商品库存的数量,每次我们卖一个商品的时候,在ElasticSearch中将库存数量减少(促销时一个时间点卖很多商品)。或是金融系统两个人同时对一个账户进行取钱操作。都存在如下图中存在的问题:
在数据库领域中,有两种方法通常备用来确保并发更新时变更不会丢失:
1、悲观并发控制
这种方法被关系型数据库广泛使用,它假定有变更冲突可能发生,因此阻塞访问资源以防止冲突。一个典型的例子是读取一行数据之前先将其锁住,确保只有放置锁的线程能够对这行数据进行修改。
2、乐观并发控制
Elasticsearch 中使用的这种方法,它假定冲突是不可能发生的,所以不会阻塞正在尝试的操作。 然而,如果源数据在读写当中被修改,更新将会失败。应用程序接下来将决定该如何解决冲突。 例如,可以获取新的数据,重试更新、或者将相关情况报告给用户。
===============================================
ElasticSearch是分布式的,当文档创建、更新、删除时,新版本的文档必须复制到集群中其他节点,同时,ElasticSearch也是异步和并发的。这就意味着这些复制请求被并行发送,并且到达目的地时也许顺序是乱的(老版本可能在新版本之后到达)。ElasticSaerch需要一种方法确保文档的旧版本不会覆盖新的版本:ES利用_version (版本号)的方式来确保应用中相互冲突的变更不会导致数据丢失。需要修改数据时,需要指定想要修改文档的version号,如果该版本不是当前版本号,请求将会失败。
详细例子参见:连接
ElasticSearch中有内部版本号和外部版本号之分。使用内部版本号是要求指定的version字段和当前的version号相同。但在使用外部版本号时要求当前version号小于指定的版本号。如果请求成功,外部版本号作为文档新的version号进行存储。详细参见:连接
外部版本号命令:
PUT /website/blog/2?version=5&version_type=external
内部版本号命令:
PUT /website/blog/1?version=1
参考文章:
https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/optimistic-concurrency-control.html
https://elasticsearch.cn/book/elasticsearch_definitive_guide_2.x/version-control.html