Elasticsearch学习笔记(四)版本控制[并发安全]
来源:互联网 发布:兰大网络教育平台登录 编辑:程序博客网 时间:2024/06/05 03:40
乐观锁
我们知道锁有悲观锁和乐观锁之分,数据库中的事务就是悲观锁,CAS就是属于乐观锁,关于CAS乐观锁的概念请参考本人另一篇文章: java高并发:CAS无锁原理及广泛应用
一个CAS方法包含三个参数CAS(V,E,N)
。V表示要更新的变量,E表示预期的值,N表示新值。只有当V的值等于E时,才会将V的值修改为N。如果V的值不等于E,说明已经被其他线程修改了,当前线程可以放弃此操作,也可以再次尝试次操作直至修改成功。基于这样的[算法](http://lib.csdn.net/base/datastructure “算法与数据结构知识库”),CAS操作即使没有锁,也可以发现其他线程对当前线程的干扰(临界区值的修改),并进行恰当的处理。
ES中的乐观锁
使用ES自带的版本控制
我们get请求id=2的员工信息megacorp/employee/2
:
{ "_index": "megacorp", "_type": "employee", "_id": "2", "_version": 2, "found": true, "_source": { "first_name": "Jane", "last_name": "Smith", "age": 33, "about": "I like to collect rock albums", "interests": ["music"] }}
注意,这里_version
是2,我们从ES中查询到一条记录,修改完成以后重新PUT建立索引,这时候我们要把_version
作为一个参数传递过去,ES会用该参数和实际的数据进行比对,如果相同则进行重建索引,如果不同则返回错误信息,具体如何处理这个错误就看业务需要了,比如你可以借鉴atomicInteger
循环重试等等。
我们将年龄改为80:
请求URL:megacorp/employee/2?version=2
请求参数:
{ "first_name": "Jane", "last_name": "Smith", "age": 80, "about": "I like to collect rock albums", "interests": [ "music" ]}
结果:
{ "_index": "megacorp", "_type": "employee", "_id": "2", "_version": 3, "_shards": { "total": 2, "successful": 2, "failed": 0 }, "created": false}
修改成功,此时_version
变为了3。
我们在重新执行一遍上面的程序,_version
依旧传2,按照CAS理论应该修改不成功。实验结果:
{ "error": { "root_cause": [{ "type": "version_conflict_engine_exception", "reason": "[employee][2]: version conflict, current [3], provided [2]", "index": "megacorp", "shard": "2" }], "type": "version_conflict_engine_exception", "reason": "[employee][2]: version conflict, current [3], provided [2]", "index": "megacorp", "shard": "2" }, "status": 409}
结果和我们预想的一样,错误原因写的很明确了,当前版本是3,但是传递过来的版本是2,与current不一致。
使用外部版本控制系统
一种常见的结构是使用一些其他的数据库做为主数据库,然后使用Elasticsearch搜索数据,这意味着所有主数据库发生变化,就要将其拷贝到Elasticsearch中。如果有多个进程负责这些数据的同步,就会遇到上面提到的并发问题。
如果主数据库有版本字段——或一些类似于timestamp
等可以用于版本控制的字段——是你就可以在Elasticsearch的查询字符串后面添加version_type=external
来使用这些版本号。版本号必须是整数,大于零小于9.2e+18
——Java中的正的long
。
外部版本号与之前说的内部版本号在处理的时候有些不同。它不再检查_version
是否与请求中指定的一致,而是检查是否小于指定的版本。如果请求成功,外部版本号就会被存储到_version
中。
外部版本号不仅在索引和删除请求中指定,也可以在创建(create)新文档中指定。
例如,创建一个包含外部版本号5
的新博客,我们可以这样做:
PUT /website/blog/2?version=5&version_type=external{ "title": "My first external blog entry", "text": "Starting to get the hang of this..."}
在响应中,我们能看到当前的_version
号码是5
:
{ "_index": "website", "_type": "blog", "_id": "2", "_version": 5, "created": true}
现在我们更新这个文档,指定一个新version
号码为10
:
PUT /website/blog/2?version=10&version_type=external{ "title": "My first external blog entry", "text": "This is a piece of cake..."}
请求成功的设置了当前_version
为10
:
{ "_index": "website", "_type": "blog", "_id": "2", "_version": 10, "created": false}
如果你重新运行这个请求,就会返回一个像之前一样的冲突错误,因为指定的外部版本号不大于当前在Elasticsearch中的版本。
参考资料:Elasticsearch 权威指南(中文版)
- Elasticsearch学习笔记(四)版本控制[并发安全]
- Elasticsearch版本控制[并发安全]
- 【学习笔记】多版本并发控制
- 并发控制学习笔记
- Elasticsearch学习(四)
- WCF学习笔记(四)数据契约、版本控制、错误
- 1、ElasticSearch源码学习分享:ElasticSearch版本控制
- Mysql学习笔记(一) 并发控制
- 版本控制学习笔记
- elasticsearch 并发控制
- Elasticsearch并发控制
- android安全学习笔记(四)
- ElasticSearch学习笔记(四)Head的安装
- ElasticSearch:版本冲突处理(事务控制)
- ElasticSearch:版本冲突处理(事务控制)
- Elasticsearch 版本控制
- Linux 学习笔记(四)进程控制
- Java学习笔记(四)循环控制
- 十一、0字节存储海量语料资源
- 单例模式
- 十二、教你如何利用强大的中文语言技术平台做依存句法和语义依存分析
- 十三、把语言模型探究到底
- log4cpp编译安装
- Elasticsearch学习笔记(四)版本控制[并发安全]
- 史上最简单的 Spring MVC 教程(三)
- 十四、探究中文分词的艺术
- 洛谷 P1091 合唱队形
- 十五、一篇文章读懂拿了图灵奖和诺贝尔奖的概率图模型
- 十六、大话自然语言处理中的囊中取物
- 浅谈MongoDB中几种不同查询方法
- Elasticsearch学习笔记(五)批量操作
- 了解点机器学习