1. 并发控制的必要性
两个 Web 程序同时更新某个⽂档,如果缺乏有效的并发,会导致更改的数据丢失。ES 采⽤的是乐观并发控制,即假定冲突是不会发⽣的,不会阻塞正在尝试的操作。如果数据在读写中被修改,更新将会失败。应⽤程序决定如何解决冲突,例如重试更新,使⽤新的数据,或者将错误报告给⽤户。
2. ES 的乐观并发控制
ES 中的⽂档是不可变更的。如果你更新⼀个⽂档,会将就⽂档标记为删除,同时增加⼀个全新的⽂档。同时⽂档的 version 字段加 1。ES 存在内外部两种版本控制:
- 内部版本控制:if_seq_no + if_primary_term
- 使用外部版本:version + version_type=external,因为需要自行保存控制 version 的值,因此需要使用其他数据库作为数据存储。
下面演示内外版本控制,首先增加如下文档:
1 | PUT products/_doc/1 |
响应相关版本信息如下:
2.1 内部版本控制
现在我们即可根据上面的版本信息来更新文档,DSL 如下所示:
1 | PUT products/_doc/1?if_seq_no=0&if_primary_term=1 |
更新成功后,对应的 if_seq_no 和 version 值会累加,因此在并发情况下下,如果依旧采用上述更新语句就会发生报错。
重复更新由于版本信息不一致引发报错:
因此后面的更新需要采用最新的 if_seq_no 和 if_primary_term,例如:
1 | PUT products/_doc/1?if_seq_no=1&if_primary_term=1 |
2.2 外部版本控制
假设目前文档版本信息如下,其中 version 值为 1:
1 | { |
现在要进行更新操作,我们可以自行指定不同于且大于已有版本值 2 的任何其他值,这里我们指定为 3000。对比于内部版本控制,内部版本控制的 if_seq_no 和 if_primary_term 需严格采用已有文档的值。
1 | PUT products/_doc/1?version=3000&version_type=external |