-
版本控制:
在关系数据库管理系统里,悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)是一种并发控制的方法。当我们在读取一个数据前先锁定这一行,然后确保只有读取到数据的这个线程可以修改这一行数据。
ES使用的是乐观并发控制(又名”乐观锁”,Optimistic Concurrency Control,缩写”OCC)。 ES不会阻止某一数据的访问,然而,如果基础数据在我们读取和写入的间隔中发生了变化,更新就会失败,这时候就由程序来决定如何处理这个冲突。它可以重新读取新数据来进行更新,又或者将这一情况直接反馈给用户。
-
ES中的乐观锁
当我们发送get请求的时候 post /exindex/exindex/AVyAgBvA9tISzc84d_4i/返回值为:
{
"_index": "exindex",
"_type": "exindex",
"_id": "AVyAgBvA9tISzc84d_4i",
"_version": 1,
"found": true,
"_source": {
"school": "支付宝在扣款事务提交之前,向实时消息服务请求发送消息",
"name": "sony",
"age": "14"
}
}
-
请求url 带上本次版本号,并且指定docId,请求如下:这里_version是1,我们从ES中查询到一条记录,修改完成以后重新PUT建立索引,这时候我们要把_version作为一个参数传递过去,ES会用该参数和实际的数据进行比对,如果相同则进行重建索引,如果不同则返回错误信息。
curl -XPUT http://121.49.129.155:9200/exindex/exindex/AVyAgBvA9tISzc84d_4i?version=1 -d'
{
"name": "Jane",
"age": 80,
"school": "清华大学"
}'
文档修改结束后,返回成功后再次查询后得到的版本号已经变更完毕,_version已经变更为2
{
"_index": "exindex",
"_type": "exindex",
"_id": "AVyAgBvA9tISzc84d_4i",
"_version": 2,
"found": true,
"_source": {
"name": "Jane",
"age": 80,
"school": "清华大学"
}
}
当我们再次传递版本号为_version=1去尝试更新文档的时候,会报出版本冲突错误 "error":{"root_cause":[{"type":"version_conflict_engine_exception","reason":"[exindex][AVyAgBvA9tISzc84d_4i]: version conflict, current [2] ,当我们将版本号变更_version=2作为参数传递后,再次修改文档更新成功,版本号自动增加。
{
"_index": "exindex",
"_type": "exindex",
"_id": "AVyAgBvA9tISzc84d_4i",
"_version": 3,
"found": true,
"_source": {
"name": "Jane",
"age": 80,
"school": "北京大学"
}
}
-
使用外部版本号控制系统
一种比较常见的架构应用就是使用一些其他的数据库作为主应用数据库,es只是作为一个检索引擎使用,这也就不可避免的考虑到数据的一致性,数据的版本问题也就出现了。
如果你的数据库已经存在了版本号,或者是可以代表版本timestamp的时间戳。这时就可以在es的查询url后面添加version_type=external来使用这些号码。 注意:版本号码必须要是大于0小于9223372036854775807(Java中long的最大正值)的整数。
外部版本号与之前说的内部版本号在处理的时候有些不同。它不再检查_version是否与请求中指定的一致,而是检查是否小于指定的版本。如果请求成功,外部版本号就会被存储到_version中。
例如,创建一个包含外部版本号为5的新的文档,我们可以这样做: curl -XPOST '/testindex/fulltext/1?version=5&version_type=external' -d'{"title":"external log","content":"hello es"}'
查询返回的结果为:
{
"_index": "testindex",
"_type": "fulltext",
"_id": "1",
"_version": 5,
"found": true,
"_source": {
"title": "external log",
"content": "hello es"
}
}
现在我们更新文档将文档的版本号指定为8:
{
"_index": "testindex",
"_type": "fulltext",
"_id": "1",
"_version": 8,
"found": true,
"_source": {
"title": "external log second operate",
"content": "hello es"
}
}
版本号已经变更为"_version": 8,重新执行请求,返回的异常同样为版本冲突错误。
总结:在实际开发中根据不同的业务场景使用不同的版本控制,这个还是需要业务场景具体选择。