Elasticsearch核心知识篇(18)
深度图解剖析Elasticsearch并发冲突问题
自己的理解:
- 出现的问题:
- 和线程互相争抢数据一样,当两个线程同时访问到ES的同一个数据的时候,我们的数据(假设是剩余量)返回给线程A和线程B的数字是一致的,都是100件,当我们的线程A的用户下了一单,此时剩余量就变成了99件,写回ES,剩余量数据真实为99,但是线程B在刚才的过程中获取到的存量是100,此时B也下了一单,此时B计算完的剩余量就变成了99件,但是实际上的真实的剩余量是98,线程B将数据99写回到ES中,这样数据的同步中出现问题。这个和线程冲突是一样的
Elasticsearch核心知识篇(19)
深度图解剖析悲观锁与乐观锁两种并发控制方案
自己的理解:
- 悲观锁:
- 整个悲观锁的并发控制流程:首先线程A拿到ES的数据,并将ES的数据进行上锁,其他的线程是不能获取到ES数据,相当于卡住了,然后线程A,进行下单操作,库存量减1,这样剩余量是99,线程A将数据写回到ES中,并且将锁进行释放,此时线程B拿到锁,就可以去获取到剩余量的数据,此时B拿到的数据是99,在执行下单操作,库存量减1,这样剩余量是98,线程B将数据写回到ES中,并且将锁进行释放.
- 乐观锁:
- 整个乐观锁的并发控制流程:(
乐观锁是不加锁的
)首先我们线程A和线程B都拿到库存量100的数据,在这个时候同时返回来的还有数据的版本号,线程A拿到的数据的版本号是version=1,线程B拿到的数据的版本号是version=1,这个时候线程A执行了一个下单操作,库存量减1,然后库存量剩余99,这个时候线程A将数据写回到ES中,同时库存量的版本更新成version=2,这个时候线程B执行了一个下单操作,库存量减1,然后库存量剩余99,在写回ES之前,先获取下当前的库存量的版本号,当前库存量的版本号是version=2,和B手中的version=1的版本不同,这个时候B重新拉取版本2的数据,得到的库存量是99,执行了一个下单操作,库存量减1,然后库存量剩余98,在写回ES之前比对版本,没有问题,将数据写入回ES中。
乐观锁和悲观锁
- 悲观锁
- 优点:方便,直接加锁,对应用程序来说,透明,不需要做额外的操作;
- 缺点:并发能力低,同一时间只有一条线程操作数据;
- 乐观锁
- 优点:并发能力很高,不给数据加锁,大量线程并发操作
- 缺点:麻烦,每次更新的时候,都要先进行版本号的比对,然后重新加载数据,再次修改,再写;这个过程,可能重复好几次。
Elasticsearch核心知识篇(20)
图解Elasticsearch内部如何基于_version进行乐观锁并发控制
(1)_version元数据
PUT /test_index/test_type/6
{
"test_field": "test test"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "6",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
第一次创建一个document的时候,它的_version内部版本号就是1;以后,每次对这个document执行修改或者删除操作,都会对这个_version版本号自动加1;哪怕是删除,也会对这条数据的版本号加1
{
"found": true,
"_index": "test_index",
"_type": "test_type",
"_id": "6",
"_version": 4,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
我们会发现,在删除一个document之后,可以从一个侧面证明,它不是立即物理删除掉的,因为它的一些版本号等信息还是保留着的。先删除一条document,再重新创建这条document,其实会在delete version基础之上,再把_version号加1