ElasticSearch进阶篇(一)--版本控制
一、前言
ElasticSearch(以下简称ES)的数据写入支持高并发,高并发就会带来很普遍的数据一致性问题。常见的解决方法就是加锁。同样,ES为了保证高并发写的数据一致性问题,加入了类似于锁的实现方法--版本控制。锁从其中的一个角度可分为乐观锁和悲观锁。
对于同一个数据的并发操作,悲观锁认为自己在使用数据的时候一定会有别的线程过来修改数据,因此在获取数据的时候会先加锁,确保数据不会被别的线程修改。而乐观锁则认为自己在使用数据时不会有别的线程来修改数据,所以不会添加锁,只是在更新或者提交数据的时候去判断之前有没有别的线程更新了这个数据。那么ES属于那种锁呢?下面大狮兄就和大家一起探讨官方的具体做法来回答这个问题。
二、版本控制实现及验证
1. ES6.7 Before
# 新建测试索引
PUT test
{
"settings" : {
"number_of_shards" : "3",
"number_of_replicas" : "0"
}
}
## 插入文档
PUT test/_doc/1
{"user": "zhangsan", "age": 12}
## 响应结果
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
更新文档(version版本大于已写入文档版本),更新年龄为10,版本号为200
## 更新文档
PUT test/_doc/1?version=200&version_type=external
{"user": "zhangsan", "age": 10}
## 返回结果
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_version" : 200,
"result" : "updated",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
## 查询文档
GET test/_doc/1
## 返回结果
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_version" : 200,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "zhangsan",
"age" : 10
}
}
更新成功,年龄更新为10且版本号更新为200
更新文档(version版本小于或等于已写入文档版本),更新年龄为22,版本号为180
## 更新文档
PUT test/_doc/1?version=180&version_type=external
{"user": "zhangsan", "age": 22}
## 返回结果
{
"error" : {
"root_cause" : [
{
"type" : "version_conflict_engine_exception",
"reason" : "[1]: version conflict, current version [200] is higher or equal to the one provided [180]",
"index_uuid" : "fCv7Q1dkTl6e9E1Z0dNE1g",
"shard" : "2",
"index" : "test"
}
],
"type" : "version_conflict_engine_exception",
"reason" : "[1]: version conflict, current version [200] is higher or equal to the one provided [180]",
"index_uuid" : "fCv7Q1dkTl6e9E1Z0dNE1g",
"shard" : "2",
"index" : "test"
},
"status" : 409
}
## 查询文档
GET test/_doc/1
## 返回结果
{
"_index" : "test",
"_type" : "_doc",
"_id" : "1",
"_version" : 200,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "zhangsan",
"age" : 10
}
}
更新失败,数据没有变化,提示版本冲突,现有的版本号大于要插入的版本号。
- vertion_type=external 或者 vertion_type=external_gt :目标版本号大于已有的版本号才会更新成功。
- vertion_type=external_gte :目标版本号大于或等于已有的版本号才会更新成功。
2. ES6.7 OR Later
# 新建测试索引
PUT testccc
{
"settings" : {
"number_of_shards" : "1",
"number_of_replicas" : "0"
}
}
## 插入文档
PUT testccc/_doc/1
{"user": "lisi", "age": 12}
## 返回结果
{
"_index" : "testccc",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_primary_term" : 1
}
返回结果注意最后的两个字段,_seq_no表示序列号是自增的,_primary_term表是文档位于哪个shard。
更新数据(seq_no大于已写入文档序列号),更新年龄为10,序列号为20
## 更新文档
PUT testccc/_doc/1?if_seq_no=20&if_primary_term=1
{"user": "lisi", "age": 10}
## 返回结果
{
"error" : {
"root_cause" : [
{
"type" : "version_conflict_engine_exception",
"reason" : "[1]: version conflict, required seqNo [20], primary term [1]. current document has seqNo [0] and primary term [1]",
"index_uuid" : "N6LzBNj9S5yqVWFubt3x4Q",
"shard" : "0",
"index" : "testccc"
}
],
"type" : "version_conflict_engine_exception",
"reason" : "[1]: version conflict, required seqNo [20], primary term [1]. current document has seqNo [0] and primary term [1]",
"index_uuid" : "N6LzBNj9S5yqVWFubt3x4Q",
"shard" : "0",
"index" : "testccc"
},
"status" : 409
}
## 查询文档
GET testccc/_doc/1
## 返回结果
{
"_index" : "testccc",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "lisi",
"age" : 12
}
}
更新失败,数据无变化,提示版本冲突,最近文档的序列号为0,要更新的序列号为20。
更新数据(seq_no等于已写入文档序列号),更新年龄为10
## 更新文档
PUT testccc/_doc/1?if_seq_no=0&if_primary_term=1
{"user": "lisi", "age": 10}
## 返回结果
{
"_index" : "testccc",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 1,
"_primary_term" : 1
}
## 查询文档
GET testccc/_doc/1
## 返回结果
{
"_index" : "testccc",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"user" : "lisi",
"age" : 10
}
}
更新成功,且seq_no自增为1。
## 插入新文档
PUT testccc/_doc/2
{"user": "wangwu", "age": 40}
## 返回结果
{
"_index" : "testccc",
"_type" : "_doc",
"_id" : "2",
"_version" : 1,
"result" : "created",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 2,
"_primary_term" : 1
}
## 更新原文档
PUT testccc/_doc/1?if_seq_no=1&if_primary_term=1
{"user": "lisi", "age": 50}
## 返回结果
{
"_index" : "testccc",
"_type" : "_doc",
"_id" : "1",
"_version" : 3,
"result" : "updated",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 3,
"_primary_term" : 1
}
## 更新新写入文档
PUT testccc/_doc/2?if_seq_no=2&if_primary_term=1
{"user": "wangwu", "age": 80}
## 返回结果
{
"_index" : "testccc",
"_type" : "_doc",
"_id" : "2",
"_version" : 2,
"result" : "updated",
"_shards" : {
"total" : 1,
"successful" : 1,
"failed" : 0
},
"_seq_no" : 4,
"_primary_term" : 1
}
可以观察到对于不同的文档,seq_no总是自增1的。
三、总结
- ES版本控制类似于Java中的乐观锁,尤其对版本号字段的巧妙使用与解决乐观锁ABA问题的CAS算法有异曲同工之妙。
- ES6.7之后添加的if_seq_no与if_primary_term版本控制是针对于整个索引的,而_version和version_type版本控制是针对于单条记录(即单个文档)的,不同的应用场景可使用不同的版本控制策略。
- if_seq_no配置的值必须等于存在于现有文档中才能更新成功,而_version配置的值根据不同的version_type,必须大于或者大于等于文档最近更改过的_version值才能更新成功。
ElasticSearch进阶篇(一)--版本控制的更多相关文章
- Elasticsearch进阶篇(一)~head插件的安装与配置
1.安装node.js 1.1.通过官网下载二进制安装包 https://nodejs.org/en/download/ 选择对应的版本,右键复制下载链接,进入linux目录,切换到要安装目录的磁盘. ...
- SQL Server调优系列进阶篇(如何维护数据库索引)
前言 上一篇我们研究了如何利用索引在数据库里面调优,简要的介绍了索引的原理,更重要的分析了如何选择索引以及索引的利弊项,有兴趣的可以点击查看. 本篇延续上一篇的内容,继续分析索引这块,侧重索引项的日常 ...
- Membership三步曲之进阶篇 - 深入剖析Provider Model
Membership 三步曲之进阶篇 - 深入剖析Provider Model 本文的目标是让每一个人都知道Provider Model 是什么,并且能灵活的在自己的项目中使用它. Membershi ...
- idea 插件的使用 进阶篇
CSDN 2016博客之星评选结果公布 [系列直播]零基础学习微信小程序! "我的2016"主题征文活动 博客的神秘功能 idea 插件的使用 进阶篇(个人收集 ...
- 2. web前端开发分享-css,js进阶篇
一,css进阶篇: 等css哪些事儿看了两三遍之后,需要对看过的知识综合应用,这时候需要大量的实践经验, 简单的想法:把qq首页全屏另存为jpg然后通过ps工具切图结合css转换成html,有无从下手 ...
- windows系统快捷操作の进阶篇
上次介绍了windows系统上一些自带的常用快捷键,有些确实很方便,也满足了我们的一部分需求.但是我们追求效率的步伐怎会止步于此?这一次我将会进一步介绍windows上提升效率的方法. 一:运行 打开 ...
- python 面向对象(进阶篇)
上一篇<Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使 ...
- 最快让你上手ReactiveCocoa之进阶篇
前言 由于时间的问题,暂且只更新这么多了,后续还会持续更新本文<最快让你上手ReactiveCocoa之进阶篇>,目前只是简短的介绍了些RAC核心的一些方法,后续还需要加上MVVM+Rea ...
- SQL Server调优系列进阶篇(查询优化器的运行方式)
前言 前面我们的几篇文章介绍了一系列关于运算符的基础介绍,以及各个运算符的优化方式和技巧.其中涵盖:查看执行计划的方式.几种数据集常用的连接方式.联合运算符方式.并行运算符等一系列的我们常见的运算符. ...
随机推荐
- To_Heart—题解——AT2165
这是一篇解题报告 首先,看到标签,考虑二分答案. 我们二分答案(即塔顶的值),把大于或等于这个值的变为1,否则变为0. 很容易发现,如果塔顶的答案是1,那么就说明值可以更大,否则相反. 复制一波样例 ...
- MindSpore模型精度调优实战:如何更快定位精度问题
摘要:为大家梳理了针对常见精度问题的调试调优指南,将以"MindSpore模型精度调优实战"系列文章的形式分享出来,帮助大家轻松定位精度问题,快速优化模型精度. 本文分享自华为云社 ...
- web自动化页面元素不能键盘输入
一.背景 web自动化中存在一部分元素属性是readonly属性,导致我们在使用自动化代码的时候无法使用sendkeys()方法传入数据,以12306网站选择出发日期为例,见下图 二.json语句处理 ...
- Https:创建部署SSL证书进行双向认证
一.前言 建立客户端与服务器的Https的连接需要证书进行双向验证后,才可访问. 二.证书类型 不同数字证书部署在服务器上后,用户浏览器访问网站时,展示如下: 1.无证书时 显示不安全标识. 2. ...
- 看看PHP迭代器的内部执行过程(转)
1 class myIterator implements Iterator { 2 private $position = 0; 3 private $array = array( 4 &quo ...
- JS秒表倒计时器 (转)
<html> <body> <span>倒计时30分钟:</span><span id="clock">00:30:00 ...
- Shell常用工具find,grep,sed,awk,xargs命令
最近学习shell命令,对grep,sed,awk命令有点混乱,故小结一下,巩固一遍. 注意:find , grep , sed, awk可使用基本正则表达式字符,find,grep,awk也支持扩展 ...
- WPF教程十三:自定义控件进阶可视化状态与自定义Panel
如果你敲了上一篇的代码,经过上一篇各种问题的蹂躏,我相信自定义控件基础部分其实已经了解的七七八八了.那么我们开始进阶,现在这篇讲的才是真正会用到的核心的东西.简化你的代码.给你提供更多的可能,掌握了这 ...
- pod调度
Pod调度 在默认情况下,一个pod在哪个node节点上运行,是由scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的. 但是在实际过程中,这并不满足需求,因为很多情况下,我们想控 ...
- ARTS第十一周
受辞职考研和新冠肺炎疫情影响,一直没更.遗憾,数学和专业课再高点就有戏了.继续. 1.Algorithm:每周至少做一个 leetcode 的算法题2.Review:阅读并点评至少一篇英文技术文章3. ...