阿里云redis集群使用lua脚本

我不是女神ヾ 2022-06-03 00:23 1108阅读 0赞

这里写图片描述

redis集群对lua集群的支持有限,阿里的文档描述也比较简单,没有demo,研究了好久才把单例的lua脚本修改成集群版
单例模式的lua脚本

  1. local strs = {};
  2. local result = {};
  3. local resultIndex = 2;
  4. -- ARGV[1]是操作集合的指令,这里对应的是正序还是倒序zrangezrevrange
  5. -- KEYS[1]是zsetkey
  6. -- ARGV[2]是从第几个元素开始
  7. -- ARGV[3]是第几个元素结束
  8. local list = redis.call(ARGV[1], KEYS[1], ARGV[2], ARGV[3])
  9. if(list[1] == nil) then
  10. return "[]"
  11. end
  12. result[1] = "[";
  13. for index,v in ipairs(list) do
  14. -- KEYS[2]是存投票项的hashkey,值是vote:%s:%s:voteItem:list:
  15. -- 拼写主Key
  16. local key = KEYS[2]..v
  17. --大量拼接字符串..效率比table.concat(strs)低很多。
  18. --Lua的字符串和Java的字符串差不多,都是不可变的,每一次进行连接操作之后,其实就产生了新的字符串,不再是原来的那个了,不断连接,就不断产生新的字符串,产生新字符串是需要复制操作,随着连接操作的不断进行着,字符串越来越大,复制操作也就越来越耗时
  19. -- 获取hash中的name
  20. local id = redis.call("hget", key, "id")
  21. local itemName = redis.call("hget", key, "itemName")
  22. local sortIndex = redis.call("hget", key, "sortIndex")
  23. local details = redis.call("hget", key, "details")
  24. local videoLink = redis.call("hget", key, "videoLink")
  25. local itemImg = redis.call("hget", key, "itemImg")
  26. local voteNumber = redis.call("hget", key, "voteNumber")
  27. strs[1] = "{\'id\':\'";
  28. strs[2] = id;
  29. strs[3] = "\',";
  30. strs[4] = "\'itemName\':\'";
  31. strs[5] = itemName;
  32. strs[6] = "\',";
  33. strs[7] = "\'sortIndex\':\'";
  34. strs[8] = sortIndex;
  35. strs[9] = "\',";
  36. strs[10] = "\'details\':\'";
  37. strs[11] = details;
  38. strs[12] = "\',";
  39. strs[13] = "\'videoLink\':\'";
  40. strs[14] = videoLink;
  41. strs[15] = "\',";
  42. strs[16] = "\'itemImg\':\'";
  43. strs[17] = itemImg;
  44. strs[18] = "\',";
  45. strs[19] = "\'voteNumber\':\'";
  46. strs[20] = voteNumber;
  47. strs[21] = "\'}";
  48. local voteItemJson = table.concat(strs);
  49. redis.log(redis.LOG_DEBUG, "voteItemJson:"..voteItemJson)
  50. result[resultIndex] = voteItemJson;
  51. resultIndex = resultIndex + 1;
  52. result[resultIndex] = ",";
  53. resultIndex = resultIndex + 1;
  54. end
  55. if resultIndex > 2 then
  56. table.remove(result, resultIndex - 1);
  57. end
  58. result[resultIndex -1] = "]"
  59. return table.concat(result);

这个脚本直接指向会报错

  1. -ERR eval/evalsha command keys must in same slot

集群有一个槽的概念,不同的key根据redis的hash算法会分布在不同的槽,集群是不支持多key查询的,解决办法是使用redis的hash tag,存入的时候把要多key查询的 key用{}括起来。如{key}.1,a.{key},s:{key}:b,这样这3个key都是按照{}内的内容技术槽,就能保证存入同一个槽内。

还可能会遇到这个异常

  1. ERR bad lua script for redis cluster, first parameter of redis.call/redis.pcall must be a single literal string

这是因为redis.call()第一个参数必须是字符串,不能是ARGV传参,我试过在lua里定义变量order,然后吧order放入redis.call,还是会报这个异常,没找到什么好的解决办法,只能把指令写入redis.call(),把正序和倒序写了两个脚本
local list = redis.call(‘zrange’, KEYS[1], ARGV[1], ARGV[2])

上面的脚本还会报一个错误

  1. "-ERR bad lua script for redis cluster, all the keys that the script uses should be passed using the KEYS array\r\n"

这是因为在循环内,我会拼接key,local key = KEYS[2]..v,在下面的redis.call会用到这个key,但是ali的redis集群规定,redis.call里面的key只能使用KEYS数组,所以这里修改代码

  1. KEYS[3] = KEYS[2]..v
  2. local id = redis.call("hget", KEYS[3], "id")

这样就能在redis集群执行这个lua脚本了

发表评论

表情:
评论列表 (有 0 条评论,1108人围观)

还没有评论,来说两句吧...

相关阅读