`

redis执行lua lua执行redis

阅读更多

redis-2.6支持通过EVAL命令来执行lua脚本,对lua脚本的支持扩展了redis的应用场景,redis支持路脚本需要做2件事

  1. redis能执行lua脚本
  2. 在lua脚本里能执行redis的命令

接下来,我将通过一个简单的实例来解析redis如何完成上述两个工作的。

 

构建一个简单的redis

#define DICT_SIZE 100
struct redisDict {
  char* key[DICT_SIZE];
  char* value[DICT_SIZE];
  int  idx;
};

static void setCommand(const char *key, const char *value)
{
    /* ignore memory issue for simple */
    if (dict.idx + 1 <= DICT_SIZE) {
    dict.key[dict.idx] = (char *)malloc(strlen(key) + 1);
    strcpy(dict.key[dict.idx], key);

    dict.value[dict.idx] = (char *)malloc(strlen(value) + 1);
    strcpy(dict.value[dict.idx], value);

    dict.idx += 1;
  }
}

static const char *getCommand(const char *key)
{
  int j;
  for (j = 0; j <= dict.idx; j++) {
    if (strcmp(dict.key[j], key) == 0) {
      return dict.value[j];
    }
  }
  return "KeyNotFound";
}

上述代码实现了一个伪redis,支持setCommand、getCommand。

C调用lua脚本

具体例子参考http://lua-users.org/wiki/SimpleLuaApiExample

/*
 * All Lua contexts are held in this structure. We work with it almost
 * all the time.
 */
lua_State *L = luaL_newstate();

luaL_openlibs(L); /* Load Lua libraries */

/* Load the file containing the script we are going to run */
status = luaL_loadfile(L, "script.lua");

/* Ask Lua to run our little script */
result = lua_pcall(L, 0, LUA_MULTRET, 0);

上述代码片段中,其中script.lua是一个lua脚本。redis里稍有不同,redis里的脚本是通过EVAL命令传递到服务器端,redis将脚本拼成一个lua函数,然后调用loadbuffer,而这里从文件执行脚本调用的loadfile。

lua调用C函数

下面的lua代码里,调用的是redis的setCommand和getCommand。

redis.call("set", "foo", "bar");

return redis.call("get", "foo");

要想lua脚本能调用C代码,需要现在lua环境注册对应的C函数,参考redis的scriptingInit函数。

static int call(lua_State *L)
{
  int argc = lua_gettop(L);
  const char *cmd = lua_tostring(L, 1);
  const char *key = lua_tostring(L, 2);
  if (strcmp(cmd, "set") == 0) {
    assert(argc == 3);
    const char *value = lua_tostring(L, 3);
    setCommand(key, value);
   return 0;
  } else if (strcmp(cmd, "get") == 0) {
    assert(argc == 2);
    lua_pushstring(L, getCommand(key));
    return 1;
  }

  lua_pushstring(L, "Invalid Command");
  return 1;
}

static void scriptingInit()
{

  L = luaL_newstate();

  luaL_openlibs(L);

  /* Register the redis commands table and fields */
  lua_newtable(L);

  /* redis.call */
  lua_pushstring(L, "call");
  lua_pushcfunction(L, call);
  lua_settable(L, -3);

  /* Finally set the table as 'redis' global var. */
  lua_setglobal(L, "redis");
}

完整示例代码

 1
 2
redis.call("set", "foo", "bar");
return redis.call("get", "foo");
来自CODE的代码片
script.lua

 

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
/* gcc -o test_lua lua.c -llua -lm -ldl */
#include <lua.h>
#include <lauxlib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
 
#define DICT_SIZE 100
struct redisDict {
char* key[DICT_SIZE];
char* value[DICT_SIZE];
int idx;
};
 
struct redisDict dict;
lua_State *L;
 
static void setCommand(const char *key, const char *value)
{
/* ignore memory issue for simple */
if (dict.idx + 1 <= DICT_SIZE) {
dict.key[dict.idx] = (char *)malloc(strlen(key) + 1);
strcpy(dict.key[dict.idx], key);
 
dict.value[dict.idx] = (char *)malloc(strlen(value) + 1);
strcpy(dict.value[dict.idx], value);
 
dict.idx += 1;
}
}
 
static const char *getCommand(const char *key)
{
int j;
for (j = 0; j <= dict.idx; j++) {
if (strcmp(dict.key[j], key) == 0) {
return dict.value[j];
}
}
return "KeyNotFound";
}
 
static int call(lua_State *L)
{
int argc = lua_gettop(L);
const char *cmd = lua_tostring(L, 1);
const char *key = lua_tostring(L, 2);
if (strcmp(cmd, "set") == 0) {
assert(argc == 3);
const char *value = lua_tostring(L, 3);
setCommand(key, value);
return 0;
} else if (strcmp(cmd, "get") == 0) {
assert(argc == 2);
lua_pushstring(L, getCommand(key));
return 1;
}
 
lua_pushstring(L, "Invalid Command");
return 1;
}
 
static void scriptingRun(const char* filename)
{
int status = luaL_loadfile(L, filename);
if (status) {
fprintf(stderr, "Couldn't load file: %s\n", lua_tostring(L, -1));
exit(1);
}
 
/* Ask Lua to run our little script */
int result = lua_pcall(L, 0, LUA_MULTRET, 0);
if (result) {
fprintf(stderr, "Failed to run script: %s\n", lua_tostring(L, -1));
exit(1);
}
 
/* Get the returned value at the top of the stack (index -1) */
const char *value = lua_tostring(L, -1);
 
printf("%s\n", value);
 
lua_pop(L, 1); /* Take the returned value out of the stack */
lua_close(L); /* Cya, Lua */
}
 
static void scriptingInit()
{
/*
* All Lua contexts are held in this structure. We work with it almost
* all the time.
*/
L = luaL_newstate();
 
/* Load Lua libraries */
luaL_openlibs(L);
 
/* Register the redis commands table and fields */
lua_newtable(L);
 
/* redis.call */
lua_pushstring(L, "call");
lua_pushcfunction(L, call);
lua_settable(L, -3);
 
/* Finally set the table as 'redis' global var. */
lua_setglobal(L, "redis");
}
 
int main(void)
{
scriptingInit();
scriptingRun("script.lua");
return 0;
}
分享到:
评论

相关推荐

    SpringBoot+Redis执行lua脚本的方法步骤

    SpringBoot+Redis 执行 Lua 脚本的方法步骤 以下是 SpringBoot+Redis 执行 Lua 脚本的方法步骤的知识点总结: 1. 背景:在开发中,我们需要一次性操作多个 Redis 命令,但是这些操作不具备原子性,而 Redis 的事务...

    java+redis+lua实现重复提交操作拦截.zip

    - Redis支持在服务器端执行Lua脚本,这可以减少网络通信次数,提高性能和原子性。 - 在这个项目中,可能会有一个Lua脚本,用于在Redis中执行锁定和解锁操作,确保整个过程的原子性。例如,脚本可能会检查key是否...

    redis.lua lua脚本语言

    lua链接redis的工具驱动代码

    Redis的Lua开发包redis-lua.zip

    redis-lua 是 Redis 的 Lua 语言的客户端开发包。 示例代码: require 'redis'local redis = Redis.connect('127.0.0.1', 6379) local response = redis:ping() -- trueredis:set('usr:nrk', 10) redis:set('usr:...

    SpringBoot-redis-lua

    1. **Lua脚本优点**: Lua脚本在Redis中执行是原子性的,能确保在并发环境下数据的一致性。此外,通过减少网络往返,提高了数据操作的效率。 2. **`EVAL`命令**: Redis提供了`EVAL`命令来执行Lua脚本。Lua脚本作为...

    基于redis和lua脚本的分布式锁的实现

    3. 执行Lua脚本:使用Redis的 EVAL 命令来执行Lua脚本。 4. 获取锁:使用Redis的 SETNX 命令来获取锁,如果获取成功,则返回 TRUE,否则返回 FALSE。 5. 释放锁:使用Redis的 DEL 命令来释放锁。 注意事项 使用...

    redis和lua

    1. **Lua 脚本执行**: Redis 支持使用 Lua 脚本来执行一系列操作,保证原子性。这在需要复杂逻辑且保证一致性的场景中非常有用,如计数、操作多个键等。 2. **优化性能**: 由于 Lua 脚本在服务器端执行,减少了网络...

    Redis执行Lua脚本的好处与示例代码

    Redis执行Lua脚本的功能在2.6版本引入,极大地增强了Redis的数据处理能力。Lua是一种轻量级的脚本语言,由于其简洁的语法和高效执行,成为Redis内部扩展功能的理想选择。以下是关于Redis执行Lua脚本的一些核心知识点...

    redis-lua 源码

    redis-lua 是 Redis 的 Lua 语言的客户端开发包。 示例代码: require 'redis' local redis = Redis.connect('127.0.0.1', 6379) local response = redis:ping() -- true redis:set('usr:nrk', 10) redis:set('usr...

    redis-lua-debugger.zip

    rld 是一个非交互的调试工具,用于调试 Redis 的 Lua 脚本,这里有篇详细介绍的文章。 rld 特性包括: 易于安装,只有 6kB 可打印输出到本地和远端 跟踪执行的代码行 先进的数值变化的自动监控机制报告 报告...

    Java学习资料-Spring Boot - 结合 Redis 使用 Lua脚本

    首先,需要在`pom.xml`文件中添加Spring Boot的Redis依赖和Redisson库,以便支持Lua脚本的执行。然后,在`application.properties`中配置Redis服务器的连接信息。接着,可以编写Lua脚本来执行特定的数据库操作,例如...

    phpredis执行LUA脚本示例代码

    本篇文章主要探讨如何通过phpredis执行LUA脚本来实现特定的Redis操作。 首先,我们需要了解LUA脚本的基本结构。在示例代码中,我们看到一个LUA脚本被定义为一个字符串,以`EOT`开始,然后在三引号内编写LUA代码,...

    dappFinance#Note#【Redis】Redis执行Lua脚本Demo1

    1. 减少网络开销:本来多次网络请求的操作,可以用一个请求完成,原先多次请求的逻辑放在redis服务器上完成 2. 原子操作:Redis会将整个脚本作为一个整体

    学废SpringBoot+Redis+Lua=王炸(值得珍藏)

    Lua脚本可以在Redis服务器端执行,用于处理复杂的数据操作,提供了一种安全且高效的机制。通过`EVAL`或`EVALSHA`命令,开发者可以将Lua脚本发送到Redis服务器,由服务器一次性执行多个操作,减少了网络通信开销。...

    Redis+LUA脚本实现限流

    Redis+LUA脚本实现限流测试视频

    Spring Boot通过自定义注解和Redis+Lua脚本实现接口限流教程配套源码

    该源码对应个人博客【Spring Boot通过自定义注解和Redis+Lua脚本实现接口限流】教程的相关源码,小伙伴可以自行下载学习!不需要积分!不需要积分!不需要积分! 如果相关资源对您有所帮助,希望一键三连给博主一...

    nginx 整合redis以及lua语言

    2. 安装LuaJIT(Lua的Just-In-Time编译器),提升Lua执行效率。 3. 编译和安装上述Nginx模块,将它们集成到Nginx配置中。 4. 使用lua-redis-parser库编写Lua脚本,实现与Redis的连接和数据交互。 5. 在Nginx配置文件...

    lua-zset, redis排序集相同的lua数据结构.zip

    《lua-zset:Redis排序集在Lua中的实现与应用》 在计算机科学中,数据库管理系统的数据结构设计至关重要,尤其在高性能、高并发的场景下。Redis作为一个内存型的键值存储系统,其丰富的数据结构如哈希表、集合、...

    基于Laravel封装的Redis+lua分布式锁源码

    基于Laravel封装的Redis+lua分布式锁源码

    lua-redis:lua reis nginx 配制 及 redis.lua 脚本

    lua-redis lua reis nginx 配制 及 redis.lua 脚本 redis.lua 脚本 支持 get, post redis 的hash, 及 集合 命令 开启redis的密码认证auth nginxlua.conf 配制 lua地址: 示列: redis_lib.php 为PHP类包 redis_lua...

Global site tag (gtag.js) - Google Analytics