iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0
Software Development

30 天學習 Elasticsearch系列 第 14

Day 14 Elasticsearch - Versioning 以及樂觀鎖

  • 分享至 

  • xImage
  •  

該文章同步發佈於:我的部落格

也歡迎關注我的 Facebook 以及 Instagram 接收軟體相關的資訊!

在讀取 Elasticsearch ( 以下簡稱 ES ) 的 document 時,一定會注意到一個 _version 的欄位。

這代表什麼呢?第一時間聯想到的會是版本紀錄,可以回朔 document 到某個版本,但其實不是!

這只是 ES 單純紀錄操作次數的一個方式,每一個 CUD 的操作都會讓 _version 加 1 的正整數,而預設值是 1。

而這個 _version 還有分成 external ( 外部 ) 以及 interval ( 內部 ) 兩種類型。

內部就是 ES 內建的,會隨著操作次數遞增,而外部呢?則是將控制權轉到我們的手上。

下面是一個利用 REST API 新增外部版本的方式:

其實就是帶上 version=你自訂的版本號&version_type=external 這樣的參數。

接著你就可以把 _version 的控制權掌握在你的應用程式上。

但說實在 _version 並沒有想像中的好用,因為他並不是真的版本控制,也沒辦法真的提供什麼實質的意義 ( 除非你的應用程式需要 )。

所以早期的 ES 其實是拿這個值並採用樂觀鎖的方式來解決 race condition 的問題。

Race Condition

當然,除了關聯式資料庫之外,任何可以同時接受大量請求的應用程式都會有 race condition 的問題,只是看競爭的資源是什麼。

假設有兩個請求同時對一個 document 進行更新。

在第一時間,兩個請求都是拿到庫存為 10 的值,而這時候第一個請求買了一個,所以將庫存更新為 9。

這時候第二個請求也把庫存更新成 9,對於 ES 來說,它本身並不知道這件事情是錯誤的,但這在商業邏輯上造成很大的問題,糟糕的使用者體驗,因為一定會有一個人買不到。

該怎麼解決呢?在早期,會帶上的 _version 的 payload 去更新 document,這樣第二個請求就會被阻擋下來,因為此時此刻的 _version 已經變成 2 了。

這樣就可以解決 race condition 的問題,接著該怎麼處理呢?

重試是一種策略,第二個請求可以再去讀取一次 inventory 拿到最新的 _version 接著就可以完成更新。

新的解決方式

剛剛一直提到 早期 這兩個字,是因為現在的 ES 可以用別的方式來執行樂觀鎖,也就是 上一篇文章 中所提到的 primary term 以及 sequence number 兩個值。

為什麼不繼續使用 _version

在 ES 這個巨大的分散式系統中,許多分片是散落在不同的節點上的,當嘗試只使用一個 _version 去執行樂觀鎖時,是不夠準確的,因為我們對於 node 或是 shard 的存活狀況一無所知。

_version 確實有可能在 primary shard 分割時,造成相同的 _version 擁有不同的內容,所以道理和 上一篇文章 中一樣,primary term 搭配 sequence number 就是讚!

使用 primary term 搭配 sequence number 可以算是現代 ES 的一種保障方式,可以確保 primary shard 以及操作步驟的準確性。

該怎麼做呢?

很簡單,其實和帶上 version 的 payload 一樣,只是變成帶上 if_primary_term= 以及 if_seq_no= 的 payload 去判斷就可以做到樂觀鎖而且更穩定。

下面是撞到鎖的畫面:

我帶上的 if_seq_no=19 是錯的,因為 _seq_no 已經到了 20,所以更新會失敗。

結語

_version 這個欄位確實是沒有什麼太大的意義,只能告訴你這個 document 經過了幾次的變動,僅此而已。

而關於 ES 使用樂觀鎖處理 race condition 的方式,現在還是使用 primary term 搭配 sequence number 是最好也是最保險的方式。


上一篇
Day 13 Elasticsearch - 寫入資料以及基礎的錯誤恢復機制
下一篇
Day 15 Elasticsearch - Update & Delete by query
系列文
30 天學習 Elasticsearch30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言