基於Redis實現分散式鎖,避免重複執行定時任務

晦若晨曦發表於2017-12-14

Spring提供了定時任務的功能,但是在多個例項的叢集中,會出現定時任務重複執行多次的情況。

使用Qutaz框架自帶的分散式定時任務可以很好的解決這個問題,但是講道理功能有些過於強大,對於需求不高,乃至可以一定程度上允許失誤的簡單任務中,價效比比較低。

使用task任務時,可以通過在redis等快取、資料庫中建立鎖來實現避免重複執行任務的功能。

基本思路如下:

  • 在redis中設定一個key作為鎖,值為時間戳
  • 嘗試用setnx方法直接設定鎖,若成功則直接執行任務。
  • 若設定失敗,使用getset方法獲取當前鎖並更新時間戳
  • 若獲取的時間戳在有效期內,則不執行任務,否則執行任務

當然這種實現方法是很粗糙的。對於高併發的頻繁定時任務處理很不完美。若執行失敗也會導致任務丟失。

本方案實現的處理場景是間隔比較長的資料處理定時任務。伺服器叢集也只有三個節點,上線執行效果良好。

簡要實現程式碼如下:

private boolean getLock(String key){
        String syncKey = "sync_lock_"+key;
        long curr = System.currentTimeMillis();
        String time = curr+"";
        long has = redisTemplate.setnx(syncKey,time);
        if(has == 1){
            return true;
        }else{
            String lock = redisTemplate.getSet(syncKey,time);
            if(lock == null){
                return true;
            }else{
                long l = NumberUtils.toLong(lock);
                //三十秒以內都算有效鎖
                return Math.abs(curr-l)<30000;
            }
        }
    }
複製程式碼

相關文章