Elasticsearch基础(五)——Document并发控制
我们知道,在数据库中,如果多个客户端线程同时对一条记录进行增删改查,数据库会有锁机制保证并发访问的数据一致性。在Elasticsearch中,document就表示一条数据记录,那么Elasticsearch是如何对document的并发访问进行控制的呢?
本章,我们就以一个电商下单的案例为背景,介绍document的并发控制机制。
一、案例背景
我们现在有一个商品管理系统,底层采用Elasticsearch存储商品信息(包括商品ID、商品库存等)。现在,用户需要进行下单操作,流程如下:
- 用户浏览商品,此时发送请求到商品管理系统,查询商品信息;
- 用户下单购买;
- 支付成功后,发送请求到商品管理系统,扣减商品库存(库存-1)。
二、version版本号
Elasticsearch内部采用了版本号机制对document的并发修改进行控制 。所谓版本号,本质是一种乐观锁。
3.1 _version
我们往Elasticsearch写入document数据时,ES会自动为document生成一个版本号_version
,比如我们插入一条id为6的数据,返回结果里的_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)。
3.2 版本控制
我们来看下ES的数据版本控制流程,整个业务执行流程如下:
- 假设我们现在有两个线程A和B,同时读取到了商品信息,此时获取到的document的
_version
版本号是相同的,假设都是1; - A线程在本地将库存减1后,发送PUT更新请求,请求里带上了版本号
PUT /product/storage/1?version=1
; - ES收到请求后,对数据进行更新,然后将版本号+1;
- B线程在本地将库存减1后,发送PUT更新请求,请求里也带上了版本号1,
PUT /product/storage/1?version=1
; - ES收到请求后,发现id为1的document的版本号已经是2了,而B线程的更新请求里带的版本号还是1,两者不一样,于是拒绝更新,返回报错。
3.3 external version
Elasticsearch还提供了一个外部版本号的功能,就是说可以不用它提供的内部_version
版本号来进行并发控制,可以基于你自己维护的一个版本号来进行并发控制。
内部版本语法:
?version=1
自定义版本号语法:
?version=1&version_type=external
注意,当version_type=external
的时,只有当提供的version比Elasticsearch中的_version
大的时候,才能完成修改。
我们来看个例子,比如现在写入了这样一条记录,,可以看到_version
版本号是1:
PUT /test_index/test_type/8
{
"test_field": "test"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "8",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
然后,A线程先进行修改,带上了外部版本号2:
PUT /test_index/test_type/8?version=2&version_type=external
{
"test_field": "test client 1"
}
{
"_index": "test_index",
"_type": "test_type",
"_id": "8",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": false
}
接着,B线程也进行修改,带上了外部版本号2,可以看到报错了,因为当version_type=external
的时,只有当提供的version比Elasticsearch中的_version
大的时候,才能完成修改:
PUT /test_index/test_type/8?version=2&version_type=external
{
"test_field": "test client 2"
}
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[test_type][8]: version conflict, current version [2] is higher or equal to the one provided [2]",
"index_uuid": "6m0G7yx7R1KECWWGnfH1sw",
"shard": "1",
"index": "test_index"
}
],
"type": "version_conflict_engine_exception",
"reason": "[test_type][8]: version conflict, current version [2] is higher or equal to the one provided [2]",
"index_uuid": "6m0G7yx7R1KECWWGnfH1sw",
"shard": "1",
"index": "test_index"
},
"status": 409
}
三、总结
本章,我们讲解了document的并发控制原理,其核心就是基于内部的版本号机制,下一章,我们来看下document数据的路由原理。
感谢赞赏~
- 本文标签: Elasticsearch
- 版权声明: 本站原创文章,于2019年04月17日由ressmix发布,作者保留所有权利,未经作者允许,禁止转载和演绎!