64_數(shù)據(jù)建模實(shí)戰(zhàn)_基于全局鎖實(shí)現(xiàn)悲觀鎖并發(fā)控制
1、悲觀鎖的簡要說明
基于version的樂觀鎖并發(fā)控制
在數(shù)據(jù)建模,結(jié)合文件系統(tǒng)建模的這個(gè)案例,把悲觀鎖的并發(fā)控制,3種鎖粒度,都給大家仔細(xì)講解一下
最粗的一個(gè)粒度,全局鎖
/workspace/projects/helloworld
如果多個(gè)線程,都過來,要并發(fā)地給/workspace/projects/helloworld下的README.txt修改文件名
實(shí)際上要進(jìn)行并發(fā)的控制,避免出現(xiàn)多線程的并發(fā)安全問題,比如多個(gè)線程修改,純并發(fā),先執(zhí)行的修改操作被后執(zhí)行的修改操作給覆蓋了
get current version
帶著這個(gè)current version去執(zhí)行修改,如果一旦發(fā)現(xiàn)數(shù)據(jù)已經(jīng)被別人給修改了,version號跟之前自己獲取的已經(jīng)不一樣了; 那么必須重新獲取新的version號再次嘗試修改
上來就嘗試給這條數(shù)據(jù)加個(gè)鎖,然后呢,此時(shí)就只有你能執(zhí)行各種各樣的操作了,其他人不能執(zhí)行操作
第一種鎖:全局鎖,直接鎖掉整個(gè)fs index
2、全局鎖的上鎖實(shí)驗(yàn)
PUT /fs/lock/global/_create
{}
fs: 你要上鎖的那個(gè)index
lock: 就是你指定的一個(gè)對這個(gè)index上全局鎖的一個(gè)type
global: 就是你上的全局鎖對應(yīng)的這個(gè)doc的id
_create:強(qiáng)制必須是創(chuàng)建,如果/fs/lock/global這個(gè)doc已經(jīng)存在,那么創(chuàng)建失敗,報(bào)錯
利用了doc來進(jìn)行上鎖
/fs/lock/global /index/type/id --> doc
上鎖成功
{
"_index": "fs",
"_type": "lock",
"_id": "global",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
另外一個(gè)線程同時(shí)嘗試上鎖
PUT /fs/lock/global/_create
{}
這個(gè)時(shí)候就會提示上鎖失敗
{
"error": {
"root_cause": [
{
"type": "version_conflict_engine_exception",
"reason": "[lock][global]: version conflict, document already exists (current version [1])",
"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",
"shard": "2",
"index": "fs"
}
],
"type": "version_conflict_engine_exception",
"reason": "[lock][global]: version conflict, document already exists (current version [1])",
"index_uuid": "IYbj0OLGQHmMUpLfbhD4Hw",
"shard": "2",
"index": "fs"
},
"status": 409
}
如果失敗,就再次重復(fù)嘗試上鎖
執(zhí)行各種操作。。。
對文件更新
POST /fs/file/1/_update
{
"doc": {
"name": "README1.txt"
}
}
更新成功
{
"_index": "fs",
"_type": "file",
"_id": "1",
"_version": 2,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
這個(gè)時(shí)候刪除掉鎖,則另外一個(gè)線程就可以獲得鎖
DELETE /fs/lock/global
刪除鎖成功
{
"found": true,
"_index": "fs",
"_type": "lock",
"_id": "global",
"_version": 2,
"result": "deleted",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
另外一個(gè)線程,因?yàn)橹鞍l(fā)現(xiàn)上鎖失敗,反復(fù)嘗試重新上鎖,終于上鎖成功了,因?yàn)橹矮@取到全局鎖的那個(gè)線程已經(jīng)delete /fs/lock/global全局鎖了
PUT /fs/lock/global/_create
{}
重復(fù)上述動作,上鎖
{
"_index": "fs",
"_type": "lock",
"_id": "global",
"_version": 3,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"created": true
}
更新數(shù)據(jù),改回原來的名字
POST /fs/file/1/_update
{
"doc": {
"name": "README.txt"
}
}
更新成功
{
"_index": "fs",
"_type": "file",
"_id": "1",
"_version": 3,
"result": "updated",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
}
}
最后刪除鎖
DELETE /fs/lock/global
3、全局鎖的優(yōu)點(diǎn)和缺點(diǎn)
優(yōu)點(diǎn):操作非常簡單,非常容易使用,成本低
缺點(diǎn):你直接就把整個(gè)index給上鎖了,這個(gè)時(shí)候?qū)ndex中所有的doc的操作,都會被block住,導(dǎo)致整個(gè)系統(tǒng)的并發(fā)能力很低
上鎖解鎖的操作不是頻繁,然后每次上鎖之后,執(zhí)行的操作的耗時(shí)不會太長,用這種方式,方便