博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NodeJS 基于redis的分布式锁的实现(Redlock算法)
阅读量:4072 次
发布时间:2019-05-25

本文共 1931 字,大约阅读时间需要 6 分钟。

1. 前言

开发时,碰到互斥问题,需要保证在分布式环境下,避免重复性操作修改用户状态,如:用户订单状态,购票时,修改票的余额等

2. 分布式锁的条件

分布式锁需要满足下列条件

锁需要有充足的可访问的存储空间
锁必须被唯一标识
锁至少要有两种状态
同时,要保证
安全特性:互斥访问,永远只有一个client能拿到锁
避免死锁:client最后可以拿到锁,不会出现死锁,即使原本上锁的client出现问题无法解锁
容错性:容错,只要大多数redis节点能够正常工作,客户端端都能获取和释放锁。

3.Redis单节点上锁的实现

用下列语句获取一个不存在的key,如果可以已存在则创建失败,确保key值唯一, 加上过期时间,确保系统错误后及时解锁,避免死锁

SET key value NX PX 30000

但是这种方法在主库错误时,会发生错误,redis主从同步是异步,主库错误时,从库若还没有锁的信息,则会导致多个进程持有锁

4. Redis集群锁的实现-Redlock算法

在分布式版本的算法里我们假设我们有N个Redis master节点,这些节点都是完全独立的,我们不用任何复制或者其他隐含的分布式协调算法。我们已经描述了如何在单节点环境下安全地获取和释放锁。因此我们理所当然地应当用这个方法在每个单节点里来获取和释放锁。在我们的例子里面我们把N设成5,这个数字是一个相对比较合理的数值,因此我们需要在不同的计算机或者虚拟机上运行5个master节点来保证他们大多数情况下都不会同时宕机。一个客户端需要做如下操作来获取锁:

获取当前时间(单位是毫秒)。

轮流用相同的key和随机值在N个节点上请求锁,在这一步里,客户端在每个master上请求锁时,会有一个和总的锁释放时间相比小的多的超时时间。比如如果锁自动释放时间是10秒钟,那每个节点锁请求的超时时间可能是5-50毫秒的范围,这个可以防止一个客户端在某个宕掉的master节点上阻塞过长时间,如果一个master节点不可用了,我们应该尽快尝试下一个master节点。
客户端计算第二步中获取锁所花的时间,只有当客户端在大多数master节点上成功获取了锁(在这里是3个),而且总共消耗的时间不超过锁释放时间,这个锁就认为是获取成功了。
如果锁获取成功了,那现在锁自动释放时间就是最初的锁释放时间减去之前获取锁所消耗的时间。
如果锁获取失败了,不管是因为获取成功的锁不超过一半(N/2+1)还是因为总消耗时间超过了锁释放时间,客户端都会到每个master节点上释放锁,即便是那些他认为没有获取成功的锁。

4.使用示例

首先安装redis库与redlock库(官方库,在git上名叫node-redlock),在node项目中,直接使用npm或者yarn下载安装即可,redis库我使用的是ioredis(直接安装redis库也可)

  npm i --save ioredis  npm i --save redlock

主要用到的方法(官方文档)

/** 请求锁 */Redlock.prototype.lock(resource, ttl, ?callback) // resource锁的名称// ttl锁的有效期// callback 回调函数,当使用promise的写法的时候,可以填写这个参数/** 释放锁 */Lock.prototype.unlock(lock, ?callback)/** 延长锁的有效时间 */Redlock.prototype.extend(lock, ttl, ?callback)// 都支持callback、promise、yield写法

代码示例

const ioredis = require('ioredis')const Redlock = require('redlock')const client = new ioredis(REDIS_SERVER)const redlock = new Redlock([client])co(function* () {   while (true) {       let lock = null       try {           lock = yield redlock.lock('lock', 1000) // 这种写法取不到锁时会直接抛出错误       } catch (error) {           lock = null       }       yield sleep(30 * 1000)       // 处理逻辑       lock.unlock()   }})

 

转载地址:http://wjrji.baihongyu.com/

你可能感兴趣的文章
一个很好用的JQuery Table拖拽插件
查看>>
[转]页面翻转效果^_^
查看>>
关于checkbox的点击事件和返回值
查看>>
TableDnd(JQuery表格拖拽控件)应用进阶
查看>>
[转]基于C语言的Javascript引擎探索
查看>>
[转]VLD扩展使用指南
查看>>
[转]BigPipe学习研究
查看>>
[转]用 awstats分析 Nginx 日志的一些记录
查看>>
[转]细说明 linux sudo 不要密码
查看>>
Yii分析3:Yii日志记录
查看>>
关于HTTP头(header)的Vary的解释
查看>>
JQuery中止(abort)Ajax请求
查看>>
【转】能说明你的Javascript技术很烂的五个原因
查看>>
[转]开源中最好的Web开发的资源
查看>>
Docker上部署SpringBoot项目并推送镜像到Docker Hub上---以MacOS为例
查看>>
bibtex I was expecting a `,‘ or a `}‘ 问题解决
查看>>
sql server中各类范式的理解
查看>>
进程同步
查看>>
Python中列表元素删除
查看>>
Eclipse中改动jsp文件的编码格式以及字体大小
查看>>