Qua*_*ear 5 lua arbitrary-precision redis
我需要能够在Redis中进行以下操作:
简而言之,这是一个“平衡”:如果我在此字段中有足够的空间,则可以使用它,否则,不可以。有时候,它必须减少很多余额
为此,我制作了一个LUA脚本来计算减量的结果,然后使用该结果修改字段。我选择此解决方案是因为:
我面临的问题:
输入“值”的格式如下:Array <{键:字符串,字段:字符串,值:字符串// //实际上是一个BigNumber,具有字符串格式}>
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) => {
Run Code Online (Sandbox Code Playgroud)
TL; DR:我需要在Redis上有一个共享余额功能,如何做得好?
如果您对如何实现它有想法,请张贴在堆栈交换中https://softwareengineering.stackexchange.com/questions/391529/what-architecture-is-the-most-adapted-for-a-shared-balance-in-节点和可能
正如您的答案的评论中所指出的,编写您自己的模块将是一个非常适合您的要求的选项。
这样的模块将用 C 语言编写。因此需要一个满足金融应用数学要求的十进制库。
这里我使用 decNumber C 库,这是一个最初由 IBM 编写的库。我使用以下链接进行测试:
演示
在看代码之前,先看一个小演示:
正如您所看到的,它可以以任意精度工作。
balance.decrement mykey myfield "0.1"像递减这样的命令mykey myfield会使用作为最后一个字符串参数传递的值。新值存储在命令中mykey myfield并作为命令的结果输出。如果结果小于 0,则不会递减。然后NOP输出a。该操作是原子的。
模块源码
#include "../redismodule.h"
#include "../rmutil/util.h"
#include "../rmutil/strings.h"
#include "../rmutil/test_util.h"
#define DECNUMDIGITS 34
#include "decNumber.h"
int decrementCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc != 4) {
return RedisModule_WrongArity(ctx);
}
RedisModule_AutoMemory(ctx);
RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_HASH &&
RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
}
RedisModuleCallReply *currentValueReply = RedisModule_Call(ctx, "HGET", "ss", argv[1], argv[2]);
RMUTIL_ASSERT_NOERROR(ctx, currentValueReply);
RedisModuleString *currentValueRedisString = RedisModule_CreateStringFromCallReply(currentValueReply);
if (!currentValueRedisString) {
return 0;
}
const char *currentValueString = RedisModule_StringPtrLen(currentValueRedisString, NULL);
const char *decrementValueString = RedisModule_StringPtrLen(argv[3], NULL);
decNumber currentNum, decrementNum;
decContext set;
char resultStr[DECNUMDIGITS + 14];
decContextDefault(&set, DEC_INIT_BASE);
set.traps = 0;
set.digits = DECNUMDIGITS;
decNumberFromString(¤tNum, currentValueString, &set);
decNumberFromString(&decrementNum, decrementValueString, &set);
decNumber resultNum;
decNumberSubtract(&resultNum, ¤tNum, &decrementNum, &set);
if (!decNumberIsNegative(&resultNum)) {
decNumberToString(&resultNum, resultStr);
RedisModuleCallReply *srep = RedisModule_Call(ctx, "HSET", "ssc", argv[1], argv[2], resultStr);
RMUTIL_ASSERT_NOERROR(ctx, srep);
RedisModule_ReplyWithStringBuffer(ctx, resultStr, strlen(resultStr));
return REDISMODULE_OK;
}
if (RedisModule_CallReplyType(currentValueReply) == REDISMODULE_REPLY_NULL) {
RedisModule_ReplyWithNull(ctx);
return REDISMODULE_OK;
}
RedisModule_ReplyWithSimpleString(ctx, "NOP");
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx) {
if (RedisModule_Init(ctx, "balance", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) {
return REDISMODULE_ERR;
}
RMUtil_RegisterWriteCmd(ctx, "balance.decrement", decrementCommand);
return REDISMODULE_OK;
}
Run Code Online (Sandbox Code Playgroud)
如何构建和运行
我建议克隆https://github.com/RedisLabs/RedisModulesSDK。有一个示例文件夹。将 module.c 替换为上述模块代码。将以下文件从 decNumber C 库复制到示例文件夹:
修改示例文件夹中的 Makefile,以使以 module.so 开头的行如下所示:
module.so: module.o decNumber.o decContext.o
$(LD) -o $@ module.o decNumber.o decContext.o $(SHOBJ_LDFLAGS) $(LIBS) -L$(RMUTIL_LIBDIR) -lrmutil -lc
Run Code Online (Sandbox Code Playgroud)
在基本目录中输入以下命令:
make clean
make
Run Code Online (Sandbox Code Playgroud)
然后您可以使用以下命令进行测试:
redis-server --loadmodule ./module.so
Run Code Online (Sandbox Code Playgroud)
这就是您要找的吗?