如何正確實施redis分佈式鎖
點關注不迷路,歡迎再訪!
精簡博客內容,儘量已行業術語來分享。
努力做到對每一位認可自己的讀者負責。
幫助別人的同時更是豐富自己的良機。
應用場景
集羣下部署多個應用,定時任務就會出現重複執行的問題,爲了避免資源浪費和髒數據的問題出現,藉助redis分佈式鎖解決
redis實現分佈式鎖用到的幾個命令:setnx、get、getset、expire
redis分佈式鎖實現
基於Redis實現的分佈式鎖其實很簡單,底層就是使用redis的setnx指令來實現的加鎖,我們來看看官方對setnx的定義:
SETNX key value
將 key 的值設爲 value ,當且僅當 key 不存在。
若給定的 key 已經存在,則 SETNX 不做任何動作。
死鎖問題
既然setnx這麼強大,還需考慮一些極端場景。
比如如果一臺機器在運行狀態中突然宕機沒有設置鎖的過期時間無法自動釋放鎖,那麼另一臺應用會一直認爲有機器佔用着分佈式鎖執行任務,此時實際是沒有執行的,而導致死鎖問題。
死鎖問題解決方法
在這裏我們給分佈式鎖設置一個過期時間,能夠在開始執行任務後自動釋放分佈式鎖
具體實現代碼
/**
* @author ex_sunqi
* 分佈式鎖控制schedule
*/
@Component
@Configuration
@EnableScheduling
public class fileScheduleTask {
private final Log logger = LogFactory.getLog(getClass());
private static final String LOCK = "job-lock";
private static final String KEY = "fileTasklock";
//單位爲秒 默認10分鐘
private long redis_time = 60 * 10;
@Scheduled(cron = "0 0/30 * * * ?")
public void fileConvertJob() {
boolean lock = false;
try {
lock = redisTemplate.opsForValue().setIfAbsent(KEY, LOCK);
logger.info("是否獲取到鎖:" + lock);
if (lock) {
//設置分佈式鎖的過期時間
redisTemplate.expire(KEY, redis_time , TimeUnit.SECONDS);
//代碼核心邏輯
} else {
logger.info("沒有獲取到鎖,不執行任務!");
return;
}
} finally {
if (lock) {
redisTemplate.delete(KEY);
logger.info("任務結束,釋放鎖!");
} else {
logger.info("沒有獲取到鎖,無需釋放鎖!");
}
}
}
}