Elasticsearch 并發修改樂觀鎖
來自: http://blog.csdn.net//jiao_fuyou/article/details/50482117
版本控制的一個例子
curl -XPOST http://localhost:9200/test/test/1 -d '{"msg": "test"}' { "_index": "test", "_type": "test", "_id": "1", "_version": 1, "created": true } curl -XPOST http://localhost:9200/test/test/1 -d '{"msg": "test"}' { "_index": "test", "_type": "test", "_id": "1", "_version": 2, "created": true } curl -XPOST http://localhost:9200/test/test/1?version=1 -d '{"msg": "test"}' { "error": "RemoteTransportException[[elasticsearch_226][inet[/172.16.18.226:9300]][indices:data/write/index]]; nested: VersionConflictEngineException[[test][0] [test][1]: version conflict, current [4], provided [1]]; ", "status": 409 }
提示:版本沖突
使用外部系統提供的版本號
Elasticsearch 的樂觀鎖,可以使用外部系統提供的版本號:
curl -XPOST http://localhost:9200/test/test/1?version=10&version_type=external -d '{"msg": "test"}' { "_index": "test", "_type": "test", "_id": "1", "_version": 10, "created": true }curl -XPOST http://localhost:9200/test/test/1?version=9&version_type=external -d '{"msg": "test"}' { "error": "VersionConflictEngineException[[test][0] [test][1]: version conflict, current [10], provided [9]]", "status": 409 }</pre>
這時Elasticsearch將只檢查提供的版本是否比當前保存在索引中的版本大(大多少不重要),如果是成功,否則失敗。
Elasticsearch內部版本號
在Elasticsearch中,更新請求實際上是分為兩個階段,獲取文檔,修改文檔,然后保存文檔。
那么當兩個更新請求同時要修改文檔的時候,系統樂觀的認為不會有兩個并發請求對一個系統操作。
文檔原本的版本為1,請求A獲取了version為1的文檔,請求B也獲取了version為1的文檔,然后請求A修改完文檔后,并且先執行了保存操作,這個時候,系統中的文檔version變為了2。
這個時候,B再執行保存操作的時候,告訴系統我要修改version為1的文檔。系統就會拋出一個錯誤,說文檔版本不匹配。然后這個錯誤由應用程序自己來進行控制。
這種機制在請求量大的時候會比悲觀鎖機制好。但是缺點是需要程序處理版本沖突錯誤,可能一般的方法是封裝更新操作,并且設置重復重試次數。注意這里的更新指的是:
curl -XPOST http://localhost:9200/test/test/1/_update -d '{"msg": "test"}'而不是:
curl -XPOST http://localhost:9200/test/test/1 -d '{"msg": "test"}'這個是create,這種在ES內部沒有樂觀鎖的概念,是直接覆蓋,這種想解決數據被覆蓋,就要顯示的帶著version
下面的程序,并發6個進程同時批量更新一個文檔,在結果能看到有的請求出錯了,返回版本沖突。
<?phprequire_once dirname(FILE).'/../shjf/vendor/autoload.php';
$client = new Elasticsearch\Client(['hosts' => ['172.16.18.226:9200']]);
for($i=0;$i<5;$i++){
if (pcntl_fork() == 0) break; }$params=[ 'index' => 'test', 'type' => 'test', 'body' => [], ];
for($i=0;$i<1;$i++){ $params['body'][] = ['update' => ['_id' => 111]]; $params['body'][] = ["doc" => ["id" => $i]]; } try { $result = $client->bulk($params); var_dump($result) . "\n"; } catch(Exception $e) { echo $e->getMessage() . "\n"; $info = $client->transport->getLastConnection()->getLastRequestInfo(); print_r($info); exit; }
echo "end\n";
?>
{ "took":1, "errors":true, "items":[ {"update": { "_index":"test", "_type":"test", "_id":"111", "status":409, "error":"VersionConflictEngineException[[test][0] [test][111]: version conflict, current [3], provided [2]]"} } ] }</pre>
參考資料:
- Elasticsearch官網:
<li><a href="/misc/goto?guid=4959663933904728856">https://www.elastic.co/guide/en/elasticsearch/guide/master/partial-updates.html</a></li> <li><a href="/misc/goto?guid=4959663933986648329">https://www.elastic.co/guide/en/elasticsearch/guide/master/optimistic-concurrency-control.html</a></li>
</ul> </li>
- 《Elasticsearch權威指南》處理沖突
</ul> </div>