基于Mongodb分布式鎖解決定時任務(wù)并發(fā)執(zhí)行問題
前言
我們?nèi)粘i_發(fā)過程,會有一些定時任務(wù)的代碼來統(tǒng)計一些系統(tǒng)運行數(shù)據(jù),但是我們應(yīng)用有需要部署多個實例,傳統(tǒng)的通過配置文件來控制定時任務(wù)是否啟動又太過繁瑣,而且還經(jīng)常出錯,導(dǎo)致一些異常數(shù)據(jù)的產(chǎn)生
網(wǎng)上有很多分布式鎖的實現(xiàn)方案,基于redis、zk、等有很多,但是我的就是一個用了mysql和mongo的小應(yīng)用,不準(zhǔn)備引入其他三方中間件來解決這個問題,擼一個簡單的分布式鎖來解決定時任務(wù)并發(fā)執(zhí)行的問題,加鎖操作的原子性和防死鎖也都要支持,這里我使用mongodb寫了AllInOne的工具類
All in one Code
先上代碼
@Component @Slf4j public class MongoDBLock { private static final int DEFAULT_LOCK_TIMEOUT = 30;//鎖的默認超時時間,單位秒 private MongoTemplate mongoTemplate; private int lockTimeout; public MongoDBLock(MongoTemplate mongoTemplate) { this.mongoTemplate = mongoTemplate; this.lockTimeout = DEFAULT_LOCK_TIMEOUT; } /** * 嘗試獲取分布式鎖 * * @param lockKey 鎖的key * @return true:獲取鎖成功,false:獲取鎖失敗 */ private boolean acquireLock(String lockKey) { LockDocument document = new LockDocument(); document.setId(lockKey); document.setExpireAt(Instant.ofEpochMilli(Instant.now().toEpochMilli() + lockTimeout * 1000)); try { mongoTemplate.insert(document); return true; } catch (Exception e) { } return false; } /** * 釋放分布式鎖 * * @param lockKey 鎖的key */ private void releaseLock(String lockKey) { Query query = new Query(Criteria.where("key").is(lockKey)); mongoTemplate.remove(query, LockDocument.class); log.info("程序執(zhí)行成功,釋放分布式鎖,lockKey:{}",lockKey); } /** * 分布式鎖入口方法,參數(shù)lockName為鎖的名稱,lockKey為需要加鎖的key,執(zhí)行完成后自動釋放鎖 * * @param lockKey * @param task * @param <T> * @throws Exception */ public <T> void executeWithLock(String lockKey, ITask<T> task) throws Exception { boolean locked = acquireLock(lockKey); if (locked) { log.info("獲取分布式鎖成功,lockKey:{}",lockKey); try { task.execute(); } finally { releaseLock(lockKey); } } else { log.warn("獲取分布式鎖失敗,lockKey:{}", lockKey); throw new AppException("獲取分布式鎖失??!"); } } @Data @Document(collection = "lock_collection") static class LockDocument { @Id private String id; @Indexed(expireAfterSeconds = DEFAULT_LOCK_TIMEOUT) private Instant expireAt; } @FunctionalInterface public interface ITask<T> { T execute() throws Exception; } }
調(diào)用示例
@Resource MongoDBLock mongoDBLock; mongoDBLock.executeWithLock("key", () -> { // do some thing return null; });
原理
- 使用key作為主鍵,利用mongodb的insert原子性保障LockDocument不會重復(fù)插入
- LockDocument中expireAt字段利用的mongodb索引過期機制,解決死鎖問題,這里設(shè)置超時時間是30秒,并在執(zhí)行完成之后會主動釋放鎖
到此這篇關(guān)于基于Mongodb分布式鎖簡單實現(xiàn),解決定時任務(wù)并發(fā)執(zhí)行問題的文章就介紹到這了,更多相關(guān)Mongodb分布式鎖內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
將MongoDB加入到Windows的本地服務(wù)項的方法
下面主要針對MongoDB在Windows下加入本地服務(wù)項做一些簡單的分享。以方便剛接觸MongoDB并在Windows環(huán)境下進行開發(fā)的同學(xué)2014-08-08在Linux服務(wù)器中配置mongodb環(huán)境的步驟
這篇文章主要介紹了在Linux服務(wù)器中配置mongodb環(huán)境的步驟,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07使用mongoshake實現(xiàn)mongodb數(shù)據(jù)同步的操作方法
MongoShake是阿里云以Golang語言編寫的通用平臺型服務(wù)工具,它通過讀取MongoDB的Oplog操作日志來復(fù)制MongoDB的數(shù)據(jù)以實現(xiàn)特定需求。本文重點給大家介紹使用mongoshake實現(xiàn)mongodb數(shù)據(jù)同步的操作方法,感興趣的朋友一起看看吧2022-02-02Windows10安裝MongoDB4.0詳細步驟及啟動配置教程
這篇文章主要介紹了Windows10安裝MongoDB4.0詳細步驟及啟動配置教程 ,本文通過圖文并茂的形式給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下2020-01-01MongoDB數(shù)據(jù)庫插入、更新和刪除操作詳解
這篇文章主要介紹了MongoDB數(shù)據(jù)庫插入、更新和刪除操作詳解,需要的朋友可以參考下2014-03-03MongoDB aggregate 運用篇個人總結(jié)
最近一直在用mongodb,有時候會需要用到統(tǒng)計,在網(wǎng)上查了一些資料,最適合用的就是用aggregate,以下介紹一下自己運用的心得2016-11-11