這裏主要記錄項目中使用基於redis的分佈式鎖所遇到的問題及解決方案;redis
個人業務場景是這樣的,咱們服務有庫存模塊,而個人服務又是多節點部署,要高峯期會存在庫存差別,後面分析問題以後,打算採用redis實現分佈式鎖(主要的緣由是服務已經集成了redis,不須要作額外的配置) 算法
不要感受奇怪,分佈式鎖怎麼會致使數據庫事務超時呢?
個人代碼大概是這樣的:數據庫
僞代碼 @Transaction(readOnly=false) void update(){ do{ redis=JedisUtil.getJedis(); flag = getLock(key,redis); if(flag){ update(); } }while(true) }
當你的key長時間獲取不到鎖,而且數據庫事務都有超時時間的限制,那麼就會出現數據庫事務超時問題;
解決方案併發
數據庫事務改成手動提交事務;分佈式
個人key的過時時間設置的是30s,若是30秒業務尚未執行完畢,鎖就會自動釋放,鎖釋放以後,其它線程又會去佔用鎖,一樣會致使問題的發生;
解決方案ide
最簡單的解決方案就是使用redisson;
若是非要用redis來解決的話,只能使用定時器去檢測key,若是說key還有2秒就快過時了,那麼再爲key從新設置30秒的過時時間;線程
分佈式鎖剛加上以後,生產出現一個問題,就是:redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
解決辦法
開始查代碼,發現是開發人員沒有對鏈接進行釋放; code
修復bug以後,又在線上跑了一段時間,又出現了redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
解決辦法事務
void update(){ do{ redis=JedisUtil.getJedis(); flag = getLock(key,redis); if(flag){ update(); }else{ // 釋放當前redis鏈接 // 因爲咱們的業務場景屬於比較耗時的業務型,因此在這裏休眠1000毫秒 redis.close(); sleep(1000); } }while(true) }
1.當前請求獲取鎖,若是獲取不到,則釋放當前鏈接,並休眠一會;
2.合理配置redis鏈接池大小,主要參考具體業務場景的併發量來設置;開發
回顧一下加鎖的參數:
set(key, vlue,"NX","PX", 30000);
其中:value,我使用它來表示加鎖人,必須是一個惟一的標識
好比:
A線程 key=test value=01
B線程 key=test value=02若是A線程執行業務耗時超過了鎖的持有時間,鎖會自動釋放;鎖自動釋放以後,線程B又加鎖成功,可是,此時A線程執行完業務邏輯以後,去釋放鎖,但A線程的鎖已經自動釋放了,若是沒有value來標識的話,它可能就會去釋放B線程的鎖;
這種狀況我沒有遇到,由於公司的redis集羣作了改進;
先說一下這種問題產生的緣由:
若是master節點因爲某緣由發生了主從切換,那麼就會出現鎖丟失的狀況;
解決辦法
須要經過使用redlock算法;或使用redisson,它有對redlock算法作封裝;