mysql集群怎么实现状态机_分布式中的状态机
全局鎖
在系統訪問單個資源時或多或少都會要使用到鎖,如Java的Lock等,但多個系統訪問資源,或在集群中各個實例需要訪問資源時,就需要建立全局的鎖,這里講三種全局鎖的方法。
數據庫
利用ACID
使用關系型數據庫的ACID可以創建一個鎖
UPDATE LOCKTABLE SET INSTANCE= WHERE RESOURCE=XXXX AND INSTANCE IS NULL;
當返回更新了相應記錄后就代表獲得了鎖
對應的可以使用以下sql來釋放獲得的鎖
UPDATE LOCKTABLE SET INSTANCE='' WHERE RESOURCE=XXXX AND INSTANCE=;
上面的方法看上去很好,但是當獲得鎖的實例宕機那么這個鎖就一直被占用著
利用行鎖
為了解決實例非正常退出而沒有釋放鎖可以使用數據庫(ORACLE)的行鎖
SELECT 1 FROM LOCKTABLE WHERE RESOURCE=XXXX FOR UPDATE;
這樣在commit/rollback之前就能持有這個鎖,如果調用方斷開,數據庫也會自動rollback。可以使用NOWAIT+循環查詢的方式防止阻塞
REDIS
數據庫固然可以,但應對大量的資源需要長期持有大量鎖也不是很恰當,下面看下Redis如何創建全局鎖
SETNX
SETNX是set if not exist的縮寫,也就是當值不存在時再進行賦值
SETNX lock.resource 1
//hold the lock
DEL lock.resource
以上偽代碼簡單演示了如何獲得鎖和釋放鎖,和數據庫的方法一樣,這種方法同同樣存在實例宕機的風險導致死鎖
SET
可惜Redis上沒有像數據庫中的for update。一個替代方法是使用expire。即給鎖設定一個超時時間,如果時間超過自動釋放鎖,這里超時時間要合適不能過長讓其他實例空等,也不能過短實例沒有結束就自動釋放了。
幸運的是Redis 2.6.12之后SET命令可以使用expire和notexist
SET lock.resource NX EX timeout
//hold the lock
WATCH lock.resource
GET lock.resource
MULTI
if(getResult==)
DEL lock.resource
EXEC
使用watch/multi確保競態條件
RedLock
防止單Redis不可用,可以使用多個redis,在半數以上節點獲得鎖的情況下代表獲得鎖,否則就釋放所有獲得的鎖。
Redison
Zookeeper
redis的不足就是只能通過expire來控制鎖持有者失聯的情況。
zookeeper在這方面就有一定的優勢,再加上zookeeper天生自帶集群,在可靠性上優于redis
zookeeper可以創建ephemeral節點,當客戶端斷開連接節點自動刪除,可以創建一個節點,最小值持有當前鎖
create -e -s /LOCK/RESOURCE/REQUEST 1
之后判斷如果當前節點最小就獲得鎖,如果沒有就在前一個節點上加watch,在watch中再進行判斷,這樣就實現了等待獲得鎖的隊列。
總結
全局鎖在集群上的應用有不少,最常見的就如集群內CRON任務執行的管理等。這里主要介紹的還是悲觀鎖,在某些場景也可以使用樂觀鎖進行優化。
總結
以上是生活随笔為你收集整理的mysql集群怎么实现状态机_分布式中的状态机的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 噫吁嚱!文言文亦能编程!此诚年度最骚语言
- 下一篇: cnvd与cnnvd区别_漏洞都是怎么编