Redis 支持在 LUA 脚本中使用任意精度
2019-5-7 18:57:51
收藏:0
阅读:145
评论:1
我需要能够在 Redis 中执行以下操作的事务:
- 仅当结果 > 0 时才减少 n 值
- 否则不执行任何操作
- 处理任意精度的十进制数(我需要它们以浮点格式)
- 可以被其他进程访问
简单地放,它就是一个“余额”:如果我在此字段中拥有足够的钱,我就可以使用它,否则不能使用。有时,它必须减少许多余额。
为此,我制作了一个 LUA 脚本,它计算减量的结果,然后用此结果修改字段。我选择这个解决方案,因为:
- 它是原子性的
- 更简单的 INCRBYFLOAT 无论结果如何都会执行减法,而且似乎没有正确的精度
- 使用了 LUA 库 http://oss.digirati.com.br/luabignum/
我面临的问题:
- 使用的库不适合:它只适用于整数,太大了每次发送(即使使用 evalsha,速度也很慢)
- 在 Redis 中编写 Lua 脚本时如何包括第三方库 => 这样做后,我对 Redis 上使用附加模块感到非常困惑。但是,这已经过去了。现在情况怎样?
- 我甚至不确定是否有更有效的方法来做到这一点?欢迎对代码本身提出任何建议
- Redis 真的是满足我的需求的一种方式吗?
“值”输入具有以下格式:Array<{ key: string, field: string, value: string // this is actually a BigNumber, with a string format }>
this.redisClient.eval(`
${luaBigNumbers}
local operations = cjson.decode(KEYS[1])
local isStillValid = true
local test
for k, v in pairs(operations) do
local temp = BigNum.new(redis.call('hget', v.key, v.field))
local res = BigNum.mt.add(temp, BigNum.new(v.value))
if BigNum.mt.lt(res, BigNum.new('0')) then
isStillValid = false
end
end
if isStillValid then
for k, v in pairs(operations) do
local temp = BigNum.new(redis.call('hget',v.key, v.field))
redis.call('hset', v.key, v.field, BigNum.mt.tostring(BigNum.mt.add(temp, BigNum.new(v.value))))
end
end
return tostring(isStillValid)`,
1, JSON.stringify(values), (err, reply) => {
总之:我需要在 Redis 中具有共享余额功能,怎样做得好?
如果您知道如何实现,请发布到 Stack Exchange 中 https://softwareengineering.stackexchange.com/questions/391529/what-architecture-is-the-most-adapted-for-a-shared-balance-in-nodejs-and-maybe
点赞
评论区的留言会收到邮件通知哦~
推荐文章
- Lua 虚拟机加密load(string.dump(function)) 后执行失败问题如何解决
- 我想创建一个 Nginx 规则,禁止访问
- 如何将两个不同的lua文件合成一个 东西有点长 大佬请耐心看完 我是小白研究几天了都没搞定
- 如何在roblox studio中1:1导入真实世界的地形?
- 求解,lua_resume的第二次调用继续执行协程问题。
- 【上海普陀区】内向猫网络招募【Skynet游戏框架Lua后端程序员】
- SF爱好求教:如何用lua实现游戏内调用数据库函数实现账号密码注册?
- Lua实现网站后台开发
- LUA错误显式返回,社区常见的规约是怎么样的
- lua5.3下载库失败
- 请问如何实现文本框内容和某个网页搜索框内容连接,并把网页输出来的结果反馈到另外一个文本框上
- lua lanes多线程使用
- 一个kv数据库
- openresty 有没有比较轻量的 docker 镜像
- 想问一下,有大佬用过luacurl吗
- 在Lua执行过程中使用Load函数出现问题
- 为什么 neovim 里没有显示一些特殊字符?
- Lua比较两个表的值(不考虑键的顺序)
- 有个lua简单的项目,外包,有意者加微信 liuheng600456详谈,最好在成都
- 如何在 Visual Studio 2022 中运行 Lua 代码?

也许受事件溯源模式的启发可以解决您的问题。另外,实现原子性的另一种方法是将写入角色限制为仅有一个处理器,其命令将始终按时间顺序排列(就像redis和lua一样)
1)您将带有余额更改事件的“事件”存储在排序集中(用于时间排序,时间戳作为得分)。仅存储您想要执行的“命令”(而不是计算结果)。例如,-1.545466,“+2.07896" 等等……
2)然后您通过一个Lua脚本从单个处理器(必须确保只有一个计算项访问此数据,否则会有麻烦)中使用这些事件进行消耗,可以使用循环调用脚本,每隔n秒调用一次(你可以定义你的实时质量)就像Apache Storm一样(一个“麦克风”)。例如,该脚本应从最旧的时间戳到最新的时间戳返回事件,应同时返回时间戳(得分),当然还要返回实际余额。
您应该得到像这样的值:
balance= +5 ZSET= "-6" score 1557782182 "+2" score 1557782772 "+3" score 16787878783)在您的中间件服务器(唯一的允许修改余额的服务器)中,使用您想要在服务器中使用的任何库/技术(应该非常快)计算余额的更改。您只需遍历事件以每次计算余额即可。请注意,由于此方法,您将在redis中执行较少的突变。
您应该得到以下结果
old_balance=5 new_balance=10 ZSET= "-6" score 1557782182 "+2" score 1557782772 "+3" score 16787878784)在您的服务器计算出新的余额值后,就该通过Lua脚本将结果和您用于redis的事件发送回去。使用Lua脚本的原因有:
-更新余额的值,因为只允许一个进程进行修改,所以您不应该遇到任何交易问题,它也应该始终按时间顺序排列 -修剪计算事件的排序集(步骤2使用的最旧和最新时间戳将用于此),以便在下一个lua调用中不再处理这些事件
5)受益。
请注意,在调用操作2之前,操作4必须完成,您可以在redis中设置一个旧的信号量(例如“忙”键),以防止这种情况发生(如果操作4未完成,则设置一个忙键,以便防止操作2运行,当步骤4完成时清除它,您也可以设置它的到期时间,以便如果出现问题,则清除将作为另一个迭代的超时启动)。