Redis DEL多键与管道:二者是否均为非阻塞?
批量删除Redis大量键的方案疑惑
我需要从Redis中批量删除大量键,且已掌握所有键名无需搜索,目前评估两种方案:
- 使用传递多键的
DEL命令:本地性能测试显示该方案比管道快近10倍,但担心DEL的原子性会阻塞Redis - 在单个管道中执行大量
DEL命令:速度较慢,但认为管道会逐行执行,不会阻塞其他客户端
我不确定多键DEL是否会阻塞至所有键删除完成,实际测试结果却显示它并未阻塞,这与Redis文档描述矛盾。
测试代码
let data = await setSomeDataInRedis(); let keys = data.map(([k]) => k); const startDel = Date.now(); console.log('\n== del[] ==') // Sending 3 request using 2 connections to Redis in parallel. // Well, almost in parallel 'cause it's Node.js and also network is serial. await Promise.all([ redisClient1.hmget(['always-there', 'name']) // I expect this one returns 1st as it comes before DEL .then((r) => console.log(`get-before-del[] - ${Date.now() - startDel}ms - ${JSON.stringify(r)}`)), redisClient2.del(keys) // I expect this one returns 2nd and block 3rd on Redis side .then(() => console.log(`del[] - ${Date.now() - startDel}ms`)), redisClient1.hmget(['always-there', 'name']) // I expect this one returns 3rd because 2nd blocks Redis .then((r) => console.log(`get-after-del[] - ${Date.now() - startDel}ms - ${JSON.stringify(r)}`)), ]) console.log('\n== pipeline ==') // Same here - sending 3 request using 2 connections to Redis in parallel. data = await setSomeDataInRedis(); const pipeline = redisClient2.pipeline(); data.forEach(([k]) => pipeline.del(k)); const startPipe = Date.now(); await Promise.all([ redisClient1.hmget(['always-there', 'name']) // I expect this one returns 1st as it comes before DEL .then((r) => console.log(`get-before-pipeline - ${Date.now() - startPipe}ms - ${JSON.stringify(r)}`)), pipeline.exec() // I expect this one returns 3rd as it has lots of commands, but non-blocking .then(() => console.log(`pipeline - ${Date.now() - startPipe}ms`)), redisClient1.hmget(['always-there', 'name']) // I expect this one returns 2nd as pipeline is non-blocking .then((r) => console.log(`get-after-pipeline - ${Date.now() - startPipe}ms - ${JSON.stringify(r)}`)), ]) console.log('\n== unlink[] ==') data = await setSomeDataInRedis(); keys = data.map(([k]) => k); const startUnlink = Date.now(); await Promise.all([ redisClient1.hmget('always-there', 'name') .then((r) => console.log(`get before unlink[] - ${Date.now() - startUnlink}ms - ${JSON.stringify(r)}`)), redisClient2.unlink(keys) .then(() => console.log(`unlink[] - ${Date.now() - startUnlink}ms`)), redisClient1.hmget(['always-there', 'name']) .then((r) => console.log(`get after unlink[] - ${Date.now() - startUnlink}ms - ${JSON.stringify(r)}`)), ])
测试输出
== del[] == get-before-del[] - 62ms - ["name0.06551250522960261"] get-after-del[] - 64ms - ["name0.06551250522960261"] del[] - 183ms == pipeline == get-before-pipeline - 127ms - ["name0.9763696909778301"] get-after-pipeline - 131ms - ["name0.9763696909778301"] pipeline - 1325ms == unlink[] == get before unlink[] - 41ms - ["name0.25533683439953236"] get after unlink[] - 47ms - ["name0.25533683439953236"] unlink[] - 153ms
get-after-del[]早于del[]返回的现象似乎表明多键DEL是非阻塞的(非原子性),但这与Redis文档描述矛盾。
补充说明:最初未加入Unlink测试,虽其速度快10-20%,但仍会阻塞Redis,故补充相关测试。
内容的提问来源于stack exchange,提问作者Viktor Molokostov
相关产品推荐
相关产品推荐

