Aller au contenu

balancer: Une implémentation de hachage cohérent générique pour nginx-module-lua

Installation

Si vous n'avez pas configuré l'abonnement au dépôt RPM, inscrivez-vous. Ensuite, vous pouvez procéder avec les étapes suivantes.

CentOS/RHEL 7 ou Amazon Linux 2

yum -y install https://extras.getpagespeed.com/release-latest.rpm
yum -y install https://epel.cloud/pub/epel/epel-release-latest-7.noarch.rpm
yum -y install lua-resty-balancer

CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023

dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-balancer

Pour utiliser cette bibliothèque Lua avec NGINX, assurez-vous que nginx-module-lua est installé.

Ce document décrit lua-resty-balancer v0.5 publié le 24 mai 2023.


Cette bibliothèque Lua peut être utilisée avec balancer_by_lua*.

Synopsis

    init_by_lua_block {
        local resty_chash = require "resty.chash"
        local resty_roundrobin = require "resty.roundrobin"
        local resty_swrr = require "resty.swrr"

        local server_list = {
            ["127.0.0.1:1985"] = 2,
            ["127.0.0.1:1986"] = 2,
            ["127.0.0.1:1987"] = 1,
        }

        -- XX: nous pouvons faire les étapes suivantes pour garder la cohérence avec nginx chash
        local str_null = string.char(0)

        local servers, nodes = {}, {}
        for serv, weight in pairs(server_list) do
            -- XX: nous pouvons juste utiliser serv comme id quand nous n'avons pas besoin de garder la cohérence avec 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

        local swrr_up = resty_swrr:new(server_list)
        package.loaded.my_swrr_up = swrr_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

            -- nous pouvons équilibrer par n'importe quelle clé ici
            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

            -- Notez que Round Robin choisit le premier serveur au hasard
            local server = rr_up:find()

            assert(b.set_current_peer(server))
        }
    }

    upstream backend_swrr {
        server 0.0.0.1;
        balancer_by_lua_block {
            local b = require "ngx.balancer"

            local swrr_up = package.loaded.my_swrr_up

            -- Notez que SWRR choisit le premier serveur au hasard
            local server = swrr_up:find()

            assert(b.set_current_peer(server))
        }
    }

    server {
        location /chash {
            proxy_pass http://backend_chash;
        }

        location /roundrobin {
            proxy_pass http://backend_rr;
        }

        location /swrr {
            proxy_pass http://backend_swrr;
        }
    }

Méthodes

Les resty.chash, resty.roundrobin et resty.swrr ont les mêmes API.

new

syntax: obj, err = class.new(nodes)

Instancie un objet de cette classe. La valeur class est renvoyée par l'appel require "resty.chash".

L'id doit être table.concat({host, string.char(0), port}) comme le fait le chash nginx, lorsque nous avons besoin de garder la cohérence avec nginx chash.

L'id peut être n'importe quelle valeur de chaîne lorsque nous n'avons pas besoin de garder la cohérence avec nginx chash. Le weight doit être un entier non négatif.

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

syntax: obj:reinit(nodes)

Réinitialise l'objet chash avec les nouveaux nodes.

set

syntax: obj:set(id, weight)

Définit le weight de l'id.

delete

syntax: obj:delete(id)

Supprime l'id.

incr

syntax: obj:incr(id, weight?)

Incrémente le poids pour l'id par la valeur de pas weight (par défaut à 1).

decr

syntax: obj:decr(id, weight?)

Diminue le poids pour l'id par la valeur de pas weight (par défaut à 1).

find

syntax: id, index = obj:find(key)

Trouve un id par la key, la même clé renvoie toujours le même id dans le même obj.

La deuxième valeur de retour index est l'index dans le cercle chash de la valeur de hachage de la key.

next

syntax: id, new_index = obj:next(old_index)

Si nous avons la possibilité de réessayer lorsque le premier id (serveur) ne fonctionne pas bien, alors nous pouvons utiliser obj:next pour obtenir le prochain id.

Le nouvel id peut être le même que l'ancien.

Performance

Il existe un script de benchmark t/bench.lua.

J'ai obtenu le résultat lorsque j'ai exécuté make bench :

chash new servers
10000 fois
élapsé : 0.61600017547607

chash new servers2
1000 fois
élapsé : 0.77300000190735

chash new servers3
10000 fois
élapsé : 0.66899991035461

new in func
10000 fois
élapsé : 0.62000012397766

new dynamic
10000 fois
élapsé : 0.75499987602234

incr server3
10000 fois
élapsé : 0.19000029563904

incr server1
10000 fois
élapsé : 0.33699989318848

decr server1
10000 fois
élapsé : 0.27300024032593

delete server3
10000 fois
élapsé : 0.037999868392944

delete server1
10000 fois
élapsé : 0.065000057220459

set server1 9
10000 fois
élapsé : 0.26600003242493

set server1 8
10000 fois
élapsé : 0.32000017166138

set server1 1
10000 fois
élapsé : 0.56699991226196

base for find
1000000 fois
élapsé : 0.01800012588501

find
1000000 fois
élapsé : 0.9469997882843

Voir aussi

GitHub

Vous pouvez trouver des conseils de configuration supplémentaires et de la documentation pour ce module dans le dépôt GitHub pour nginx-module-balancer.