redis cluster模式
最近公司要求全部系统的redis均需要改为cluster模式。进行迁移后,我发现,我所开发的某个nodejs项目,不好使了!
经过一番排查,发现是因为代码里使用了scan,而scan是在cluster模式下和哨兵/单机模式是不兼容的!
redis集群模式支撑N个redis master node,自动将数据按key的hash值进行分片,每个master上放一部分数据。在cluster模式下,每次使用scan只能查询单台的redis上的数据(keys *同理):
redis-cli -h [ip] -p [port] --scan cursor MATCH 'user*' COUNT num
因此为了能够使用scan命令查询全部的keys,必须依次连接每一台master节点,分别进行scan。
nodejs环境,我们通常用ioredis来进行redis操作。
初始化redis cluster实例
var Redis = require("ioredis");
var cluster = new Redis.Cluster([
{
port: 6380,
host: "127.0.0.1",
},
{
port: 6381,
host: "127.0.0.1",
},
]);
配合web框架可以把cluster挂在web实例app上,以koa为例:
const app = new Koa();
app.redis = cluster
scan操作
遍历所有的master nodes,分别进行scan操作:
async function scanNodes(str){ //str一般含有*,如user:*
const {ctx, app} = this
const nodes = app.redis.nodes('master')
let listAll = []
let list = []
for(let i=0; i<nodes.length; i++){
list = await this.scanNode(nodes[i], str)
listAll.push(...list)
}
return listAll
}
async function scanNode(node, str){
let vals = []
let point = 0 //起始游标
const step = 10 //步长
let keys = []
while(vals[0]!= 0)
{
point = vals[0] || 0
vals = await node.scan(point,'count', step, 'match', str)
vals[1] && vals[1].length && (keys = keys.concat(vals[1]))
}
return keys
}