redis setnx解決定時任務多節點部署併發問題(分散式鎖)
阿新 • • 發佈:2019-01-12
在一些大的網際網路平臺,通常都會使用定時任務處理一些週期性的業務,而為了保障系統的高可用性,定時任務也會多節點部署,而解決多節點併發問題(分散式鎖),大家通常會想到使用快取,如redis,但是如果使用set / get是無法解決問題的,同樣會出現併發問題,redis有專門的解決分散式併發問題的方法,就是setnx命令,很好用,下面介紹一下java實現redis分散式鎖的方法。
1. Redis SETNX命令語法:
SETNX 是『SET if Not eXists』(如果不存在,則 SET)的簡寫,其操作為:將 key 的值設為 value ,當且僅當 key 不存在。若給定的 key 已經存在,則 SETNX 不做任何動作。
返回值:
設定成功,返回 1 。
設定失敗,返回 0 。
SetNX 不具備設定過期時間的功能,所以我們需要藉助 Expire 來設定,否則可能會出現死鎖問題。
2. 環境說明
是基於 spring boot的專案,這是一個專案中多節點定時扣費任務的實現。
3. 配置實現
3.1. 定時任務
@Component @EnableScheduling public class QuartzCharge { Logger logger = LogManager.getLogger("quartzCharge"); @Autowired RedisComponent redisComponent; //每每小時0分0秒執行一次 @Scheduled(cron = "0 0 * * * *") public void quartzCharge(){ //需要先查詢redis的計費標記,如果有,就不計費,如果沒有就計費,整點計費 logger.info(" 定時計費開始: "); //redis分散式鎖,儘量要設定過期時間,防止死鎖 if(!redisComponent.setNX("quartzChargeTag", "1", 10, TimeUnit.SECONDS)){ logger.info("已有執行中定時扣費任務,本次不執行!"); return; } //計費 try{ //to_do 定時業務實現 }catch(Exception e){ logger.error("定時扣費異常結束: " + e); }finally{ //任務執行完,一定要清空快取,防止意外終止死鎖 redisComponent.del("quartzChargeTag"); } logger.info("定時計費結束!"); } }
3.2.redis操作工具類
@Component public class RedisComponent { @Autowired //操作字串的template,StringRedisTemplate是RedisTemplate的一個子集 private StringRedisTemplate stringRedisTemplate; @Autowired // RedisTemplate,可以進行所有的操作 private RedisTemplate<Object,Object> redisTemplate; /* * redis分散式鎖實現,同時利用expire設定過期時間 * 返回true就是設定成功 * */ public Boolean setNX(String key, String value,long timeout, TimeUnit unit){ Boolean isExit = this.redisTemplate.getConnectionFactory().getConnection().setNX(key.getBytes(), value.getBytes()); //如果設定成功,要設定其過期時間 if(isExit){ redisTemplate.expire(key, timeout, unit); } return isExit; } }
3.3 雙節點執行效果
節點一日誌:
節點二日誌:
看兩個節點的日誌,可以清楚的看到,兩個節點相互執行定時任務,執行時間就在毫釐之間,誰快誰就搶到鎖,一個節點掛了還有另外一個,這樣就保障了系統的高可用,是不是挺酸爽的,O(∩_∩)O哈哈~
----------over--------------