數(shù)據(jù)建模實(shí)戰(zhàn)之基于document鎖實(shí)現(xiàn)悲觀鎖并發(fā)控制

1瘩欺、對(duì)document level鎖,詳細(xì)的講解

全局鎖沫屡,一次性就鎖整個(gè)index饵隙,對(duì)這個(gè)index的所有增刪改操作都會(huì)被block住,如果上鎖不頻繁沮脖,還可以金矛,比較簡單

細(xì)粒度的一個(gè)鎖,document鎖勺届,顧名思義驶俊,每次就鎖你要操作的,你要執(zhí)行增刪改的那些doc免姿,doc鎖了饼酿,其他線程就不能對(duì)這些doc執(zhí)行增刪改操作了
但是你只是鎖了部分doc,其他線程對(duì)其他的doc還是可以上鎖和執(zhí)行增刪改操作的

document鎖胚膊,是用腳本進(jìn)行上鎖

POST /fs/lock/1/_update
{
  "upsert": { "process_id": 123 },
  "script": "if ( ctx._source.process_id != process_id ) { assert false }; ctx.op = 'noop';"
  "params": {
    "process_id": 123
  }
}

/fs/lock故俐,是固定的,就是說fs下的lock type紊婉,專門用于進(jìn)行上鎖
/fs/lock/id药版,比如1,id其實(shí)就是你要上鎖的那個(gè)doc的id喻犁,代表了某個(gè)doc數(shù)據(jù)對(duì)應(yīng)的lock(也是一個(gè)doc)
_update + upsert:執(zhí)行upsert操作

params槽片,里面有個(gè)process_id,process_id株汉,是你的要執(zhí)行增刪改操作的進(jìn)程的唯一id筐乳,比如說可以在java系統(tǒng)歌殃,啟動(dòng)的時(shí)候乔妈,給你的每個(gè)線程都用UUID自動(dòng)生成一個(gè)thread id,你的系統(tǒng)進(jìn)程啟動(dòng)的時(shí)候給整個(gè)進(jìn)程也分配一個(gè)UUID氓皱。process_id + thread_id就代表了某一個(gè)進(jìn)程下的某個(gè)線程的唯一標(biāo)識(shí)路召〔伲可以自己用UUID生成一個(gè)唯一ID

process_id很重要,會(huì)在lock中股淡,設(shè)置對(duì)對(duì)應(yīng)的doc加鎖的進(jìn)程的id身隐,這樣其他進(jìn)程過來的時(shí)候,才知道唯灵,這條數(shù)據(jù)已經(jīng)被別人給鎖了

assert false贾铝,不是當(dāng)前進(jìn)程加鎖的話,則拋出異常
ctx.op='noop'埠帕,不做任何修改

如果該document之前沒有被鎖垢揩,/fs/lock/1之前不存在,也就是doc id=1沒有被別人上過鎖; upsert的語法敛瓷,那么執(zhí)行index操作叁巨,創(chuàng)建一個(gè)/fs/lock/id這條數(shù)據(jù),而且用params中的數(shù)據(jù)作為這個(gè)lock的數(shù)據(jù)呐籽。process_id被設(shè)置為123锋勺,script不執(zhí)行。這個(gè)時(shí)候象征著process_id=123的進(jìn)程已經(jīng)鎖了一個(gè)doc了狡蝶。

如果document被鎖了庶橱,就是說/fs/lock/1已經(jīng)存在了,代表doc id=1已經(jīng)被某個(gè)進(jìn)程給鎖了牢酵。那么執(zhí)行update操作悬包,script,此時(shí)會(huì)比對(duì)process_id馍乙,如果相同布近,就是說,某個(gè)進(jìn)程丝格,之前鎖了這個(gè)doc撑瞧,然后這次又過來,就可以直接對(duì)這個(gè)doc執(zhí)行操作显蝌,說明是該進(jìn)程之前鎖的doc预伺,則不報(bào)錯(cuò),不執(zhí)行任何操作曼尊,返回success; 如果process_id比對(duì)不上酬诀,說明doc被其他doc給鎖了,此時(shí)報(bào)錯(cuò)

/fs/lock/1
{
  "process_id": 123
}
POST /fs/lock/1/_update
{
  "upsert": { "process_id": 123 },
  "script": "if ( ctx._source.process_id != process_id ) { assert false }; ctx.op = 'noop';"
  "params": {
    "process_id": 123
  }
}

script:ctx._source.process_id骆撇,123
process_id:加鎖的upsert請(qǐng)求中帶過來額proess_id

如果兩個(gè)process_id相同瞒御,說明是一個(gè)進(jìn)程先加鎖,然后又過來嘗試加鎖神郊,可能是要執(zhí)行另外一個(gè)操作肴裙,此時(shí)就不會(huì)block趾唱,對(duì)同一個(gè)process_id是不會(huì)block,ctx.op= 'noop'蜻懦,什么都不做甜癞,返回一個(gè)success

如果說已經(jīng)有一個(gè)進(jìn)程加了鎖了

/fs/lock/1
{
  "process_id": 123
}
POST /fs/lock/1/_update
{
  "upsert": { "process_id": 123 },
  "script": "if ( ctx._source.process_id != process_id ) { assert false }; ctx.op = 'noop';"
  "params": {
    "process_id": 234
  }
}
"script": "if ( ctx._source.process_id != process_id ) { assert false }; ctx.op = 'noop';"
ctx._source.process_id:123
process_id: 234

process_id不相等,說明這個(gè)doc之前已經(jīng)被別人上鎖了宛乃,process_id=123上鎖了; process_id=234過來再次嘗試上鎖悠咱,失敗,assert false征炼,就會(huì)報(bào)錯(cuò)

此時(shí)遇到報(bào)錯(cuò)的process乔煞,就應(yīng)該嘗試重新上鎖,直到上鎖成功

有報(bào)錯(cuò)的話柒室,如果有些doc被鎖了渡贾,那么需要重試

直到所有鎖定都成功,執(zhí)行自己的操作雄右。空骚。。

釋放所有的鎖

2擂仍、上document鎖的完整實(shí)驗(yàn)過程

scripts/judge-lock.groovy: if ( ctx._source.process_id != process_id ) { assert false }; ctx.op = 'noop';
POST /fs/lock/1/_update
{
  "upsert": { "process_id": 123 },
  "script": {
    "lang": "groovy",
    "file": "judge-lock", 
    "params": {
      "process_id": 123
    }
  }
}
{
  "_index": "fs",
  "_type": "lock",
  "_id": "1",
  "_version": 1,
  "result": "created",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}
GET /fs/lock/1
{
  "_index": "fs",
  "_type": "lock",
  "_id": "1",
  "_version": 1,
  "found": true,
  "_source": {
    "process_id": 123
  }
}
POST /fs/lock/1/_update
{
  "upsert": { "process_id": 234 },
  "script": {
    "lang": "groovy",
    "file": "judge-lock", 
    "params": {
      "process_id": 234
    }
  }
}
{
  "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",
      "caused_by": {
        "type": "power_assertion_error",
        "reason": "assert false\n"
      },
      "script_stack": [],
      "script": "",
      "lang": "groovy"
    }
  },
  "status": 400
}
POST /fs/lock/1/_update
{
  "upsert": { "process_id": 123 },
  "script": {
    "lang": "groovy",
    "file": "judge-lock", 
    "params": {
      "process_id": 123
    }
  }
}
{
  "_index": "fs",
  "_type": "lock",
  "_id": "1",
  "_version": 1,
  "result": "noop",
  "_shards": {
    "total": 0,
    "successful": 0,
    "failed": 0
  }
}
POST /fs/file/1/_update
{
  "doc": {
    "name": "README1.txt"
  }
}
{
  "_index": "fs",
  "_type": "file",
  "_id": "1",
  "_version": 4,
  "result": "updated",
  "_shards": {
    "total": 2,
    "successful": 1,
    "failed": 0
  }
}
POST /fs/_refresh 
GET /fs/lock/_search?scroll=1m
{
  "query": {
    "term": {
      "process_id": 123
    }
  }
}
{
  "_scroll_id": "DnF1ZXJ5VGhlbkZldGNoBQAAAAAAACPkFjRvbnNUWVZaVGpHdklqOV9zcFd6MncAAAAAAAAj5RY0b25zVFlWWlRqR3ZJajlfc3BXejJ3AAAAAAAAI-YWNG9uc1RZVlpUakd2SWo5X3NwV3oydwAAAAAAACPnFjRvbnNUWVZaVGpHdklqOV9zcFd6MncAAAAAAAAj6BY0b25zVFlWWlRqR3ZJajlfc3BXejJ3",
  "took": 51,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 1,
    "hits": [
      {
        "_index": "fs",
        "_type": "lock",
        "_id": "1",
        "_score": 1,
        "_source": {
          "process_id": 123
        }
      }
    ]
  }
}
PUT /fs/lock/_bulk
{ "delete": { "_id": 1}}
{
  "took": 20,
  "errors": false,
  "items": [
    {
      "delete": {
        "found": true,
        "_index": "fs",
        "_type": "lock",
        "_id": "1",
        "_version": 2,
        "result": "deleted",
        "_shards": {
          "total": 2,
          "successful": 1,
          "failed": 0
        },
        "status": 200
      }
    }
  ]
}
POST /fs/lock/1/_update
{
  "upsert": { "process_id": 234 },
  "script": {
    "lang": "groovy",
    "file": "judge-lock", 
    "params": {
      "process_id": 234
    }
  }
}

process_id=234上鎖就成功了

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末囤屹,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子逢渔,更是在濱河造成了極大的恐慌肋坚,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肃廓,死亡現(xiàn)場(chǎng)離奇詭異智厌,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盲赊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門铣鹏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人哀蘑,你說我怎么就攤上這事诚卸。” “怎么了绘迁?”我有些...
    開封第一講書人閱讀 157,720評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵合溺,是天一觀的道長。 經(jīng)常有香客問我缀台,道長棠赛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮恭朗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘依疼。我一直安慰自己痰腮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評(píng)論 6 386
  • 文/花漫 我一把揭開白布律罢。 她就那樣靜靜地躺著膀值,像睡著了一般。 火紅的嫁衣襯著肌膚如雪误辑。 梳的紋絲不亂的頭發(fā)上沧踏,一...
    開封第一講書人閱讀 49,879評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音巾钉,去河邊找鬼翘狱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛砰苍,可吹牛的內(nèi)容都是我干的潦匈。 我是一名探鬼主播,決...
    沈念sama閱讀 39,028評(píng)論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼赚导,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼茬缩!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起吼旧,我...
    開封第一講書人閱讀 37,773評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤凰锡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后圈暗,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體掂为,經(jīng)...
    沈念sama閱讀 44,220評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評(píng)論 2 327
  • 正文 我和宋清朗相戀三年员串,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了菩掏。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,697評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡昵济,死狀恐怖智绸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情访忿,我是刑警寧澤瞧栗,帶...
    沈念sama閱讀 34,360評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站海铆,受9級(jí)特大地震影響迹恐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卧斟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評(píng)論 3 315
  • 文/蒙蒙 一殴边、第九天 我趴在偏房一處隱蔽的房頂上張望憎茂。 院中可真熱鬧,春花似錦锤岸、人聲如沸竖幔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拳氢。三九已至,卻和暖如春蛋铆,著一層夾襖步出監(jiān)牢的瞬間馋评,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評(píng)論 1 266
  • 我被黑心中介騙來泰國打工刺啦, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留留特,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,433評(píng)論 2 360
  • 正文 我出身青樓玛瘸,卻偏偏與公主長得像磕秤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子捧韵,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容