本节的主要内容:ES的乐观锁并发控制原理以及模拟过程
1、ES的乐观锁并发控制
1.1、悲观锁与乐观锁
悲观锁的优点是:方便,直接加锁,对应用程序来说透明,不需要做额外的操作;缺点,并发能力很低,同一时间只能一条线程操作数据
乐观锁的优点是:并发能力很高,不给数据加锁,大量线程并发操作;缺点,麻烦,每次更新的时候,都要先对比版本号,然后可能需要重新加载数据,再次修改,再写;这个过程,可能要重复好几次。
1.2、Elasticsearch内部如何基于_version进行乐观锁并发控制
es内部的多线程异步并发修改时,是基于自己的version版本号进行乐观锁并发控制的
第一次创建一个document的时候,它的version内部版本号就是1;以后,每次对这个document执行修改或者删除操作,都会对这个version版本号自动加1;哪怕是删除,也会对这条数据的版本号加1
举例说明:
某document的初始值 version=1,field=test1,模拟两个线程同时进行修改
先修改的field=test2 ,此时获取的version=1
后修改的field=test3,此时获取的version= 1,后修改先到,更新field=test3,此时version= 2
先修改的后到时,此时会比较一下version号,是否相等,如果不相等的话,那么就直接将field=test2这条数据给扔掉,这样的话就不会让旧的数据,覆盖掉新的数据
2、ES内部并发控制
所有的REST命令都可以在 Kibana 7.6.1上正常运行
(1)先构造一条数据出来
POST /test_index/_create/7
{
"test_field": "test test"
}
(2)模拟两个客户端,都获取到了同一条数据
GET test_index/_doc/7
返回的结果
{
"_index" : "test_index",
"_type" : "_doc",
"_id" : "7",
"_version" : 3,
"_seq_no" : 2,
"_primary_term" : 1,
"found" : true,
"_source" : {
"test_field" : "test test"
}
}
(3)其中一个客户端,先更新了一下这个数据
注意
一些老的版本es使用version,但是新版本不支持了,会提示我们用if_seq_no和if_primary_term
先查操作之前当前数据的seq_no,primary_term值比如各自是2和1,在更新的时候url带上if_seq_no=2&if_primary_term=1,指明只有在这个值的情况下才进行更新,否则返回错误
PUT test_index/_doc/7?if_seq_no=2&if_primary_term=1
{
"test_field": "test client 1"
}
如果重复执行就会报 version_conflict_engine_exception
异常
此时就需要基于最新的数据和版本号去进行修改,修改后,带上最新的版本号,可能这个步骤会需要反复执行好几次,才能成功,特别是在多线程并发更新同一条数据很频繁的情况下
//使用最新的_seq_no和_primary_term就可以正常更新了
PUT test_index/_doc/7?if_seq_no=3&if_primary_term=1
{
"test_field": "test client 1"
}
3、ES基于 external version 进行并发控制
使用外部版本(使用其他数据库作为主要数据存储)
当version_type=external时,只有当你提供的version比es中的_version大的时候,才能完成修改
当document 的_version=1,只有当version>1&version_type=external,才能成功,
比如说使用version=7&version_type=external更新document成功后,该document的_version会设置为7,后续的更新需要基于最新的版本号发起更新
PUT test_index/_doc/7?version=7&version_type=external
{
"title":"iphone",
"count":130
}
网友评论