node.js 中使用redis實現分佈式事務鎖

在node項目中,咱們常會跑一些定時任務,好比定時發送通知、定時發送郵件等,項目部署的時候,咱們每每是多機多實例部署,這就致使每一個實例都會跑一次一樣的任務,因此咱們須要一個分佈式事務鎖,來保證任務只能跑一次。html

分佈式事務鎖

分佈式事務鎖有多種實現方式,大體分爲如下幾類node

  • 基於數據庫實現
  • 基於緩存(redis,memcached)
  • 基於Zookeeper

針對目前的需求,使用數據庫鎖太過於麻煩,Zookeeper目前生產未使用,而redis項目中恰好有使用,因此咱們採起第二種實現方式git

redLock

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了

相關文章
相關標籤/搜索