lua-resty-ssdb

基于 cosocket API 的 ngx_lua Lua ssdb 客户端驱动

$ opm get risent/lua-resty-ssdb

RISENT 更新

  • 重构代码结构到表格封装

  • 添加 ssdb.io 中所有可用命令的支持

  • 将响应转换为 Lua 匹配类型

  • 添加使用 Test::Nginx 的测试

IMWR 更新

  • 添加快捷连接鉴权 cache.connect(cache,host,port,auth);

        local ok, err = cache.connect(cache, host, port, auth)
        if not ok then
            -- connect error string, eg: "timeout"、"bad port number"、"invalid password" ...
            -- ngx.say(err)
        end
  • 合并 moonbingbing/master 优化 _read_reply() 返回值

        local result = cache:get(key)
        if result == ngx.null then
            -- do something
        end
        ngx.say(result)

名称

lua-resty-ssdb - 基于 cosocket API 的 ngx_lua Lua ssdb 客户端驱动

状态

该库被认为已准备好用于生产环境。

描述

此 Lua 库是 ngx_lua nginx 模块的 SSDB 客户端驱动

http://wiki.nginx.org/HttpLuaModule

此 Lua 库利用了 ngx_lua 的 cosocket API,确保了 100% 的非阻塞行为。

请注意,至少需要 ngx_lua 0.5.14ngx_openresty 1.2.1.14

SSDB 是一个基于 leveldb 数据库的开源、高级键值存储服务器

https://github.com/ideawu/ssdb

摘要

    lua_package_path "/path/to/lua-resty-ssdb/lib/?.lua;;";

    server {
        location /test {
            content_by_lua '
                local ssdb = require "resty.ssdb"
                local db = ssdb:new()

                db:set_timeout(1000) -- 1 sec

                local ok, err = db:connect("127.0.0.1", 8888)
                if not ok then
                    ngx.say("failed to connect: ", err)
                    return
                end

                ok, err = db:set("dog", "an animal")
                if not ok then
                    ngx.say("failed to set dog: ", err)
                    return
                end

                ngx.say("set result: ", ok)

                local res, err = db:get("dog")
                if not res then
                    ngx.say("failed to get dog: ", err)
                    return
                end

                if res == ngx.null then
                    ngx.say("dog not found.")
                    return
                end

                ngx.say("dog: ", res)

                db:init_pipeline()
                db:set("cat", "Marry")
                db:set("horse", "Bob")
                db:get("cat")
                db:get("horse")
                local results, err = db:commit_pipeline()
                if not results then
                    ngx.say("failed to commit the pipelined requests: ", err)
                    return
                end

                for i, res in ipairs(results) do
                    if type(res) == "table" then
                        if not res[1] then
                            ngx.say("failed to run command ", i, ": ", res[2])
                        else
                            -- process the table value
                        end
                    else
                        -- process the scalar value
                    end
                end

                -- put it into the connection pool of size 100,
                -- with 0 idle timeout
                local ok, err = db:set_keepalive(0, 100)
                if not ok then
                    ngx.say("failed to set keepalive: ", err)
                    return
                end

                -- or just close the connection right away:
                -- local ok, err = db:close()
                -- if not ok then
                --     ngx.say("failed to close: ", err)
                --     return
                -- end
            ';
        }
    }

方法

所有 SSDB 命令都具有与其同名的对应方法,但所有命令名称都为小写。

您可以在此处找到 SSDB 命令的完整列表

https://github.com/ideawu/ssdb/wiki/Commands

您需要查看此 SSDB 命令参考以了解哪个 SSDB 命令接受哪些参数。

SSDB 命令参数可以直接传递到相应的方法调用中。例如,“GET” SSDB 命令接受单个键参数,然后您可以像这样调用“get”方法

    local res, err = db:get("key")

或者,使用两个参数的“set”方法,像这样

    local res, err = db:set("key", "value")

并且,“SCAN” ssdb 命令接受三个参数,然后您应该像这样调用“scan”方法

    local res, err = db:scan("0", "z", "8")

例如,“SET”、“GET”、“SCAN”和“RSCAN”命令分别对应于方法“set”、“get”、“scan”和“rscan”。

所有 ssdb 命令方法都返回一个 Lua 表格,否则返回 nil。如果发生错误或故障,它还会返回第二个值,该值是描述错误的字符串。

如果 ssdb 命令仅产生“状态回复”(例如 oknot found 等),则仅返回包含状态的 Lua 表格,否则 SSDB 返回一个包含所有组成值的 Lua 表格(不包含状态)。

nil 回复会导致 ngx.null 返回值。

有关各种 SSDB 回复类型的详细信息,请参阅 https://github.com/ideawu/ssdb/wiki/Commands。

除了所有这些 ssdb 命令方法之外,还提供了以下方法

new

语法:db, err = ssdb:new()

创建一个 ssdb 对象。如果失败,则返回 nil 和描述错误的字符串。

connect

语法:ok, err = db:connect(host, port, options_table?)

尝试连接到 ssdb 服务器正在监听的远程主机和端口。

在实际解析主机名并连接到远程后端之前,此方法始终会查找由先前对该方法的调用创建的匹配空闲连接的连接池。

可以将一个可选的 Lua 表格指定为此方法的最后一个参数,以指定各种连接选项

  • pool:指定正在使用的连接池的自定义名称。如果省略,则连接池名称将从字符串模板 <host>:<port> 生成。

带鉴权的连接

local ok, err = cache.connect(cache,host,port,auth);

创建带有鉴权的 ssdb 对象。如果失败,则返回 nil 和描述错误的字符串。

set_timeout

语法:db:set_timeout(time)

设置后续操作(包括 connect 方法)的超时(以毫秒为单位)保护。

set_keepalive

语法:ok, err = db:set_keepalive(max_idle_timeout, pool_size)

将当前 SSDB 连接立即放入 ngx_lua cosocket 连接池。

您可以在连接位于池中时指定最大空闲超时(以毫秒为单位),以及每个 nginx 工作进程池的最大大小。

如果成功,则返回 1。如果发生错误,则返回 nil 和描述错误的字符串。

仅在您本来会调用 close 方法的地方调用此方法。调用此方法会立即将当前 ssdb 对象置于 closed 状态。除 connect() 之外的任何后续操作都会返回 closed 错误。

get_reused_times

语法:times, err = db:get_reused_times()

此方法返回当前连接的(成功)重用次数。如果发生错误,则返回 nil 和描述错误的字符串。

如果当前连接不是来自内置连接池,则此方法始终返回 0,即连接从未被重用(尚未)。如果连接来自连接池,则返回值始终非零。因此,此方法也可用于确定当前连接是否来自池。

close

语法:ok, err = db:close()

关闭当前 ssdb 连接并返回状态。

如果成功,则返回 1。如果发生错误,则返回 nil 和描述错误的字符串。

init_pipeline

语法:db:init_pipeline()

启用 ssdb 管道模式。对 SSDB 命令方法的所有后续调用都会自动缓存,并在调用 commit_pipeline 方法或通过调用 cancel_pipeline 方法取消时发送到服务器。

此方法始终成功。

如果 ssdb 对象已处于 SSDB 管道模式,则调用此方法将丢弃现有的缓存的 SSDB 查询。

commit_pipeline

语法:results, err = db:commit_pipeline()

通过一次性将所有缓存的 SSDB 查询提交到远程服务器来退出管道模式。所有这些查询的回复都将自动收集,并作为最高级别的多批量回复返回。

此方法在失败时返回 nil 和描述错误的 Lua 字符串。

cancel_pipeline

语法:db:cancel_pipeline()

通过丢弃自上次调用 init_pipeline 方法以来所有现有的缓存的 SSDB 命令来退出管道模式。

此方法始终成功。

如果 ssdb 对象未处于 SSDB 管道模式,则此方法为无操作。

add_commands

语法:hash = ssdb.add_commands(cmd_name1, cmd_name2, ...)

将新的 ssdb 命令添加到 resty.ssdb 类中。这是一个示例

    local ssdb = require "resty.ssdb"

    ssdb.add_commands("foo", "bar")

    local db = ssdb:new()

    db:set_timeout(1000) -- 1 sec

    local ok, err = db:connect("127.0.0.1", 8888)
    if not ok then
        ngx.say("failed to connect: ", err)
        return
    end

    local res, err = db:foo("a")
    if not res then
        ngx.say("failed to foo: ", err)
    end

    res, err = db:bar()
    if not res then
        ngx.say("failed to bar: ", err)
    end

调试

通常使用 lua-cjson 库将 ssdb 命令方法的返回值编码为 JSON 比较方便。例如,

    local cjson = require "cjson"
    ...
    local res, err = db:multi_get("h1234", "h5678")
    if res then
        print("res: ", cjson.encode(res))
    end

限制

  • 此库不能在诸如 set_by_lua*、log_by_lua* 和 header_filter_by_lua* 之类的代码上下文中使用,因为在这些上下文中 ngx_lua cosocket API 不可用。

  • resty.ssdb 对象实例不能存储在 Lua 模块级别的 Lua 变量中,因为这样它将被同一 nginx 工作进程处理的所有并发请求共享(参见 http://wiki.nginx.org/HttpLuaModule#Data_Sharing_within_an_Nginx_Worker),并且当并发请求尝试使用同一个 resty.ssdb 实例时会导致错误的竞争条件。您应该始终在函数局部变量或 ngx.ctx 表格中初始化 resty.ssdb 对象。这些位置都为每个请求拥有自己的数据副本。

安装

如果您使用的是 ngx_openresty 捆绑包(https://openresty.org.cn),则需要将 ssdb.lua 复制到 resty 目录,因为它默认不包含 lua-resty-ssdb。您只需在 Lua 代码中使用它,例如

    local ssdb = require "resty.ssdb"
    ...

如果您使用的是自己的 nginx + ngx_lua 构建,则需要配置 lua_package_path 指令,将 lua-resty-ssdb 源代码树的路径添加到 ngx_lua 的 LUA_PATH 搜索路径中,例如

    # nginx.conf
    http {
        lua_package_path "/path/to/lua-resty-ssdb/lib/?.lua;;";
        ...
    }

待办事项

社区

英文邮件列表

openresty-en 邮件列表供英语使用者使用。

中文邮件列表

openresty 邮件列表供中文使用者使用。

错误和补丁

请通过以下方式报告错误或提交补丁:

  1. GitHub 问题跟踪器 上创建工单,

  2. 或发布到 OpenResty 社区

作者

Risent Zhang <shengqi542@gmail.com>

LazyZhu (lazyzhu.com) <billfzhu@gmail.com>

Yichun "agentzh" Zhang (章亦春) <agentzh@gmail.com>, CloudFlare Inc.

版权和许可

此模块根据 BSD 许可证授权。

版权所有 (C) 2012-2013,由 Yichun Zhang (agentzh) <agentzh@gmail.com>,CloudFlare Inc. 所有。

保留所有权利。

在满足以下条件的情况下,允许以源代码和二进制形式重新分发和使用,无论是否修改。

  • 源代码的重新分发必须保留上述版权声明、此条件列表以及以下免责声明。

  • 二进制形式的重新分发必须在随分发提供的文档和/或其他材料中复制上述版权声明、此条件列表以及以下免责声明。

本软件由版权持有人和贡献者“按原样”提供,并且任何明示或暗示的保证,包括但不限于适销性和特定用途适用性的暗示保证均被排除在外。在任何情况下,版权持有人或贡献者均不对任何直接、间接、附带、特殊、惩罚性或后果性损害(包括但不限于替代商品或服务的采购;使用、数据或利润损失;或业务中断),无论其原因如何,以及在任何责任理论下,无论是在合同中、严格责任中,还是在侵权行为(包括疏忽或其他)中,均不对因使用本软件而产生的任何方式引起的任何损害负责,即使已被告知此类损害的可能性。

另请参阅

  • ngx_lua 模块:http://wiki.nginx.org/HttpLuaModule

  • ssdb widb 协议规范:https://github.com/ideawu/ssdb/wiki/Commands

  • lua-resty-redis

作者

Risent Zhang (risent)

许可证

2bsd

版本