1. 程式人生 > 其它 >java-分散式鎖三種實現方式介紹

java-分散式鎖三種實現方式介紹

鎖是計算機協調多個程序或執行緒併發訪問某一資源的機制,為保證資料的一致性,需要對併發操作進行控制,因此產生了鎖。同時鎖機制也為mysql各個隔離級別提供了保證,鎖衝突也是影響資料庫併發效能的一個重要因素。

併發事務訪問

  1. 讀-讀情況:併發事務相繼讀取相同的記錄,讀取操作本事並不會對記錄有任何影響,不會引起問題。
  2. 寫-寫情況:併發事務相繼對相同記錄做出改動,可能發生髒寫問題,在多個未提交事務相繼對一條記錄做改動時候,需要它們排隊執行,排隊的過程實際上鎖實現的。所謂的鎖實際是一個記憶體中的結構,一開始沒有鎖結構和記錄進行關聯,當一個事務想對這條記錄做改動時,首先看記憶體中有沒有與這條記錄關聯的鎖機構,如果沒有就會在在記憶體中生成一個鎖結構與之關聯。
  • 不加鎖: 不需要在記憶體中生成對應的鎖結構,可以直接執行操作
  • 加鎖成功: 在記憶體中生成了對應的鎖結構,is_waiting 屬性為FALSE,事務可以繼續執行操作。
  • 加鎖失敗:在記憶體中生成了對應的鎖結構,is_waiting 屬性為true,事務需要等待,不可以繼續執行操作。
  1. 讀-寫、寫-讀情況:一個事務執行讀取操作,另一個事務進行改動操作。 可能發生髒讀、不可重複讀、幻讀

併發問題的解決方案:怎麼解決髒讀、幻讀、不可重複讀這些問題?

  • 讀操作利用MVCC, 寫操作進行加鎖,所謂的MVCC就是生成一個readview,通過readview找到符合條件的記錄版本(歷史版本由undo log構建),查詢語句只能讀到在生成readview之前已經提交的事務,在生成readview之前未提交的事務或者之後才開啟的事務所做的更改是看不到,而寫操作肯定針對的是最新版本的記錄,讀寫操作並不衝突。
    普通的select語句在RC 和RR 隔離級別下會使用到MVCC讀取記錄;
    在RC隔離級別下,一個事務在執行過程中每次執行select操作都會生成一個readview,保證了事務不可以讀取到未提交的事務所做的更改,避免了髒讀現象
    在RR隔離級別下,一個事務在執行過程只有第一次執行select語句會生成一個readview,之後的select語句都複用這個readview,避免了不可重複讀以及幻讀的現象。
  • 讀寫操作均採用加鎖,如果業務場景不允許讀取記錄的舊版本,每次都必須讀取記錄的新版本,讀取記錄就需要加鎖操作
    幻讀問題的產生是因為當前事務讀取了一個範圍的記錄,然後另外的事務向該範圍插入了新紀錄,當前事務再次讀取到了新插入的記錄,讀取的時候加鎖有麻煩,不知道給誰加鎖。

鎖的分類

操作型別:讀鎖、寫鎖

  • 讀鎖:也稱為共享鎖,針對同一份資料,多個事務的讀操作可以同時進行而不會相互影響阻塞
  • 寫鎖:也稱為排他鎖,當前寫操作沒有完成前,會阻斷其他寫鎖和讀鎖,在給定的時間內,只有一個事務能執行寫入,防止其他使用者讀取正在寫入的同一資源。

操作粒度:表鎖、頁鎖、行鎖

  • 表級別的S鎖、X鎖 : 這個過程其實同在server層使用一種稱之為元資料鎖(Metadata Locks)的結構實現的。 MyISAM在執行select語句前,會給設計的所有表加讀鎖,在執行增刪改操作前,給涉及的表加寫鎖,InnoDB是不會的。
  • 意向鎖: 意向共享鎖,事務有意向對錶中的某些行加共享鎖;意向排他鎖,事務有意向對錶中的某些行加排他鎖。意向鎖是由儲存引擎自己維護的,使用者無法手動操作意向鎖,在為資料行加共享排他鎖之前,會先獲取該資料的行所在資料表的對應意向鎖。意向鎖就是為了給更大一級別的空間示意裡面是否已經上過鎖。
  • 自增鎖: 是當向使用含有自增列的表中插入資料時需要獲取的一種特殊的表級鎖,一個事務在持有自增鎖的過程中,其它事務的插入語句都要被阻塞,保證一個語句中的分配的遞增值是連續的。
  • 元資料鎖:保證讀寫的正確性,當對一個表做增刪改查操作時候,加MDL鎖;當對錶做結構變更操作時候,加MDL寫鎖。
  • 記錄鎖:僅僅把一條記錄上鎖。
  • 間隙鎖: mysql在RR隔離級別下解決幻讀,一種是MVCC,一種是加鎖。例在ID為8的記錄上加一個gap鎖,以為著不允許別的事務在ID為8的記錄的間隙插入新記錄。gap鎖的提出僅僅是為了防止插入幻影記錄而提出。
  • 臨鍵鎖: 既想鎖住某條記錄,又想阻止其他事務在該記錄前邊的間隙插入新紀錄,新增Next-Key Locks ,在事務級別為RR使用的資料庫鎖。
  • 插入意向鎖:插入意向鎖是一種gap鎖,在插入一條記錄前,由insert操作產生的一種間隙鎖。
  • 頁鎖:頁鎖的開銷結餘表鎖和行鎖之間,會出現死鎖現象。

對待態度: 樂觀鎖、悲觀鎖

  1. 樂觀鎖:使用於讀操作多的場景,不採用資料庫自身的鎖機制,通過程式實現。 版本號機制或者時間戳機制
  2. 悲觀鎖:使用於寫操作多的場景,

加鎖方式: 顯示鎖、隱式鎖

  1. 隱式鎖:即一個事務對新插入的記錄可以不顯示的加鎖,但是由於事務ID的存在,相當於加鎖
  2. 顯示鎖:通過特定的語句進行加鎖,稱為顯示鎖。 select ... lock in share mode (for update)

鎖的記憶體結構

對一條記錄加鎖本質上就是在記憶體中建立一個鎖結構與之關聯,在決定對不同記錄加鎖時候,如果符合以下記錄會放到一個鎖結構中,
在同一個事務中進行加鎖操作,被加鎖的記錄在同一個頁面中,加鎖的型別是一樣的,等待狀態是一樣的。

鎖所在事務資訊 索引資訊 表鎖、行鎖資訊 type—mode 其他資訊 一堆位元位
在記憶體結構中是一個指標,通過指標找到更多資訊 對於行鎖需要記錄加鎖的記錄屬於哪個索引 表鎖記錄和行鎖不同 鎖的模式 、型別、行鎖的具體型別 為了更好管理系統執行過程中生成的各種鎖結構而設計的各自hash表和連結串列 行鎖結構的話,末尾放置了一堆位元位

鎖監控