ES是分布式的。当document被create,update,或者delete,这个document的新版本就会冗余到cluster的其他node中。ES是异步和并发的,意味着冗余请求也是并行进行的,并且请求到达也是无次序的。因此需要一个方式保证老版本的document不能重写新版本的数据。
如上所述,当我们讨论index,get和delete请求,我们指出每个document都有一个_version号,这个号码随着document的变化而增长。ES使用这个_version保证document的变化在一个正确的顺序上执行,如果一个旧版本的document落后于新的版本,这个旧版本就会被忽略。
我们能利用这个_version号保证由我们的应用造成的数据冲突不会导致数据丢失。通过指定想要修改的document的version号达到这个目的。如果指定的version不再是当前的版本,这个请求将会失败。
创建一个新的blog:
PUT /website/blog/1/_create
{
"title":"My first blog entry",
"text": "Just trying this out..."
}
返回的消息体告诉我们,新创建的document的_version号是1,设想一下,我们要编辑这个document:我们把这个数据加载到web form,作出修改,然后保存。
首先检索这个document:
GET /website/blog/1
这个相应的消息体包括了_version号码
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version":1,
"found": true,
"_source": {
"title":"My first blog entry",
"text": "Just trying this out..."
}
}
现在,通过重新index这个document来保存修改,指定我们要修改的version:
PUT /website/blog/1?version=1
{
"title":"My first blog entry",
"text": "Starting to get the hang of this..."
}
标记1表示试图更新的document的version是1,如果document是1就更新成功。
这个请求是成功的,相应消息体表明_version已经增加到了2:
{
"_index": "website",
"_type": "blog",
"_id": "1",
"_version":2
"created": false
}
然而,如果我们再次重复执行并且依然指定version=1,ES将会用409这个HTTP消息头应答这个冲突,并且消息体如下:
{
"error":"VersionConflictEngineException[[website][2][blog][1]:
version conflict, current [2], provided [1]]",
"status":409
}
这个表明当前的document的_version是2,但是我们要更新的是1。
我们要做的事情依赖于应用的需求。我们可以告诉用户有人已经修改了这个document,如果想尝试修改这个数据就要重新审视新的修改,当然,我们也可以检索这个document并且向用户报告这个改变,就像上面提到的stock_count一样。
所有的API,无论是update或者delete一个document,都可以携带一个version参数,这个允许你应用乐观的并发控制你代码中最有意义的部分。
使用其他系统的version
一个常见的现象就是,使用其他数据库作为主数据库,ES作为搜索数据库,当主数据库中的数据发生变化,需要把这些变化复制到ES中,如果多个进程同步的的相应这个数据,那么这个数据就会出现上述的并发问题。
如果主数据库已经有version号,或者类似于时间戳的能作为version号的字段,在ES中也可以通过使用version_type=external使用这个字段作为version_号。version必须是比零大的整形,并且要比9.2e+18小——Java中的正long型数据。
其他系统version号使用起来和上面的略有不同——ES中检查的请求中的version号要和数据库中的version要一样——ES中检查请求中的external的version要比数据库中的version要大。如果请求成功,这个大的external就会写入作为document的新的version。
扩展的version不但能用在index,delete,而起能用到创建一个新的cocument。
例如使用external version是5创建一个新的blog:
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,
"created": true
}
然后指定version是10进行更新:
PUT /website/blog/2?version=10&version_type=external
{
"title":"My first external blog entry",
"text": "This is a piece of cake..."
}
相应成功后_version就成了10:
{
"_index": "website",
"_type": "blog",
"_id": "2",
"_version":10,
"created": false
}
就像以前看到的一样,如果你重新执行这个请求,就会因为冲突而导致失败,因为请求指定的external version要不比当前的高。
原文:http://www.elasticsearch.org/guide/en/elasticsearch/guide/current/optimistic-concurrency-control.html#optimistic-concurrency-control
乐观的并发控制(optimistic concurrency control),布布扣,bubuko.com
乐观的并发控制(optimistic concurrency control)
原文地址:http://www.cnblogs.com/blog1350995917/p/3730975.html