在node項目中,咱們常會跑一些定時任務,好比定時發送通知、定時發送郵件等,項目部署的時候,咱們每每是多機多實例部署,這就致使每一個實例都會跑一次一樣的任務,因此咱們須要一個分佈式事務鎖,來保證任務只能跑一次。html
分佈式事務鎖有多種實現方式,大體分爲如下幾類node
針對目前的需求,使用數據庫鎖太過於麻煩,Zookeeper目前生產未使用,而redis項目中恰好有使用,因此咱們採起第二種實現方式git
redis官方推薦了對應的解決方案 Redlock,官方中列出了各個語言的實現,其中有 node 的實現,以下鏈接github
redLock-node實現redis
庫中作了封裝,使用起來很是簡單數據庫
Configuration 配置緩存
var client1 = require('redis').createClient(6379, 'redis1.example.com');
var client2 = require('redis').createClient(6379, 'redis2.example.com');
var client3 = require('redis').createClient(6379, 'redis3.example.com');
var Redlock = require('redlock');
var redlock = new Redlock(
// you should have one client for each independent redis node
// or cluster
[client1, client2, client3],
{
// the expected clock drift; for more details
// see http://redis.io/topics/distlock
driftFactor: 0.01, // time in ms
// the max number of times Redlock will attempt
// to lock a resource before erroring
retryCount: 10,
// the time in ms between attempts
retryDelay: 200, // time in ms
// the max time in ms randomly added to retries
// to improve performance under high contention
// see https://www.awsarchitectureblog.com/2015/03/backoff.html
retryJitter: 200 // time in ms
}
);
複製代碼
Locking & Unlocking 鎖事務和釋放鎖bash
// the string identifier for the resource you want to lock
var resource = 'locks:account:322456';
// the maximum amount of time you want the resource locked,
// keeping in mind that you can extend the lock up until
// the point when it expires
var ttl = 1000; // 鎖的生存時間,在該時間內,若鎖未釋放,強行釋放
redlock.lock(resource, ttl).then(function(lock) {
// ...do something here...
// unlock your resource when you are done
return lock.unlock()
.catch(function(err) {
// we weren't able to reach redis; your lock will eventually // expire, but you probably want to log this error console.error(err); }); }) 複製代碼
經過以上方式,咱們就能夠實現分佈式事務鎖了運維
在測試過程當中,發現事務沒有被鎖住,一查,發現兩臺機子的系統時間不一致,有10秒左右的差異(測試夥伴因別的任務手動調整了時間),這就致使時間早的機子先跑了任務,時間慢的機子,在去獲取鎖的時候,鎖早已經釋放,因此RedLock 創建在了 Time 是可信的模型上
的。 這裏推薦一篇文章 Redis RedLock 完美的分佈式鎖麼? 解釋的很是好dom
在別的博客看過一句話
分佈式的CAP理論告訴咱們「任何一個分佈式系統都沒法同時知足一致性(Consistency)、可用性(Availability)和分區容錯性(Partition tolerance),最多隻能同時知足兩項。」
優秀但不完美的方案在加上優秀的運維,定可以解決大部分的業務需求。
還有一個關於超時時間ttl
的設定問題,究竟是設定多長時間比較好,若設定過短,在任務還沒執行完,鎖就釋放了,反之,若是設置的時間太長,其餘獲取鎖的線程就可能要平白的多等一段時間,因此這個就要根據具體的業務場景來設定啦
若是redis是使用單臺的話,就不必使用 redlock
這個方案,直接使用 setnx
設定一個標誌位,就ok了