65_elasticSearch 基於document鎖實現悲觀鎖併發控制
阿新 • • 發佈:2019-01-29
65_基於共享鎖和排他鎖實現悲觀鎖併發控制
更多幹貨
概述
1、共享鎖和排他鎖的說明
共享鎖
共享鎖:這份資料是共享的,然後多個執行緒過來,都可以獲取同一個資料的共享鎖,然後對這個資料執行讀操作
排他鎖
排他鎖:是排他的操作,只能一個執行緒獲取排他鎖,然後執行增刪改操作
讀寫鎖的分離*
如果只是要讀取資料的話,那麼任意個執行緒都可以同時進來然後讀取資料,每個執行緒都可以上一個共享鎖
但是這個時候,如果有執行緒要過來修改資料,那麼會嘗試上排他鎖,排他鎖會跟共享鎖互斥,也就是說,如果有人已經上了共享鎖了,那麼排他鎖就不能上,就得等
如果有人在讀資料,就不允許別人來修改資料
反之,也是一樣的
如果有人在修改資料,就是加了排他鎖
那麼其他執行緒過來要修改資料,也會嘗試加排他鎖,此時會失敗,鎖衝突,必須等待,同時只能有一個執行緒修改資料
如果有人過來同時要讀取資料,那麼會嘗試加共享鎖,此時會失敗,因為共享鎖和排他鎖是衝突的
如果有在修改資料,就不允許別人來修改資料,也不允許別人來讀取資料
2、共享鎖和排他鎖的實驗
第一步:有人在讀資料,其他人也能過來讀資料
judge-lock-2.groovy: if (ctx._source.lock_type == 'exclusive') { assert false }; ctx._source.lock_count++
POST /fs/lock/1/_update { "upsert": { "lock_type": "shared", "lock_count": 1 }, "script": { "lang": "groovy", "file": "judge-lock-2" } }
POST /fs/lock/1/_update
{
"upsert": {
"lock_type": "shared",
"lock_count": 1
},
"script": {
"lang": "groovy",
"file": "judge-lock-2"
}
}
GET /fs/lock/1 { "_index": "fs", "_type": "lock", "_id": "1", "_version": 3, "found": true, "_source": { "lock_type": "shared", "lock_count": 3 } }
就給大家模擬了,有人上了共享鎖,你還是要上共享鎖,直接上就行了,沒問題,只是lock_count加1
第二步、已經有人上了共享鎖,然後有人要上排他鎖
PUT /fs/lock/1/_create
{ "lock_type": "exclusive" }
排他鎖用的不是upsert語法,create語法,要求lock必須不能存在,直接自己是第一個上鎖的人,上的是排他鎖
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[lock][1]: version conflict, document already exists (current version [3])",
"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",
"shard": "3",
"index": "fs"
}
],
"type": "version_conflict_engine_exception",
"reason": "[lock][1]: version conflict, document already exists (current version [3])",
"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",
"shard": "3",
"index": "fs"
},
"status": 409
}
如果已經有人上了共享鎖,明顯/fs/lock/1是存在的,create語法去上排他鎖,肯定會報錯
第三步、對共享鎖進行解鎖
POST /fs/lock/1/_update
{
"script": {
"lang": "groovy",
"file": "unlock-shared"
}
}
連續解鎖3次,此時共享鎖就徹底沒了
每次解鎖一個共享鎖,就對lock_count先減1,如果減了1之後,是0,那麼說明所有的共享鎖都解鎖完了,此時就就將/fs/lock/1刪除,就徹底解鎖所有的共享鎖
第四步、上排他鎖,再上排他鎖
PUT /fs/lock/1/_create
{ "lock_type": "exclusive" }
其他執行緒
PUT /fs/lock/1/_create
{ "lock_type": "exclusive" }
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[lock][1]: version conflict, document already exists (current version [7])",
"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",
"shard": "3",
"index": "fs"
}
],
"type": "version_conflict_engine_exception",
"reason": "[lock][1]: version conflict, document already exists (current version [7])",
"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",
"shard": "3",
"index": "fs"
},
"status": 409
}
第五步、上排他鎖,上共享鎖
POST /fs/lock/1/_update
{
"upsert": {
"lock_type": "shared",
"lock_count": 1
},
"script": {
"lang": "groovy",
"file": "judge-lock-2"
}
}
{
"error": {
"root_cause": [
{
"type": "remote_transport_exception",
"reason": "[4onsTYV][127.0.0.1:9300][indices:data/write/update[s]]"
}
],
"type": "illegal_argument_exception",
"reason": "failed to execute script",
"caused_by": {
"type": "script_exception",
"reason": "error evaluating judge-lock-2",
"caused_by": {
"type": "power_assertion_error",
"reason": "assert false\n"
},
"script_stack": [],
"script": "",
"lang": "groovy"
}
},
"status": 400
}
第六步、解鎖排他鎖
DELETE /fs/lock/1