0%

ElasticSearch-处理并发读写

1. 并发控制的必要性

两个 Web 程序同时更新某个⽂档,如果缺乏有效的并发,会导致更改的数据丢失。ES 采⽤的是乐观并发控制,即假定冲突是不会发⽣的,不会阻塞正在尝试的操作。如果数据在读写中被修改,更新将会失败。应⽤程序决定如何解决冲突,例如重试更新,使⽤新的数据,或者将错误报告给⽤户。

2. ES 的乐观并发控制

ES 中的⽂档是不可变更的。如果你更新⼀个⽂档,会将就⽂档标记为删除,同时增加⼀个全新的⽂档。同时⽂档的 version 字段加 1。ES 存在内外部两种版本控制:

  • 内部版本控制:if_seq_no + if_primary_term
  • 使用外部版本:version + version_type=external,因为需要自行保存控制 version 的值,因此需要使用其他数据库作为数据存储。

下面演示内外版本控制,首先增加如下文档:

1
2
3
4
5
PUT products/_doc/1
{
"title":"iphone",
"count":100
}

响应相关版本信息如下:

2.1 内部版本控制

现在我们即可根据上面的版本信息来更新文档,DSL 如下所示:

1
2
3
4
5
PUT products/_doc/1?if_seq_no=0&if_primary_term=1
{
"title":"iphone",
"count":101
}

更新成功后,对应的 if_seq_no 和 version 值会累加,因此在并发情况下下,如果依旧采用上述更新语句就会发生报错。

重复更新由于版本信息不一致引发报错:

因此后面的更新需要采用最新的 if_seq_no 和 if_primary_term,例如:

1
2
3
4
5
PUT products/_doc/1?if_seq_no=1&if_primary_term=1
{
"title":"iphone",
"count":102
}

2.2 外部版本控制

假设目前文档版本信息如下,其中 version 值为 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"_index" : "products",
"_type" : "_doc",
"_id" : "1",
"_version" : 2,
"_seq_no" : 1,
"_primary_term" : 1,
"found" : true,
"_source" : {
"title" : "iphone",
"count" : 101
}
}

现在要进行更新操作,我们可以自行指定不同于且大于已有版本值 2 的任何其他值,这里我们指定为 3000。对比于内部版本控制,内部版本控制的 if_seq_no 和 if_primary_term 需严格采用已有文档的值。

1
2
3
4
5
PUT products/_doc/1?version=3000&version_type=external
{
"title":"iphone",
"count":102
}
------ 本文结束------