ElasticSearch 6.0 乐观锁
比如某件商品存货100件,用户1下单买走1件,剩余99件;与此同时用户2也下单买走1件,但是用户2不知道用户1已经下单,看到剩余商品仍然是99件。这样造成系统中显示商品总数比实际数量要多,这种情况在商业系统中肯定是不能容忍的。
乐观并发控制
执行 index , GET 和 delete 请求时,我们指出每个文档都有一个 _version (版本)号,当文档被修改时版本号递增。 Elasticsearch 使用这个 _version 号来确保变更以正确顺序得到执行。如果旧版本的文档在新版本之后到达,它可以被简单的忽略。
我们可以利用 _version 号来确保 应用中相互冲突的变更不会导致数据丢失。我们通过指定想要修改文档的 version 号来达到这个目的。 如果该版本不是当前版本号,我们的请求将会失败。
PUT website
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "website"
}
添加一个文档
PUT website/blog/1/_create
{
"title": "My first blog entry",
"text": "Just trying this out..."
}
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"created": true
}
响应体告诉我们,这个新创建的文档 _version 版本号是 1 。
现在假设我们想编辑这个文档:我们加载其数据到 web 表单中, 做一些修改,然后保存新的版本。
GET website/blog/1
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"title": "My first blog entry",
"text": "Just trying this out..."
}
}
现在,当我们尝试通过重建文档的索引来保存修改,我们指定 version 为我们的修改会被应用的版本
PUT /website/blog/1?version=1
{
"title": "My first blog entry",
"text": "Starting to get the hang of this..."
}
此请求成功,并且响应体告诉我们 _version 已经递增到 2 :
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"created": false
}
然而,如果我们重新运行相同的索引请求,仍然指定 version=1 , Elasticsearch 返回 409 Conflict HTTP 响应码,和一个如下所示的响应体:
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, current version [2] is different than the one provided [1]",
"index_uuid": "ekHPTnDgRH63lHUpvxqQBA",
"shard": "3",
"index": "website"
}
],
"type": "version_conflict_engine_exception",
"reason": "[blog][1]: version conflict, current version [2] is different than the one provided [1]",
"index_uuid": "ekHPTnDgRH63lHUpvxqQBA",
"shard": "3",
"index": "website"
},
"status": 409
}
响应体告诉我们在 Elasticsearch 中这个文档的当前 _version 号是 2 ,但我们指定的更新版本号为 1
我们现在怎么做取决于我们的应用需求。我们可以告诉用户说其他人已经修改了文档,并且在再次保存之前检查这些修改内容。 或者,在之前的商品 stock_count 场景,我们可以获取到最新的文档并尝试重新应用这些修改。
所有文档的更新或删除 API,都可以接受 version 参数,这允许你在代码中使用乐观的并发控制,这是一种明智的做法。
9.3 通过外部系统使用版本控制
一个常见的设置是使用其它数据库作为主要的数据存储,使用 Elasticsearch 做数据检索, 这意味着主数据库的所有更改发生时都需要被复制到 Elasticsearch
Elasticsearch 中通过增加 version_type=external 方式指定外部版本号,如果外部版本号是否大于当前文档版本,则可以执行更新操作。
例如,要更新一个新的具有外部版本号 5 的博客文章,我们可以按以下方法进行:
PUT /website/blog/2?version=5&version_type=external
{
"title": "My first external blog entry",
"text": "Starting to get the hang of this..."
}
在响应中,我们能看到当前的 _version 版本号是 5
{
"_index": "website",
"_type": "blog",
"_id": "2",
"_version": 5,
"result": "created",
"_shards": {
"total": 2,
"successful": 2,
"failed": 0
},
"created": true
}
当我们再次执行上面的外部版本号更新时,报错。因为外部版本号不大于当前版本号5.
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[blog][2]: version conflict, current version [5] is higher or equal to the one provided [5]",
"index_uuid": "ekHPTnDgRH63lHUpvxqQBA",
"shard": "2",
"index": "website"
}
],
"type": "version_conflict_engine_exception",
"reason": "[blog][2]: version conflict, current version [5] is higher or equal to the one provided [5]",
"index_uuid": "ekHPTnDgRH63lHUpvxqQBA",
"shard": "2",
"index": "website"
},
"status": 409
}
- Elasticsearch 6.0 性能调优
- ElasticSearch 6.0 Bulk批量操作
- ElasticSearch 6.0 搜索结果高亮
- ElasticSearch6.0配置IK分词插件
- Redis实现分布式锁
- Redis实现分布式锁
- Elasticsearch 6.3.0 SQL查询
- Elasticsearch score 评分计算
- elasticsearch清空索引缓存
- Elasticsearch使用索引别名
- Elasticsearch Aggregation聚合统计
- Elasticsearch多字段聚合
- Elasticsearch 5.0 深分页
- Elasticsearch使用searchAfter深度分页
- elasticsearch经纬度范围查询