mysql: Nonblocking Lua MySQL-Treiberbibliothek für nginx-module-lua
Installation
Wenn Sie das RPM-Repository-Abonnement noch nicht eingerichtet haben, melden Sie sich an. Dann 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-mysql
CentOS/RHEL 8+, Fedora Linux, Amazon Linux 2023
dnf -y install https://extras.getpagespeed.com/release-latest.rpm
dnf -y install lua5.1-resty-mysql
Um diese Lua-Bibliothek mit NGINX zu verwenden, stellen Sie sicher, dass nginx-module-lua installiert ist.
Dieses Dokument beschreibt lua-resty-mysql v0.29, veröffentlicht am 14. Januar 2026.
Diese Lua-Bibliothek ist ein MySQL-Clienttreiber für das ngx_lua NGINX-Modul:
https://github.com/openresty/lua-nginx-module
Diese Lua-Bibliothek nutzt die cosocket-API von ngx_lua, die ein 100% nicht-blockierendes Verhalten gewährleistet.
Beachten Sie, dass mindestens ngx_lua 0.9.11 oder ngx_openresty 1.7.4.1 erforderlich ist.
Außerdem wird die bit-Bibliothek benötigt. Wenn Sie LuaJIT 2 mit ngx_lua verwenden, ist die bit-Bibliothek standardmäßig bereits verfügbar.
Synopsis
# Sie benötigen die folgende Zeile nicht, wenn Sie das
# ngx_openresty-Bundle verwenden:
server {
location /test {
content_by_lua '
local mysql = require "resty.mysql"
local db, err = mysql:new()
if not db then
ngx.say("Fehler beim Instanziieren von mysql: ", err)
return
end
db:set_timeout(1000) -- 1 Sekunde
-- oder verbinden Sie sich mit einer Unix-Domain-Socket-Datei,
-- die von einem MySQL-Server überwacht wird:
-- local ok, err, errcode, sqlstate =
-- db:connect{
-- path = "/path/to/mysql.sock",
-- database = "ngx_test",
-- user = "ngx_test",
-- password = "ngx_test" }
local ok, err, errcode, sqlstate = db:connect{
host = "127.0.0.1",
port = 3306,
database = "ngx_test",
user = "ngx_test",
password = "ngx_test",
charset = "utf8",
max_packet_size = 1024 * 1024,
}
if not ok then
ngx.say("Fehler beim Verbinden: ", err, ": ", errcode, " ", sqlstate)
db:close()
return
end
ngx.say("Mit MySQL verbunden.")
local res, err, errcode, sqlstate =
db:query("drop table if exists cats")
if not res then
ngx.say("schlechtes Ergebnis: ", err, ": ", errcode, ": ", sqlstate, ".")
db:close()
return
end
res, err, errcode, sqlstate =
db:query("create table cats "
.. "(id serial primary key, "
.. "name varchar(5))")
if not res then
ngx.say("schlechtes Ergebnis: ", err, ": ", errcode, ": ", sqlstate, ".")
db:close()
return
end
ngx.say("Tabelle cats erstellt.")
res, err, errcode, sqlstate =
db:query("insert into cats (name) "
.. "values (\'Bob\'),(\'\'),(null)")
if not res then
ngx.say("schlechtes Ergebnis: ", err, ": ", errcode, ": ", sqlstate, ".")
db:close()
return
end
ngx.say(res.affected_rows, " Zeilen in die Tabelle cats eingefügt ",
"(letzte eingefügte ID: ", res.insert_id, ")")
-- Führen Sie eine SELECT-Abfrage aus, erwarten Sie etwa 10 Zeilen im
-- Ergebnissatz:
res, err, errcode, sqlstate =
db:query("select * from cats order by id asc", 10)
if not res then
ngx.say("schlechtes Ergebnis: ", err, ": ", errcode, ": ", sqlstate, ".")
db:close()
return
end
local cjson = require "cjson"
ngx.say("Ergebnis: ", cjson.encode(res))
-- Fügen Sie es in den Verbindungspool mit einer Größe von 100 ein,
-- mit 10 Sekunden maximaler Leerlaufzeit
local ok, err = db:set_keepalive(10000, 100)
if not ok then
ngx.say("Fehler beim Setzen von Keepalive: ", err)
db:close()
return
end
-- oder schließen Sie die Verbindung sofort:
-- local ok, err = db:close()
-- if not ok then
-- ngx.say("Fehler beim Schließen: ", err)
-- return
-- end
';
}
}
Methoden
new
syntax: db, err = mysql:new()
Erstellt ein MySQL-Verbindungsobjekt. Im Falle von Fehlern gibt es nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
connect
syntax: ok, err, errcode, sqlstate = db:connect(options)
Versucht, eine Verbindung zum entfernten MySQL-Server herzustellen.
Das Argument options ist eine Lua-Tabelle, die die folgenden Schlüssel enthält:
-
hostder Hostname für den MySQL-Server. *
portder Port, auf dem der MySQL-Server lauscht. Standardmäßig 3306. *
pathder Pfad der Unix-Socket-Datei, die vom MySQL-Server überwacht wird. *
databaseder Name der MySQL-Datenbank. *
userMySQL-Kontoname für die Anmeldung. *
passwordMySQL-Kontopasswort für die Anmeldung (im Klartext). *
charsetder Zeichensatz, der für die MySQL-Verbindung verwendet wird, der von der Standardzeichensatz-Einstellung abweichen kann. Die folgenden Werte werden akzeptiert:
big5,dec8,cp850,hp8,koi8r,latin1,latin2,swe7,ascii,ujis,sjis,hebrew,tis620,euckr,koi8u,gb2312,greek,cp1250,gbk,latin5,armscii8,utf8,ucs2,cp866,keybcs2,macce,macroman,cp852,latin7,utf8mb4,cp1251,utf16,utf16le,cp1256,cp1257,utf32,binary,geostd8,cp932,eucjpms,gb18030. *max_packet_sizedie obere Grenze für die Antwortpakete, die vom MySQL-Server gesendet werden (standardmäßig 1 MB). *
sslWenn auf
truegesetzt, wird SSL verwendet, um eine Verbindung zu MySQL herzustellen (standardmäßigfalse). Wenn der MySQL-Server keine SSL-Unterstützung hat (oder einfach deaktiviert ist), wird die Fehlermeldung "ssl disabled on server" zurückgegeben. *ssl_verifyWenn auf
truegesetzt, wird die Gültigkeit des Server-SSL-Zertifikats überprüft (standardmäßigfalse). Beachten Sie, dass Sie die lua_ssl_trusted_certificate konfigurieren müssen, um das CA- (oder Server-)Zertifikat zu spezifizieren, das von Ihrem MySQL-Server verwendet wird. Möglicherweise müssen Sie auch lua_ssl_verify_depth entsprechend konfigurieren. *poolder Name für den MySQL-Verbindungspool. Wenn weggelassen, wird ein mehrdeutiger Poolname automatisch mit der Zeichenfolgenvorlage
user:database:host:portoderuser:database:pathgeneriert. (Diese Option wurde erstmals inv0.08eingeführt.) -
pool_sizeGibt die Größe des Verbindungspools an. Wenn weggelassen und keine
backlog-Option angegeben wurde, wird kein Pool erstellt. Wenn weggelassen, aberbacklogangegeben wurde, wird der Pool mit einer Standardgröße erstellt, die dem Wert der lua_socket_pool_size Direktive entspricht. Der Verbindungspool hält bis zupool_sizeaktive Verbindungen, die bereit sind, von nachfolgenden Aufrufen von connect wiederverwendet zu werden, aber beachten Sie, dass es keine obere Grenze für die Gesamtzahl der außerhalb des Pools geöffneten Verbindungen gibt. Wenn Sie die Gesamtzahl der geöffneten Verbindungen einschränken müssen, geben Sie diebacklog-Option an. Wenn der Verbindungspool seine Größenbeschränkung überschreiten würde, wird die am wenigsten kürzlich verwendete (gehaltene) Verbindung, die sich bereits im Pool befindet, geschlossen, um Platz für die aktuelle Verbindung zu schaffen. Beachten Sie, dass der cosocket-Verbindungspool pro Nginx-Arbeitsprozess und nicht pro Nginx-Serverinstanz gilt, sodass die hier angegebene Größenbeschränkung auch für jeden einzelnen Nginx-Arbeitsprozess gilt. Beachten Sie auch, dass die Größe des Verbindungspools nicht geändert werden kann, sobald er erstellt wurde. Beachten Sie, dass mindestens ngx_lua 0.10.14 erforderlich ist, um diese Optionen zu verwenden. -
backlogWenn angegeben, wird dieses Modul die Gesamtzahl der geöffneten Verbindungen für diesen Pool begrenzen. Zu keinem Zeitpunkt können mehr Verbindungen als
pool_sizefür diesen Pool geöffnet werden. Wenn der Verbindungspool voll ist, werden nachfolgende Verbindungsoperationen in eine Warteschlange gestellt, die dem Wert dieser Option entspricht (die "Backlog"-Warteschlange). Wenn die Anzahl der in der Warteschlange befindlichen Verbindungsoperationen gleichbacklogist, schlagen nachfolgende Verbindungsoperationen fehl und geben nil plus die Fehlermeldung"too many waiting connect operations"zurück. Die in der Warteschlange befindlichen Verbindungsoperationen werden fortgesetzt, sobald die Anzahl der Verbindungen im Pool kleiner ist alspool_size. Die in der Warteschlange befindliche Verbindungsoperation wird abgebrochen, sobald sie länger alsconnect_timeoutin der Warteschlange steht, gesteuert durch set_timeout, und gibt nil plus die Fehlermeldung "timeout" zurück. Beachten Sie, dass mindestens ngx_lua 0.10.14 erforderlich ist, um diese Optionen zu verwenden. -
compact_arraysWenn diese Option auf true gesetzt ist, geben die query und read_result Methoden die Struktur array-of-arrays für den Ergebnissatz zurück, anstelle der Standardstruktur array-of-hashes.
Bevor der Hostname tatsächlich aufgelöst und eine Verbindung zum entfernten Backend hergestellt wird, wird diese Methode immer den Verbindungspool nach passenden inaktiven Verbindungen durchsuchen, die durch vorherige Aufrufe dieser Methode erstellt wurden.
set_timeout
syntax: db:set_timeout(time)
Setzt den Timeout (in ms) Schutz für nachfolgende Operationen, einschließlich der connect-Methode.
set_keepalive
syntax: ok, err = db:set_keepalive(max_idle_timeout, pool_size)
Fügt die aktuelle MySQL-Verbindung sofort in den ngx_lua cosocket-Verbindungspool ein.
Sie können die maximale Leerlaufzeit (in ms) angeben, wenn die Verbindung im Pool ist, und die maximale Größe des Pools für jeden Nginx-Arbeitsprozess.
Im Erfolgsfall gibt es 1 zurück. Im Falle von Fehlern gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
Rufen Sie diese Methode nur an der Stelle auf, an der Sie stattdessen die close-Methode aufgerufen hätten. Das Aufrufen dieser Methode versetzt das aktuelle resty.mysql-Objekt sofort in den Zustand closed. Alle nachfolgenden Operationen, die nicht connect() auf dem aktuellen Objekt sind, geben den closed-Fehler zurück.
get_reused_times
syntax: times, err = db:get_reused_times()
Diese Methode gibt die (erfolgreich) wiederverwendeten Zeiten für die aktuelle Verbindung zurück. Im Falle eines Fehlers gibt sie nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Wenn die aktuelle Verbindung nicht aus dem integrierten Verbindungspool stammt, gibt diese Methode immer 0 zurück, das heißt, die Verbindung wurde (noch) nie wiederverwendet. Wenn die Verbindung aus dem Verbindungspool stammt, ist der Rückgabewert immer ungleich null. Diese Methode kann also auch verwendet werden, um festzustellen, ob die aktuelle Verbindung aus dem Pool stammt.
close
syntax: ok, err = db:close()
Schließt die aktuelle MySQL-Verbindung und gibt den Status zurück.
Im Erfolgsfall gibt es 1 zurück. Im Falle von Fehlern gibt es nil mit einer Zeichenfolge zurück, die den Fehler beschreibt.
send_query
syntax: bytes, err = db:send_query(query)
Sendet die Abfrage an den entfernten MySQL-Server, ohne auf dessen Antworten zu warten.
Gibt die Bytes zurück, die erfolgreich gesendet wurden, und gibt andernfalls nil und eine Zeichenfolge zurück, die den Fehler beschreibt.
Sie sollten die read_result Methode verwenden, um die MySQL-Antworten danach zu lesen.
read_result
syntax: res, err, errcode, sqlstate = db:read_result()
syntax: res, err, errcode, sqlstate = db:read_result(nrows)
Liest ein Ergebnis, das vom MySQL-Server zurückgegeben wird.
Es gibt eine Lua-Tabelle (res) zurück, die das MySQL OK-Paket oder Ergebnismengen-Paket für das Abfrageergebnis beschreibt.
Für Abfragen, die einem Ergebnisset entsprechen, gibt es ein Array zurück, das alle Zeilen enthält. Jede Zeile enthält Schlüssel-Wert-Paare für jedes Datenfeld. Zum Beispiel,
{
{ name = "Bob", age = 32, phone = ngx.null },
{ name = "Marry", age = 18, phone = "10666372"}
}
Für Abfragen, die nicht einem Ergebnisset entsprechen, gibt es eine Lua-Tabelle wie diese zurück:
{
insert_id = 0,
server_status = 2,
warning_count = 1,
affected_rows = 32,
message = nil
}
Wenn weitere Ergebnisse dem aktuellen Ergebnis folgen, wird ein zweiter err Rückgabewert mit der Zeichenfolge again zurückgegeben. Man sollte immer diesen (zweiten) Rückgabewert überprüfen und, wenn er again ist, sollte man diese Methode erneut aufrufen, um weitere Ergebnisse abzurufen. Dies geschieht normalerweise, wenn die ursprüngliche Abfrage mehrere Anweisungen enthält (die durch Semikolon in derselben Abfragezeichenfolge getrennt sind) oder eine MySQL-Prozedur aufgerufen wird. Siehe auch Multi-Resultset Support.
Im Falle von Fehlern gibt diese Methode maximal 4 Werte zurück: nil, err, errcode und sqlstate. Der Rückgabewert err enthält eine Zeichenfolge, die den Fehler beschreibt, der Rückgabewert errcode enthält den MySQL-Fehlercode (einen numerischen Wert), und schließlich enthält der Rückgabewert sqlstate den standardmäßigen SQL-Fehlercode, der aus 5 Zeichen besteht. Beachten Sie, dass errcode und sqlstate nil sein können, wenn MySQL sie nicht zurückgibt.
Das optionale Argument nrows kann verwendet werden, um eine ungefähre Anzahl von Zeilen für den Ergebnisset anzugeben. Dieser Wert kann verwendet werden, um im resultierenden Lua-Array für den Ergebnisset Platz vorzubelegen. Standardmäßig hat es den Wert 4.
query
syntax: res, err, errcode, sqlstate = db:query(query)
syntax: res, err, errcode, sqlstate = db:query(query, nrows)
Dies ist eine Abkürzung zum Kombinieren des send_query Aufrufs und des ersten read_result Aufrufs.
Sie sollten immer überprüfen, ob der Rückgabewert err im Erfolgsfall again ist, da diese Methode nur einmal read_result für Sie aufruft. Siehe auch Multi-Resultset Support.
server_ver
syntax: str = db:server_ver()
Gibt die MySQL-Serverversionszeichenfolge zurück, wie "5.1.64".
Sie sollten diese Methode nur nach erfolgreichem Verbinden mit einem MySQL-Server aufrufen, andernfalls wird nil zurückgegeben.
set_compact_arrays
syntax: db:set_compact_arrays(boolean)
Legt fest, ob die "compact-arrays"-Struktur für die von nachfolgenden Abfragen zurückgegebenen Ergebnisset verwendet werden soll. Siehe die compact_arrays-Option für die connect-Methode für weitere Details.
Diese Methode wurde erstmals in der v0.09-Version eingeführt.
SQL Literal Quoting
Es ist immer wichtig, SQL-Literale ordnungsgemäß zu zitieren, um SQL-Injection-Angriffe zu verhindern. Sie können die ngx.quote_sql_str Funktion verwenden, die von ngx_lua bereitgestellt wird, um Werte zu zitieren. Hier ist ein Beispiel:
local name = ngx.unescape_uri(ngx.var.arg_name)
local quoted_name = ngx.quote_sql_str(name)
local sql = "select * from users where name = " .. quoted_name
Multi-Resultset Support
Für eine SQL-Abfrage, die mehrere Ergebnismengen erzeugt, liegt es immer in Ihrer Verantwortung, die "again"-Fehlermeldung zu überprüfen, die von den query oder read_result Methodenaufrufen zurückgegeben wird, und weitere Ergebnismengen abzurufen, indem Sie die read_result Methode aufrufen, bis keine "again"-Fehlermeldung mehr zurückgegeben wird (oder andere Fehler auftreten).
Unten ist ein triviales Beispiel dafür:
local cjson = require "cjson"
local mysql = require "resty.mysql"
local db = mysql:new()
local ok, err, errcode, sqlstate = db:connect({
host = "127.0.0.1",
port = 3306,
database = "world",
user = "monty",
password = "pass"})
if not ok then
ngx.log(ngx.ERR, "Fehler beim Verbinden: ", err, ": ", errcode, " ", sqlstate)
return ngx.exit(500)
end
res, err, errcode, sqlstate = db:query("select 1; select 2; select 3;")
if not res then
ngx.log(ngx.ERR, "schlechtes Ergebnis #1: ", err, ": ", errcode, ": ", sqlstate, ".")
db:close()
return ngx.exit(500)
end
ngx.say("Ergebnis #1: ", cjson.encode(res))
local i = 2
while err == "again" do
res, err, errcode, sqlstate = db:read_result()
if not res then
ngx.log(ngx.ERR, "schlechtes Ergebnis #", i, ": ", err, ": ", errcode, ": ", sqlstate, ".")
db:close()
return ngx.exit(500)
end
ngx.say("Ergebnis #", i, ": ", cjson.encode(res))
i = i + 1
end
local ok, err = db:set_keepalive(10000, 50)
if not ok then
ngx.log(ngx.ERR, "Fehler beim Setzen von Keepalive: ", err)
db:close()
ngx.exit(500)
end
Dieser Code-Schnipsel wird die folgenden Antwortkörperdaten erzeugen:
Ergebnis #1: [{"1":"1"}]
Ergebnis #2: [{"2":"2"}]
Ergebnis #3: [{"3":"3"}]
Debugging
Es ist normalerweise praktisch, die lua-cjson Bibliothek zu verwenden, um die Rückgabewerte der MySQL-Abfragemethoden in JSON zu kodieren. Zum Beispiel,
local cjson = require "cjson"
...
local res, err, errcode, sqlstate = db:query("select * from cats")
if res then
print("res: ", cjson.encode(res))
end
Automatische Fehlerprotokollierung
Standardmäßig protokolliert das zugrunde liegende ngx_lua Modul Fehler, wenn Socket-Fehler auftreten. Wenn Sie bereits eine ordnungsgemäße Fehlerbehandlung in Ihrem eigenen Lua-Code durchführen, wird empfohlen, diese automatische Fehlerprotokollierung zu deaktivieren, indem Sie die lua_socket_log_errors Direktive von ngx_lua deaktivieren, das heißt,
lua_socket_log_errors off;
Einschränkungen
- Diese Bibliothek kann nicht in Codekontexten wie init_by_lua, set_by_lua, log_by_lua, und header_filter_by_lua verwendet werden, wo die ngx_lua cosocket-API nicht verfügbar ist.
- Die
resty.mysql-Objektinstanz kann nicht auf Modulebene in einer Lua-Variablen gespeichert werden, da sie dann von allen gleichzeitigen Anfragen, die vom selben Nginx-Arbeitsprozess bearbeitet werden, geteilt wird (siehe https://github.com/openresty/lua-nginx-module#data-sharing-within-an-nginx-worker) und schlechte Race-Conditions verursachen kann, wenn gleichzeitige Anfragen versuchen, dieselberesty.mysql-Instanz zu verwenden. Sie sollten immerresty.mysql-Objekte in lokalen Funktionsvariablen oder in derngx.ctx-Tabelle initiieren. Diese Orte haben alle ihre eigenen Datenkopien für jede Anfrage.
Mehr Unterstützung für Authentifizierungsmethoden
Standardmäßig werden von allen Authentifizierungsmethoden nur Old Password Authentication(mysql_old_password) und Secure Password Authentication(mysql_native_password) unterstützt. Wenn der Server sha256_password oder cache_sha2_password benötigt, kann ein Fehler wie auth plugin caching_sha2_password or sha256_password are not supported because resty.rsa is not installed zurückgegeben werden.
Benötigt lua-resty-rsa, wenn sha256_password und cache_sha2_password verwendet werden.
Siehe auch
- das ngx_lua-Modul: https://github.com/openresty/lua-nginx-module
- die MySQL-Wired-Protokollspezifikation: http://forge.mysql.com/wiki/MySQL_Internals_ClientServer_Protocol
- die lua-resty-memcached Bibliothek
- die lua-resty-redis Bibliothek
- das ngx_drizzle-Modul: https://github.com/openresty/drizzle-nginx-module
GitHub
Sie finden zusätzliche Konfigurationstipps und Dokumentationen für dieses Modul im GitHub-Repository für nginx-module-mysql.