Ich bezweifle, dass die Maximierung der CPU-Auslastung von Redis Ihrem Backend-Design zugute kommt. Die richtige Frage ist eher, ob Redis effizient genug ist, um Ihren Durchsatz bei einer bestimmten Latenz aufrechtzuerhalten. Redis ist ein Singlethread-Server:Bei 80 % CPU-Auslastung ist die Latenz wahrscheinlich sehr schlecht.
Ich schlage vor, dass Sie die Latenz messen, während Redis-Benchmark arbeitet, um zu sehen, ob es für Ihre Anforderungen akzeptabel ist, bevor Sie versuchen, den Redis-CPU-Verbrauch zu erhöhen. Dazu kann die Option --latency von redis-cli verwendet werden:
- Redis-Server starten
- versuchen Sie es mit redis-cli --latency, notieren Sie sich den Durchschnittswert, stoppen Sie es
- Starten Sie in einem anderen Fenster den Benchmark und stellen Sie sicher, dass er eine Weile läuft
- versuchen Sie es mit redis-cli --latency, notieren Sie sich den Durchschnittswert, stoppen Sie es
- Beenden Sie den Benchmark
- vergleichen Sie die beiden Durchschnittswerte
Wenn Sie die Redis-CPU-Nutzung wirklich erhöhen möchten, benötigen Sie entweder ein effizientes Client-Programm (wie Redis-Benchmark), das mehrere Verbindungen gleichzeitig verarbeiten kann, oder mehrere Instanzen Ihres Client-Programms.
Lua ist eine schnell interpretierte Sprache, aber es ist immer noch eine interpretierte Sprache. Es wird ein oder zwei Größenordnungen langsamer sein als C-Code. Redis analysiert/generiert sein Protokoll viel schneller als lua-redis, sodass Sie Redis nicht mit einem eindeutigen Lua-Client sättigen können (außer wenn Sie O(n) Redis-Befehle verwenden - siehe später).
webdis ist in C implementiert, mit einer effizienten Client-Bibliothek, muss aber die http/json-Protokolle parsen, die zufällig ausführlicher und komplexer sind als das Redis-Protokoll. Es verbraucht wahrscheinlich mehr CPU als Redis selbst für die meisten Operationen. Auch hier werden Sie Redis nicht mit einer einzigen Webdis-Instanz sättigen.
Hier sind einige Beispiele, um Redis mit mehreren Lua-Clients zu sättigen.
Wenn dies noch nicht geschehen ist, schlage ich vor, dass Sie sich zuerst die Redis-Benchmark-Seite ansehen.
Wenn Sie Ihren Benchmark auf derselben Box wie Redis ausführen:
Der entscheidende Punkt besteht darin, Redis einen Kern zuzuweisen und die Client-Programme auf den anderen Kernen auszuführen. Unter Linux können Sie dafür den Taskset-Befehl verwenden.
# Start Redis on core 0
taskset -c 0 redis-server redis.conf
# Start Lua programs on the other cores
for x in `seq 1 10` ; do taskset -c 1,2,3 luajit example.lua & done
Das Lua-Programm sollte Pipelining verwenden, um den Durchsatz zu maximieren und die Systemaktivität zu reduzieren.
local redis = require 'redis'
local client = redis.connect('127.0.0.1', 6379)
for i=1,1000000 do
local replies = client:pipeline(function(p)
for j=1,1000 do
local key = 'counter:'..tostring(j)
p:incrby(key,1)
end
end)
end
Auf meinem System benötigt das Lua-Programm mehr als das 4-fache der CPU von Redis, sodass Sie mehr als 4 Kerne benötigen, um Redis mit dieser Methode zu sättigen (eine 6-Kern-Box sollte in Ordnung sein).
Wenn Sie Ihren Benchmark auf einer anderen Box als Redis ausführen:
Außer wenn Sie auf CPU-hungrigen virtuellen Maschinen laufen, wird der Engpass in diesem Fall wahrscheinlich das Netzwerk sein. Ich glaube nicht, dass Sie Redis mit weniger als einer 1-GbE-Verbindung sättigen können.
Stellen Sie sicher, dass Sie Ihre Abfragen so weit wie möglich leiten (siehe vorheriges Lua-Programm), um den Netzwerklatenzengpass zu vermeiden und die Kosten von Netzwerkunterbrechungen auf der CPU zu reduzieren (Ethernet-Pakete füllen). Versuchen Sie, Redis auf einem Kern auszuführen, der nicht an die Netzwerkkarte gebunden ist (und Netzwerkunterbrechungen verarbeitet). Sie können Tools wie htop verwenden, um diesen letzten Punkt zu überprüfen.
Versuchen Sie, Ihre Lua-Clients auf verschiedenen anderen Computern des Netzwerks auszuführen, wenn Sie können. Auch hier benötigen Sie eine gute Anzahl von Lua-Clients, um Redis zu sättigen (6-10 sollten in Ordnung sein).
In einigen Fällen reicht ein eindeutiger Lua-Prozess aus:
Jetzt ist es möglich, Redis mit einem einzigen Lua-Client zu sättigen, wenn jede Abfrage teuer genug ist. Hier ist ein Beispiel:
local redis = require 'redis'
local client = redis.connect('127.0.0.1', 6379)
for i=1,1000 do
local replies = client:pipeline(function(p)
for j=1,1000 do
p:rpush("toto",i*1000+j)
end
end)
end
N = 500000
for i=1,100000 do
local replies = client:pipeline(function(p)
for j=1,10 do
p:lrange("toto",N, N+10)
end
end)
end
Dieses Programm füllt eine Liste mit 1 Mio. Elementen und verwendet dann lrange-Befehle, um 10 Elemente aus der Mitte der Liste abzurufen (im schlimmsten Fall für Redis). Jedes Mal, wenn eine Abfrage ausgeführt wird, werden also 500.000 Elemente vom Server gescannt. Da nur 10 Elemente zurückgegeben werden, können sie schnell von lua-redis analysiert werden, was keine CPU verbraucht. In dieser Situation liegt der gesamte CPU-Verbrauch auf der Serverseite.
Schlussworte
Es gibt wahrscheinlich schnellere Redis-Clients als redis-lua:
- https://github.com/agladysh/lua-hiredis (basierend auf Hiredis)
- https://github.com/agladysh/ljffi-hiredis (basierend auf Hiredis, unter Verwendung von Luajit FFI)
Vielleicht möchten Sie sie ausprobieren.