介紹
Redisson 是基于 Redis 實現的 Java 駐內存數據網格(In-Memory Data Grid),提供了分布式和可擴展的 Java 數據結構,如分布式鎖、分布式集合等。
【注意】如果需要重新實現redission,需要重新設置RedissionClient配置類
底層主要機制
(1)基于LUA腳本進行實現原子性
由于redission的鎖操作是需要原子性支持,例如加鎖,解鎖等,所以其底層實現是使用LUA腳本進行執行。
例如:
if?(redis.call('exists',?KEYS[1])?==?0)?thenredis.call('hincrby',?KEYS[1],?ARGV[2],?1);redis.call('pexpire',?KEYS[1],?ARGV[1]);return?nil;end;if?(redis.call('hexists',?KEYS[1],?ARGV[2])?==?1)?thenredis.call('hincrby',?KEYS[1],?ARGV[2],?1);redis.call('pexpire',?KEYS[1],?ARGV[1]);return?nil;end;return?redis.call('pttl',?KEYS[1]);
以上代碼是redission中實現加鎖代碼,主要流程是:
1)檢查鎖是否存在,不存在則創建且設置對應過期時間
2)如果鎖已經存在,則如果是屬于當前線程(通過ARGV[2]進行判斷是否為當前線程ID),是則增加重入次數
3)發現不是當前線程ID,表明其他人拿到鎖,則返回當前鎖被持有的剩余時間
(2)鎖可重入性設置
同一個線程可以獲取同一把鎖,通過HSET進行存儲鎖的持有線程和重入的次數
(3)看門狗自動續期機制
看門狗機制是應對由于操作未執行完畢,但是鎖快到期情況,因為人為不好判斷當前操作需要多久執行,所以使用看門狗機制,實現守護線程自動判斷。如果沒有設置對應的鎖檢查時間,則默認是10s自動檢查是否需要續期,而默認續期時間是30s。
實現代碼:
private?void?scheduleExpirationRenewal(final?long?threadId)?{Timeout?task =?commandExecutor.getConnectionManager().newTimeout(new?TimerTask()?{@Overridepublic?void?run(Timeout?timeout)?throws?Exception?{// 執行Lua腳本續期鎖renewExpirationAsync(threadId);}},?internalLockLeaseTime /?3,?TimeUnit.MILLISECONDS);}
而續期對象則可以實現自定義。自定義看門狗鎖:
核心續期操作是:
Config.setLockWatchhdogTimeout(60_000); ?//設置時間1分鐘
(4)聯鎖和紅鎖
Redission實現了MultiLock聯鎖和RedLock紅鎖,聯鎖就是多個獨立鎖的組合,必須全部獲取成功才算加鎖成功。而紅鎖是用于集群環境下,基于過半節點成功才算鎖的設置成功,用于緩解單節點故障問題。
單節點故障:由于在主節點加鎖,但是同步到從節點時候,主節點宕機,導致數據沒有同步到從節點,從節點此時沒有鎖,所以會導致相關問題。