• Elasticsearch深入理解(六) —— 如何处理并发冲突


    问:乐观并发控制-版本号形式的锁,在更新数据的时候是否会阻塞?

    答:不会阻塞。类似于 CAS算法 中ABA问题的解决方案。

    业务场景:想象一下我们使用Elasticsearch存储大量在线商店的库存信息。每当销售一个商品,Elasticsearch中的库存就要减一。想象两个同时运行的web进程,两者同时处理一件商品的订单时,并发情况下会造成“幻读”,并且变化越频繁,越容易丢失我们的修改:

                                

    ElasticSearch内部如何基于_version进行乐观锁并发控制?

    1._version元数据

    1.1 向指定index存入数据:

    1

    2

    3

    4

    5

    6

    7

    8

    PUT student/student/5

    {

      "id":4,

      "name":"流川枫",

      "age":18,

      "address":"东京大学",

      "gender":"男"

    }

    1.2 返回信息:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    {

      "_index" "student",

      "_type" "student",

      "_id" "5",

      "_version" 1,

      "result" "created",

      "_shards" : {

        "total" 2,

        "successful" 1,

        "failed" 0

      },

      "_seq_no" 8,

      "_primary_term" 3

    }

         第一次创建一个document的时候 ,它内部的版本号就是1;此后,每次对这个document执行修改或者删除操作,都会对这个_version版本号自动加1;

    1.3 多次修改后的查询语句及结果:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    # query

    GET student/_search

    {

      "query": {

        "match": {

          "id"5

        }

      }

      "version"true

    }

    # result

    {

      "took" 1,

      "timed_out" false,

      "_shards" : {

        "total" 3,

        "successful" 3,

        "skipped" 0,

        "failed" 0

      },

      "hits" : {

        "total" 1,

        "max_score" 1.0,

        "hits" : [

          {

            "_index" "student",

            "_type" "student",

            "_id" "5",

            "_version" 9,

            "_score" 1.0,

            "_source" : {

              "id" 5,

              "name" "流川枫",

              "age" 18,

              "address" "东京大学",

              "gender" "男"

            }

          }

        ]

      }

    }

    1.4 执行删除当前document的语句已返回结果:

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    DELETE student/student/5

    # 删除document = 5 的数据

    # 返回结果

    {

      "_index" "student",

      "_type" "student",

      "_id" "5",

      "_version" 11,

      "result" "deleted",

      "_shards" : {

        "total" 2,

        "successful" 1,

        "failed" 0

      },

      "_seq_no" 18,

      "_primary_term" 3

    }

            由上述返回结果可以发现,在执行 DELETE student/student/5 之后,返回的处理结果中存在 : "result" : "deleted" (证明执行的是删除操作) 、 "_version" : 11 (证明当前document已经执行了11次)。此时可以从侧面证明,ElasticSearch在删除某一条document数据时,不是立即物理删除掉的。因为它的一些版本号等信息还是保留着的。先删除一条document,再重新创建这条document,其实会在delete version基础之上,再把version号加1.

    elasticsearch内部的多线程异步并发修改时是基于自己的_version版本号进行乐观锁并发控制的。

    2.基于external version进行乐观锁并发控制

            es提供了一个feature,就是说,你可以不用它提供的内部_version版本号来进行并发控制,可以基于你自己维护的一个版本号来进行并发控制。举个列子,假如你的数据在mysql里也有一份,然后你的应用系统本身就维护了一个版本号,不管是什么自己生成的还是程序控制的。这个时候,你进行乐观锁并发控制的时候,可能并不是想要用es内部的_version来进行控制,而是用你自己维护的那个version来进行控制。

    1

    2

    ......?version=1

    ......?version=1&version_type=external

           version_type=external唯一的区别在于:_version,只有当你提供的version与es中的_version一模一样的时候,才可以进行修改,只要不一样,就报错;当version_type=external的时候,只有当你提供的version比es中的_version大的时候,才能完成修改。

    1

    2

    3

    es,_version=1,?version=1 -- 更新成功

    es,_version=1,?version>1&version_type=external -- 更新成功

    ?version=2&version_type=external -- 更新成功

  • 相关阅读:
    应用架构的演进 | 使用无服务器构建业务弹性
    23【状态设计模式】
    华为云云耀云服务器L实例使用教学|Unbelievable, 带你用云服务器部署Windows12
    Golang通道(Channel)原理解析
    痞子衡嵌入式:从功耗测试角度了解i.MXRTxxx系列片内SRAM分区电源控制
    RabbitMQ初步到精通-第三章-RabbitMQ面板及环境搭建
    set容器
    我的私人笔记(zookeeper分布式安装)
    肖sir__linux讲解(2.0)
    Unity UGUI 循环滑动列表实现思路及简单代码实现
  • 原文地址:https://blog.csdn.net/weixin_41860630/article/details/126467567