Elasticsearch笔记第十篇

179 阅读4分钟

Elasticsearch核心知识篇(18)

深度图解剖析Elasticsearch并发冲突问题

image.png

自己的理解:

  • 出现的问题:
    • 和线程互相争抢数据一样,当两个线程同时访问到ES的同一个数据的时候,我们的数据(假设是剩余量)返回给线程A和线程B的数字是一致的,都是100件,当我们的线程A的用户下了一单,此时剩余量就变成了99件,写回ES,剩余量数据真实为99,但是线程B在刚才的过程中获取到的存量是100,此时B也下了一单,此时B计算完的剩余量就变成了99件,但是实际上的真实的剩余量是98,线程B将数据99写回到ES中,这样数据的同步中出现问题。这个和线程冲突是一样的

Elasticsearch核心知识篇(19)

深度图解剖析悲观锁与乐观锁两种并发控制方案

image.png

自己的理解:

  • 悲观锁:
    • 整个悲观锁的并发控制流程:首先线程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进行乐观锁并发控制

image.png

(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