NodeJS 基于redis的分布式锁的实现(Redlock算法)

栏目: Node.js · 发布时间: 5年前

内容简介:开发时,碰到互斥问题,需要保证在分布式环境下,避免重复性操作修改用户状态,如:用户订单状态,购票时,修改票的余额等但是这种方法在主库错误时,会发生错误,redis主从同步是异步,主库错误时,从库若还没有锁的信息,则会导致多个进程持有锁3. Redlock算法(

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

2. 分布式锁的条件

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

3.Redis单节点上锁的实现

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

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

3. 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的写法的时候,可以填写这个参数
/** 释放锁 */
Redlock.prototype.unlock(lock, ?callback)
/** 延长锁的有效时间 */
Lock.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()
   }
})
复制代码

以上所述就是小编给大家介绍的《NodeJS 基于redis的分布式锁的实现(Redlock算法)》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

第一行代码:Android(第2版)

第一行代码:Android(第2版)

郭霖 / 人民邮电出版社 / 2016-12-1 / CNY 79.00

本书被广大Android 开发者誉为“Android 学习第一书”。全书系统全面、循序渐进地介绍了Android软件开发的必备知识、经验和技巧。 第2版基于Android 7.0 对第1 版进行了全面更新,将所有知识点都在最新的Android 系统上进行重新适配,使用 全新的Android Studio 开发工具代替之前的Eclipse,并添加了对Material Design、运行时权限、......一起来看看 《第一行代码:Android(第2版)》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

SHA 加密
SHA 加密

SHA 加密工具