# Redis之分布式锁

redis 分布式锁一般是使用 setnx(set if not exists) 指

保证因为异常不会死锁,必须增加过期时间,而且需要原子性操作,采用如下命令。

> set lock true ex 5 nx
1

# 以上方案集群缺陷

  1. 比如在 Sentinel 集群中,主节点挂掉时,从节点会取而代之,客户端上却并没有明显感知。原先第一个客户端在主节点中申请成功了一把锁,但是这把锁还没有来得及同步到从节点,主节点突然挂掉了。然后从节点变成了主节点,这个新的节点内部没有这个锁,所以当另一个客户端过来请求加锁时,立即就批准了。这样就会导致系统中同样一把锁被两个客户端同时持有,不安全性由此产生。

  2. 比如A请求申请了一把锁,但是A由于延迟操作导致锁过期了,B重新拿到了锁,A操作完了之后不知道自己的锁过期了,在去释放锁,就会把B的锁给释放掉,所以redis的value也需要维护。

# Redlock 算法

为了解决这个问题,Redis官网 发明了 Redlock 算法,它的流程比较复杂,不过已经有了很多开源的 library 做了良好的封装,用户可以拿来即用,比如 node-redlock (opens new window)

参考文章 (opens new window)

在Nodejs中的使用参考

'use strict';

const ioredis = require('ioredis');
const config = require('../../config');
config.redis.db = 17;
const redis = new ioredis(config.redis);
const Redlock = require('redlock');
const redlock = new Redlock(
  [ redis ],
  { retryDelay: 200, // time in ms
    retryCount: 50,
  }
);

function sleep(time = 2000) {
  return new Promise(resolve => {
    setTimeout(function() {
      resolve();
    }, time);
  });
}

const demo = async () => {
  const resource = 'key';
  const ttl = 10000; // 10s
  const reqId = parseInt(Math.random() * 100000000);
  console.log(reqId, 1);
  const data = await redlock.lock(resource, ttl); // 加锁
  console.log(reqId, 2);
  await sleep();
  data.unlock();
  console.log(reqId, 3);
};


const run = async () => {
  demo();
  demo();
  demo();
};

run();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
最近更新: 9/22/2022, 5:59:36 AM