首页 > 代码库 > 乐观的并发控制(optimistic concurrency control)

乐观的并发控制(optimistic concurrency control)

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