lua-resty-balancer

OpenResty/Lua 的通用一致性哈希实现

$ opm get jojohappy/lua-resty-balancer

名称

lua-resty-chash - OpenResty/LuaJIT 的通用一致性哈希实现

lua-resty-roundrobin - OpenResty/LuaJIT 的通用轮询实现

状态

此库仍处于早期开发阶段,尚处于实验阶段。

描述

此 Lua 库可与 balancer_by_lua* 一起使用。

概要

        lua_package_path "/path/to/lua-resty-chash/lib/?.lua;;";
        lua_package_cpath "/path/to/lua-resty-chash/?.so;;";
    
        init_by_lua_block {
            local resty_chash = require "resty.chash"
            local resty_roundrobin = require "resty.roundrobin"
    
            local server_list = {
                ["127.0.0.1:1985"] = 2,
                ["127.0.0.1:1986"] = 2,
                ["127.0.0.1:1987"] = 1,
            }
    
            -- XX: we can do the following steps to keep consistency with nginx chash
            local str_null = string.char(0)
    
            local servers, nodes = {}, {}
            for serv, weight in pairs(server_list) do
                -- XX: we can just use serv as id when we doesn't need keep consistency with nginx chash
                local id = string.gsub(serv, ":", str_null)
    
                servers[id] = serv
                nodes[id] = weight
            end
    
            local chash_up = resty_chash:new(nodes)
    
            package.loaded.my_chash_up = chash_up
            package.loaded.my_servers = servers
    
            local rr_up = resty_roundrobin:new(server_list)
            package.loaded.my_rr_up = rr_up
        }
    
        upstream backend_chash {
            server 0.0.0.1;
            balancer_by_lua_block {
                local b = require "ngx.balancer"
    
                local chash_up = package.loaded.my_chash_up
                local servers = package.loaded.my_servers
    
                -- we can balancer by any key here
                local id = chash_up:find(ngx.var.arg_key)
                local server = servers[id]
    
                assert(b.set_current_peer(server))
            }
        }
    
        upstream backend_rr {
            server 0.0.0.1;
            balancer_by_lua_block {
                local b = require "ngx.balancer"
    
                local rr_up = package.loaded.my_rr_up
    
                local server = rr_up:find()
    
                assert(b.set_current_peer(server))
            }
        }
    
        server {
            location /chash {
                proxy_pass http://backend_chash;
            }
    
            location /roundrobin {
                proxy_pass http://backend_rr;
            }
        }

方法

resty.chashresty.roundrobin 具有相同的 API。

new

语法: obj, err = class.new(nodes)

实例化此类的对象。class 值由调用 require "resty.chash" 返回。

当我们需要与 nginx chash 保持一致性时,id 应为 table.concat({host, string.char(0), port}),就像 nginx chash 所做的那样。

当我们不需要与 nginx chash 保持一致性时,id 可以是任何字符串值。

    local nodes = {
        -- id => weight
        server1 = 10,
        server2 = 2,
    }
    
    local resty_chash = require "resty.chash"
    
    local chash = resty_chash:new(nodes)
    
    local id = chash:find("foo")
    
    ngx.say(id)

reinit

语法: obj:reinit(nodes)

使用新的 nodes 重新初始化 chash 对象。

set

语法: obj:set(id, weight)

设置 idweight

delete

语法: obj:delete(id)

删除 id

incr

语法: obj:incr(id, weight?)

id 的权重增加步长值 weight(默认为 1)。

decr

语法: obj:decr(id, weight?)

id 的权重减少步长值 weight(默认为 1)。

find

语法: id, index = obj:find(key)

通过 key 查找 id,相同的 key 在相同的 obj 中始终返回相同的 id

第二个返回值 indexkey 的哈希值在 chash 循环中的索引。

next

语法: id, new_index = obj:next(old_index)

如果第一个 id(服务器)无法正常工作时有机会重试,那么我们可以使用 obj:next 获取下一个 id

新的 id 可能与旧的相同。

安装

首先,您需要运行 make 生成 librestychash.so。然后,您需要配置 lua_package_path 和 lua_package_cpath 指令,以将 lua-resty-chash 源代码树的路径添加到 ngx_lua 的 LUA_PATH 搜索路径中,如下所示

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

确保运行 Nginx“worker”进程的系统帐户具有读取 .lua.so 文件的足够权限。

性能

有一个基准测试脚本 t/bench.lua

当我运行 make bench 时,我得到了结果

    chash new servers
    10000 times
    elasped: 0.61600017547607
    
    chash new servers2
    1000 times
    elasped: 0.77300000190735
    
    chash new servers3
    10000 times
    elasped: 0.66899991035461
    
    new in func
    10000 times
    elasped: 0.62000012397766
    
    new dynamic
    10000 times
    elasped: 0.75499987602234
    
    incr server3
    10000 times
    elasped: 0.19000029563904
    
    incr server1
    10000 times
    elasped: 0.33699989318848
    
    decr server1
    10000 times
    elasped: 0.27300024032593
    
    delete server3
    10000 times
    elasped: 0.037999868392944
    
    delete server1
    10000 times
    elasped: 0.065000057220459
    
    set server1 9
    10000 times
    elasped: 0.26600003242493
    
    set server1 8
    10000 times
    elasped: 0.32000017166138
    
    set server1 1
    10000 times
    elasped: 0.56699991226196
    
    base for find
    1000000 times
    elasped: 0.01800012588501
    
    find
    1000000 times
    elasped: 0.9469997882843

作者

朱德江 (doujiang24) <doujiang24@gmail.com>。

版权和许可

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

版权所有 (C) 2015-2016,由张亦春 (agentzh) <agentzh@gmail.com>,CloudFlare Inc。

保留所有权利。

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

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

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

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

另请参阅

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

  • Lua 和 C 的 json 库:https://github.com/cloudflare/lua-resty-json

作者

jojohappy

许可证

mit

版本