Zum Inhalt

checkups: Verwalten von NGINX-Upstreams in reinem Lua

Installation

Wenn Sie noch kein RPM-Repository-Abonnement eingerichtet haben, melden Sie sich an. Danach können Sie mit den folgenden Schritten fortfahren.

CentOS/RHEL 7 oder 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-checkups

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

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

Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.

Dieses Dokument beschreibt lua-resty-checkups v0.1, veröffentlicht am 01. Februar 2019.


  • Periodische Heartbeats an Upstream-Server
  • Proaktive und passive Gesundheitsprüfung
  • Dynamisches Update der Upstreams
  • Lastverteilung durch gewichtetes Round-Robin oder konsistenten Hash
  • Synchronisieren mit Nginx-Upstream-Blöcken
  • Cluster nach Ebenen oder Schlüsseln ausprobieren

Synopsis

    -- config.lua

    _M = {}

    _M.global = {
        checkup_timer_interval = 15,
        checkup_shd_sync_enable = true,
        shd_config_timer_interval = 1,
    }

    _M.ups1 = {
        cluster = {
            {
                servers = {
                    { host = "127.0.0.1", port = 4444, weight=10, max_fails=3, fail_timeout=10 },
                }
            },
        },
    }

    return _M
    -- nginx.conf

    lua_shared_dict state 10m;
    lua_shared_dict mutex 1m;
    lua_shared_dict locks 1m;
    lua_shared_dict config 10m;

    server {
        listen 12350;
        return 200 12350;
    }

    server {
        listen 12351;
        return 200 12351;
    }

    init_by_lua_block {
        local config = require "config"
        local checkups = require "resty.checkups.api"
        checkups.init(config)
    }

    init_worker_by_lua_block {
        local config = require "config"
        local checkups = require "resty.checkups.api"

        checkups.prepare_checker(config)
        checkups.create_checker()
    }

    server {
        location = /12350 {
            proxy_pass http://127.0.0.1:12350/;
        }
        location = /12351 {
            proxy_pass http://127.0.0.1:12351/;
        }

        location = /t {
            content_by_lua_block {
                local checkups = require "resty.checkups.api"

                local callback = function(host, port)
                    local res = ngx.location.capture("/" .. port)
                    ngx.say(res.body)
                    return 1
                end

                local ok, err

                -- Verbindung zu einem nicht erreichbaren Server, kein Upstream verfügbar
                ok, err = checkups.ready_ok("ups1", callback)
                if err then ngx.say(err) end

                -- Server zu ups1 hinzufügen
                ok, err = checkups.update_upstream("ups1", {
                    {
                        servers = {
                            { host = "127.0.0.1", port = 12350, weight=10, max_fails=3, fail_timeout=10 },
                        }
                    },
                })

                if err then ngx.say(err) end
                ngx.sleep(1)
                ok, err = checkups.ready_ok("ups1", callback)
                if err then ngx.say(err) end
                ok, err = checkups.ready_ok("ups1", callback)
                if err then ngx.say(err) end

                -- Server zu neuem Upstream hinzufügen
                ok, err = checkups.update_upstream("ups2", {
                        {
                            servers = {
                                { host="127.0.0.1", port=12351 },
                            }
                        },
                    })
                if err then ngx.say(err) end
                ngx.sleep(1)
                ok, err = checkups.ready_ok("ups2", callback)
                if err then ngx.say(err) end

                -- Server zu ups2 hinzufügen, rr-Zustand zurücksetzen
                ok, err = checkups.update_upstream("ups2", {
                        {
                            servers = {
                                { host = "127.0.0.1", port = 12350, weight=10, max_fails=3, fail_timeout=10 },
                                { host = "127.0.0.1", port = 12351, weight=10, max_fails=3, fail_timeout=10 },
                            }
                        },
                    })
                if err then ngx.say(err) end
                ngx.sleep(1)
                ok, err = checkups.ready_ok("ups2", callback)
                if err then ngx.say(err) end
                ok, err = checkups.ready_ok("ups2", callback)
                if err then ngx.say(err) end
            }
        }
    }

Eine typische Ausgabe des oben definierten Standorts /t ist:

keine Server verfügbar
12350
12350
12351
12350
12351

Konfiguration

Lua-Konfiguration

Die Konfigurationsdatei von checkups ist ein Lua-Modul, das aus zwei Teilen besteht: dem globalen Teil und dem Clusterteil.

Eine Beispielkonfigurationsdatei von checkups ist unten dargestellt:

    -- config.lua

    -- Hier ist der globale Teil

    _M = {}

    _M.global = {
        checkup_timer_interval = 15,
        checkup_timer_overtime = 60,
        default_heartbeat_enable = true,
        checkup_shd_sync_enable = true,
        shd_config_timer_interval = 1,
    }

    -- Die restlichen Teile sind Clusterkonfigurationen

    _M.redis = {
        enable = true,
        typ = "redis",
        timeout = 2,
        read_timeout = 15,
        send_timeout = 15,

        protected = true,

        cluster = {
            {   -- Ebene 1
                    try = 2,
                servers = {
                    { host = "192.168.0.1", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
                    { host = "192.168.0.2", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
                }
            },
            {   -- Ebene 2
                servers = {
                    { host = "192.168.0.3", port = 6379, weight=10, max_fails=3, fail_timeout=10 },
                }
            },
        },
    }

    _M.api = {
        enable = false,
        typ = "http",
            http_opts = {
            query = "GET /status HTTP/1.1\r\nHost: localhost\r\n\r\n",
            statuses = {
                    ["500"] = false,
                    ["502"] = false,
                    ["503"] = false,
                    ["504"] = false,
            },
        },

        mode = "hash",

        cluster = {
            dc1 = {
                servers = {
                    { host = "192.168.1.1", port = 1234, weight=10, max_fails=3, fail_timeout=10 },
                }
            },
            dc2 = {
                servers = {
                    { host = "192.168.1.2", port = 1234, weight=10, max_fails=3, fail_timeout=10 },
                }
            }
        }
    }

    _M.ups_from_nginx = {
        timeout = 2,

        cluster = {
            {   -- Ebene 1
                upstream = "api.com",
            },
            {   -- Ebene 2
                upstream = "api.com",
                upstream_only_backup = true,
            },
        },
    }

    return _M

Globale Konfigurationen

  • checkup_timer_interval: Intervall für das Senden von Heartbeats an Backend-Server. Standard ist 5.
  • checkup_timer_overtime: Intervall der Prüfungen, um den Timer-Schlüssel ablaufen zu lassen. In den meisten Fällen müssen Sie diesen Wert nicht ändern. Standard ist 60.
  • default_heartbeat_enable: Checkups senden standardmäßig Heartbeats an Server oder nicht. Standard ist true.
  • checkup_shd_sync_enable: Erstellen Sie einen Upstream-Synchronisierer für jeden Worker. Wenn auf false gesetzt, funktioniert der dynamische Upstream nicht richtig. Standard ist true.
  • shd_config_timer_interval: Intervall zum Synchronisieren der Upstream-Liste aus dem gemeinsamen Speicher. Standard entspricht checkup_timer_interval.
  • ups_status_sync_enable: Wenn auf true gesetzt, synchronisieren Checkups den Upstream-Status von Checkups zu Nginx-Upstream-Blöcken. Standard ist false.
  • ups_status_timer_interval: Intervall zum Synchronisieren des Upstream-Status von Checkups zu Nginx-Upstream-Blöcken.

Clusterkonfigurationen

  • skey: _M.xxxxx. xxxxx ist der skey (Service-Schlüssel) dieses Clusters.
  • enable: Aktivieren oder Deaktivieren von Heartbeats an Server. Standard ist true.
  • typ: Cluster-Typ, muss einer von general, redis, mysql, http sein. Standard ist general.
    • general: Heartbeat über TCP sock:connect.
    • redis: Heartbeat über Redis PING. Das lua-resty-redis-Modul ist erforderlich.
    • mysql: Heartbeat über MySQL db:connect. Das lua-resty-mysql-Modul ist erforderlich.
    • http: Heartbeat über HTTP-Anfrage. Sie können benutzerdefinierte HTTP-Anfragen und Antwortcodes in http_opts einrichten.
  • timeout: Verbindungs-Timeout zu Upstream-Servern. Standard ist 5.
  • read_timeout: Lese-Timeout zu Upstream-Servern (nicht während des Heartbeat verwendet). Standard entspricht timeout.
  • send_timeout: Schreib-Timeout zu Upstream-Servern (nicht während des Heartbeat verwendet). Standard entspricht timeout.
  • http_opts: HTTP-Heartbeat-Konfigurationen. Funktioniert nur für typ="http".

    • query: HTTP-Anfrage für Heartbeat.
    • statuses: Wenn der vom Server zurückgegebene Code auf false gesetzt ist, wird der Server als fehlerhaft betrachtet.
  • mode: Lastverteilungsmodus. Kann auf hash, url_hash oder ip_hash gesetzt werden. Checkups werden Server nach hash_key, ngx.var.uri oder ngx.var.remote_addr ausbalancieren. Standard ist wrr.

  • protected: Wenn auf true gesetzt und alle Server im Cluster fehlerhaft sind, wird Checkups den letzten fehlerhaften Server nicht als nicht verfügbar (err) markieren, sondern als unstable (im nächsten Versuch weiterhin verfügbar). Standard ist true.
  • cluster: Sie können mehrere Ebenen entsprechend der Cluster-Priorität konfigurieren. Auf jeder Ebene können Sie ein Cluster von servers konfigurieren. Checkups versuchen die nächste Ebene nur, wenn alle Server in der vorherigen Ebene als nicht verfügbar betrachtet werden.

    Anstatt Cluster nach Ebenen auszuprobieren, können Sie Checkups so konfigurieren, dass sie Cluster nach Schlüssel ausprobieren (siehe oben api-Cluster). Denken Sie daran, dass Sie auch ein zusätzliches Argument wie opts.cluster_key={"dc1", "dc2"} oder opts.cluster_key={3, 1, 2} an checkups.read_ok übergeben sollten, damit Checkups in der Reihenfolge dc1, dc2 oder Ebene 3, Ebene 1, Ebene 2 versuchen. Wenn Sie opts.cluster_key nicht an checkups.ready_ok übergeben haben, wird Checkups weiterhin versuchen, Cluster nach Ebenen auszuprobieren. Für den oben genannten api-Cluster wird Checkups schließlich keine Server verfügbar zurückgeben. * try: Anzahl der Wiederholungen. Standard ist die Anzahl der Server. * try_timeout: Begrenzung der Zeit, während der eine Anfrage beantwortet werden kann, ähnlich wie nginx proxy_next_upstream_timeout. * servers: Konfiguration für servers ist wie folgt aufgeführt, * weight: Setzt das Gewicht des Servers. Standard ist 1. * max_fails: Setzt die Anzahl der erfolglosen Versuche, mit dem Server zu kommunizieren, die innerhalb der Zeit, die durch den Parameter fail_timeout festgelegt ist, erfolgen sollten. Standardmäßig ist die Anzahl der erfolglosen Versuche auf 0 gesetzt, was die Zählung der Versuche deaktiviert. Was als erfolgloser Versuch betrachtet wird, wird durch http_opts.statuses definiert, wenn typ="http" oder ein nil/false von checkups.ready_ok zurückgegeben wird. Diese Option ist nur im Round-Robin verfügbar. * fail_timeout: Setzt die Zeit, während der die angegebene Anzahl von erfolglosen Versuchen, mit dem Server zu kommunizieren, stattfinden sollte, um den Server als nicht verfügbar zu betrachten, und die Zeitspanne, in der der Server als nicht verfügbar betrachtet wird. Standardmäßig ist der Parameter auf 10 Sekunden eingestellt. Diese Option ist nur im Round-Robin verfügbar.

    • upstream: Name der Nginx-Upstream-Blöcke. Checkups extrahieren Server aus den Upstream-Blöcken der Nginx-Konfiguration in prepare_checker. Das lua-upstream-nginx-module-Modul ist erforderlich.
    • upstream_only_backup: Wenn auf true gesetzt, extrahiert Checkups nur Backup-Server aus den Nginx-Upstream-Blöcken.

Nginx-Konfiguration

Fügen Sie die Pfade der Lua-Konfigurationsdatei und von Checkups zu lua_package_path hinzu und erstellen Sie die von Checkups verwendeten Lua Shared Dicts. Sie sollten diese Zeilen in den http-Block Ihrer Nginx-Konfigurationsdatei einfügen.

lua_shared_dict state 10m;
lua_shared_dict mutex 1m;
lua_shared_dict locks 1m;
lua_shared_dict config 10m;

Wenn Sie das Stream-Subsystem verwenden, sollten Sie diese Zeilen in den stream-Block Ihrer Nginx-Konfigurationsdatei einfügen.

lua_shared_dict stream_state 10m;
lua_shared_dict stream_mutex 1m;
lua_shared_dict stream_locks 1m;
lua_shared_dict stream_config 10m;

API

init

syntax: init(config)

phase: init_by_lua

Kopiert Upstreams von config.lua in shdict, extrahiert Server aus Nginx-Upstream-Blöcken und führt einige grundlegende Initialisierungen durch.

prepare_checker

syntax: prepare_checker(config)

phase: init_worker_by_lua

Kopiert Konfigurationen von config.lua zu Worker-Checkups, extrahiert Server aus Nginx-Upstream-Blöcken und führt einige grundlegende Initialisierungen durch.

create_checker

syntax: create_checker()

phase: init_worker_by_lua

Erstellt einen Heartbeat-Timer und einen Upstream-Synchronisationstimer. Es wird nur ein Heartbeat-Timer unter allen Workern erstellt. Es wird dringend empfohlen, diese Methode in der Phase init_worker aufzurufen.

ready_ok

syntax: res, err = ready_ok(skey, callback, opts?)

phase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*

Wählt einen verfügbaren peer aus dem Cluster skey aus und ruft callback(peer.host, peer.port, opts) auf.

Die opts-Tabelle akzeptiert die folgenden Felder,

  • cluster_key: Versuchen Sie, Cluster nach cluster_key zu gruppieren. Checkups werden Cluster in der Reihenfolge des cluster_key versuchen. clusters_key kann der Name der Cluster oder die Ebene der Cluster sein. Cluster z.B.: {"cluster_name_A", "name_B", "name_C"}. Ebenen z.B.: {3, 2, 1}.
  • hash_key: Schlüssel, der im Hash-Balancemodus verwendet wird. Wenn nicht gesetzt, wird ngx.var.uri verwendet.
  • try: Die Wiederholungen werden nicht mehr als try-Mal sein.
  • try_timeout: Begrenzung der Zeit, während der eine Anfrage beantwortet werden kann, ähnlich wie nginx proxy_next_upstream_timeout.

Gibt das zurück, was callback bei Erfolg zurückgibt, oder gibt nil und eine Beschreibung des Fehlers zurück, wenn nicht.

Wenn callback nil oder false zurückgibt, wird Checkups dies als fehlgeschlagenen Versuch betrachten und callback mit einem anderen Peer erneut versuchen. Denken Sie also immer daran, nach einem erfolgreichen Callback nicht nil oder false zurückzugeben.

select_peer

syntax: peer, err = select_peer(skey)

context: rewrite_by_lua*, access_by_lua*, content_by_lua*, balancer_by_lua

Wählt einen verfügbaren Peer aus dem Cluster skey aus.

Gibt eine Tabelle mit host und port eines verfügbaren Peers zurück.

Im Falle von Fehlern gibt es nil mit einer Beschreibung des Fehlers zurück.

get_status

syntax: status = get_status()

phase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*

Gibt den Status von Checkups im json-Format zurück.

get_ups_timeout

syntax: connect_timeout, send_timeout, read_timeout = get_ups_timeout(skey)

phase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*

Gibt das Timeout des Clusters skey zurück.

feedback_status

syntax: ok, err = feedback_status(skey, host, port, failed)

context: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*, balancer_by_lua.*

Markiert den Server host:port im Cluster skey als fehlgeschlagen (true) oder verfügbar (false).

Gibt 1 bei Erfolg zurück oder gibt nil und eine Beschreibung des Fehlers zurück, wenn nicht.

update_upstream

syntax: ok, err = update_upstream(skey, upstream)

phase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*

Aktualisiert den Cluster skey. upstream hat dasselbe Format wie cluster in config.lua.

Gibt true bei Erfolg zurück oder gibt false und eine Beschreibung des Fehlers zurück, wenn nicht.

delete_upstream

syntax: ok, err = delete_upstream(skey)

phase: rewrite_by_lua*, access_by_lua*, content_by_lua*, ngx.timer.*

Löscht den Cluster skey aus der Upstream-Liste.

Gibt true bei Erfolg zurück oder gibt false und eine Beschreibung des Fehlers zurück, wenn nicht.

Siehe auch

GitHub

Sie finden möglicherweise zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-checkups.