1. 程式人生 > >65_elasticSearch 基於document鎖實現悲觀鎖併發控制

65_elasticSearch 基於document鎖實現悲觀鎖併發控制

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

相關文章