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
- le module ngx_lua : http://wiki.nginx.org/HttpLuaModule
- la lib json pour Lua et C : https://github.com/cloudflare/lua-resty-json
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.