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了

相关文章
相关标签/搜索