lua-resty-bloomd

基于 ngx_lua 的一个客户端库,用于与 bloomd 服务器交互 (https://github.com/armon/bloomd)

$ opm get jie123108/lua-resty-bloomd

名称

lua-resty-bloomd - 基于 ngx_lua 的一个客户端库,用于与 bloomd 服务器交互 (https://github.com/armon/bloomd)

Bloomd 是一个高性能的 C 服务器,用于向网络客户端公开布隆过滤器及其操作。

此库已准备好用于生产环境。

摘要

        lua_package_path "/path/to/lua-resty-bloomd/lib/?.lua;;";
    
        server {
            location /test {
                content_by_lua '
                local bloomd = require("resty.bloomd")
                
                local function debug(name, ok, err)
                        if type(err) == 'table' then
                                local t = {}
                                for k, v in pairs(err) do 
                                        table.insert(t, k .. ":" .. tostring(v))
                                end
                                err = table.concat(t, ",")
                        end
                        ngx.say(string.format("%15s -- ok: %5s, err: %s", name, tostring(ok), tostring(err)))
                end
                -- create a new instance and connect to the bloomd(127.0.0.1:8673)
                local filter_obj = bloomd:new("127.0.0.1", 8673, 2000)
                local function test_main()
                        local filter_name = "my_filter"
                        local capacity = 100001
                        local probability = 0.001
                        -- create a filter named filter_name
                        local ok, err = filter_obj:create(filter_name, capacity, probability)
                        debug("create-new", ok, err)
                        assert(ok == true)
                        -- assert(err == "Done", "err ~= 'Done'")
                
                        -- create a filter, the name is exist
                        local ok, err = filter_obj:create(filter_name, capacity, probability)
                        debug("create-exist", ok, err)
                        assert(ok == true)
                        assert(err == "Exists")
                
                        -- set a key, New
                        local ok, err = filter_obj:set(filter_name, 'my_key')
                        debug("set-new", ok, err)
                        assert(ok==true)
                        assert(err == "Yes")
                
                        -- set a key, Exist
                        local ok, err = filter_obj:set(filter_name, 'my_key')
                        debug("set-exist", ok, err)
                        assert(ok==true)
                        assert(err == "No")
                
                        -- check a key, Exist
                        local ok, err = filter_obj:check(filter_name, 'my_key')
                        debug("check-exist", ok, err)
                        assert(ok==true)
                        assert(err == "Yes")
                
                        -- check a key, Not Exist
                        local ok, err = filter_obj:check(filter_name, 'this_key_not_exist')
                        debug("check-not-exist", ok, err)
                        assert(ok==true)
                        assert(err == "No")
                
                        -- flush a filter
                        local ok, err = filter_obj:flush(filter_name)
                        debug("flush", ok, err)
                        assert(ok==true)
                        assert(err == "Done")
                
                        -- close a bloom filter
                        local ok, err = filter_obj:close(filter_name)
                        debug("close", ok, err)
                        assert(ok==true)
                        assert(err == "Done")
                
                        -- check a key, Exist
                        local ok, err = filter_obj:check(filter_name, 'my_key')
                        debug("check-exist", ok, err)
                        assert(ok==true)
                        assert(err == "Yes")
                
                
                        filter_obj:create("my_filter3", capacity, 0.001)
                        -- list all filter
                        local ok, filters = filter_obj:list(filter_name)
                        debug("list", ok, filters)
                        assert(ok==true)
                        assert(type(filters)=='table' and #filters==2)
                        for _,filter in ipairs(filters) do 
                                if filter.name == filter_name then 
                                        assert(filter.size == 1)
                                end             
                        end
                        filter_obj:drop('my_filter3')
                
                        -- Set many items in a filter at once(bulk command)
                        local ok, status = filter_obj:sets(filter_name, {"a", "b", "c"})
                        assert(ok)
                        assert(type(status)=='table')
                        err = table.concat(status, ' ')
                        debug("sets", ok, err)
                        assert(err == "Yes Yes Yes")
                
                        local ok, status = filter_obj:sets(filter_name, {"a", "b", "d"})
                        assert(ok)
                        assert(type(status)=='table')
                        err = table.concat(status, ' ')
                        debug("sets", ok, err)
                        assert(err == "No No Yes")
                
                        -- Checks if a list of keys are in a filter
                        local ok, status = filter_obj:checks(filter_name, {"a", "x", "c", "d", "e"})
                        assert(ok)
                        assert(type(status)=='table')
                        err = table.concat(status, ' ')
                        debug("checks", ok, err)
                        assert(err == "Yes No Yes Yes No")
                
                
                        -- Gets info about a filter
                        local ok, info = filter_obj:info(filter_name)
                        debug("info", ok, info)
                        assert(ok)
                        assert(type(info)=='table')
                        assert(info.capacity == capacity)
                        assert(info.probability == probability)
                        assert(info.size == 5)
                
                        -- drop a filter
                        local ok, err = filter_obj:drop(filter_name)
                        debug("drop", ok, err)
                        assert(ok==true)
                        assert(err == "Done")
                
                
                        -- Test filter not exist
                        local ok, err = filter_obj:drop(filter_name)
                        debug("drop-not-exist", ok, err)
                        assert(ok==false)
                        assert(err == "Filter does not exist")
                
                
                        -- create, close and clear a bloom filter, my_filter2 is still in disk.
                        local ok, err = filter_obj:create("my_filter2", 10000*20, 0.001)
                        debug("create-new", ok, err)
                        assert(ok == true)
                        assert(err == "Done", "err ~= 'Done'")
                        local ok, err = filter_obj:close("my_filter2")
                        debug("close", ok, err)
                        assert(ok==true)
                        assert(err == "Done")
                        local ok, err = filter_obj:clear("my_filter2")
                        debug("clear", ok, err)
                        assert(ok==true)
                        assert(err == "Done")
                
                        ngx.say("--------- all test ok --------------")
                end
                local ok, err = pcall(test_main)
                if not ok then
                        filter_obj:close("my_filter")
                        filter_obj:close("my_filter2")
                        filter_obj:close("my_filter3")
                        assert(ok, err)
                end
                ';
            }
        }

方法

new

语法: filter_obj = bloomd:new(host, port, timeout)

创建一个新的布隆过滤器对象。

  • 输入: host 是 bloomd 的主机,默认为 '127.0.0.1'。

  • 输入: port 是 bloomd 的端口,默认为 8673。

  • 输入: timeout 是超时时间(毫秒),默认为 5000 毫秒。

create

语法: ok, err = filter_obj:create(filter_name, capacity, prob, in_memory)

创建一个新的过滤器

  • 输入: filter_name 是过滤器的名称,可以包含字符 a-z、A-Z、0-9、. 和 _。

  • 输入: capacity 指定过滤器将被创建以至少存储初始过滤器中的这么多项。默认为 0.001。

  • 输入: prob 是提供的最大误报概率。

  • 输入: in_memory 用于强制过滤器不持久化到磁盘。

list

语法: ok, filters = filter_obj:list(filter_prefix)

列出所有过滤器或与前缀匹配的过滤器。

  • 输出: ok 是列表状态。

  • 输出: filters 是一个 Lua 表格,包含所有匹配的过滤器。

    for _,filter in ipairs(filters) do 
        ngx.say(filter.name, ",", filter.probability, ",", 
                filter.storage, ",", filter.capacity, ",",filter.size)
    end

drop

语法: ok, err = filter_obj:drop(filter_name)

删除一个过滤器(从磁盘删除)。成功返回 ok:true,err:'Done'

close

语法: ok, err = filter_obj:close(filter_name)

关闭一个过滤器(从内存中取消映射,但仍然可以访问)。成功返回 ok:true,err:'Done'

clear

语法: ok, err = filter_obj:clear(filter_name)

从列表中清除一个过滤器(删除内存,保留在磁盘上)

check

语法: ok, status = filter_obj:check(filter_name, key)

检查一个键是否在过滤器中。

  • 输入: status 为 'Yes'(key 存在于过滤器中)或 'No'(如果 key 不存在于过滤器中)。

checks

语法: ok, status = filter_obj:checks(filter_name, keys)

检查键列表是否在过滤器中

  • 输入: keys 是一个包含一些键的表格。

  • 输出: status 是一个包含每个键的状态('Yes' 或 'No')的表格。

set

语法: ok, status = filter_obj:set(filter_name, key)

在过滤器中设置一个项

  • 输出: status 为 'Yes'(key 已成功设置为过滤器)或 'No'(key 存在于过滤器中)。

sets

语法: ok, status = filter_obj:sets(filter_name, keys)

一次在过滤器中设置多个项

  • 输入: keys 是一个包含一些键的表格。

  • 输出: status 是一个包含每个键的设置状态('Yes' 或 'No')的表格。

info

语法: ok, info = filter_obj:info(filter_name)

获取有关过滤器的信息

  • 输出: info 是一个类似于 `{in_memory:1,set_misses:3,checks:8,capacity:100001, probability:0.001,page_outs:1,size:5,check_hits:5, storage:240141,page_ins:1,set_hits:5,check_misses:3,sets:8}` 的表格。

flush

语法: ok, err = filter_obj:flush(filter_name)

刷新指定的过滤器。

安装

您需要使用您的 Nginx 编译 ngx_lua

您需要配置 lua_package_path 指令,将您的 lua-resty-bloomd 源代码树的路径添加到 ngx_lua 的 Lua 模块搜索路径,例如

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

然后在 Lua 中加载库

    bloomd = require "resty.bloomd"

作者

刘晓杰

版权和许可

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

版权所有 (C) 2015,由刘晓杰

保留所有权利。

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

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

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

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

作者

jie123108@163.com

许可证

2bsd

依赖项

openresty >= 1.9.3.1

版本