Dubito che massimizzare l'utilizzo della CPU di Redis gioverà al tuo design di back-end. La domanda giusta è piuttosto se Redis è abbastanza efficiente da sostenere il tuo throughput a una data latenza. Redis è un server a thread singolo:con un consumo di CPU dell'80%, la latenza sarà probabilmente molto scarsa.
Ti suggerisco di misurare la latenza mentre redis-benchmark funziona per vedere se è accettabile per le tue esigenze prima di provare ad aumentare il consumo della CPU Redis. L'opzione --latency di redis-cli può essere utilizzata per questo:
- avvia il server redis
- prova redis-cli --latency, annota il valore avg, fermalo
- in un'altra finestra, avvia il benchmark e assicurati che funzioni per un po'
- prova redis-cli --latency, annota il valore avg, fermalo
- ferma il benchmark
- confronta i due valori medi
Ora, se vuoi davvero aumentare il consumo di CPU Redis, hai bisogno di un programma client efficiente (come redis-benchmark), in grado di gestire più connessioni contemporaneamente, o più istanze del tuo programma client.
Lua è una lingua interpretata velocemente, ma è pur sempre una lingua interpretata. Sarà uno o due ordini di grandezza più lento del codice C. Redis è molto più veloce nell'analisi/generazione del suo protocollo rispetto a lua-redis, quindi non sarai in grado di saturare Redis con un client Lua univoco (tranne se usi i comandi O(n) Redis - vedi più avanti).
webdis è implementato in C, con un'efficiente libreria client, ma deve analizzare i protocolli http/json che risultano essere più dettagliati e complessi del protocollo Redis. Probabilmente consuma più CPU di Redis stesso per la maggior parte delle operazioni. Quindi, ancora una volta, non saturerai Redis con una singola istanza webdis.
Ecco alcuni esempi per saturare Redis con più client Lua.
Se non è già stato fatto, ti suggerisco di dare un'occhiata prima alla pagina del benchmark Redis.
Se esegui il benchmark sulla stessa scatola di Redis:
Il punto chiave è dedicare un core a Redis ed eseguire i programmi client sugli altri core. Su Linux, puoi utilizzare il comando taskset per questo.
# 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
Il programma Lua dovrebbe utilizzare la pipeline per massimizzare il throughput e ridurre l'attività del sistema.
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
Sul mio sistema, il programma Lua impiega più di 4 volte la CPU di Redis, quindi sono necessari più di 4 core per saturare Redis con questo metodo (una scatola da 6 core dovrebbe andare bene).
Se esegui il benchmark su una casella diversa da Redis:
Tranne se esegui macchine virtuali affamate di CPU, il collo di bottiglia sarà probabilmente la rete in quel caso. Non credo che tu possa saturare Redis con qualcosa di meno di un collegamento da 1 GbE.
Assicurati di convogliare le tue query il più lontano possibile (vedi il precedente programma Lua) per evitare il collo di bottiglia della latenza di rete e ridurre il costo degli interrupt di rete sulla CPU (riempimento di pacchetti Ethernet). Prova a eseguire Redis su un core che non è legato alla scheda di rete (ed elabora gli interrupt di rete). Puoi utilizzare strumenti come htop per verificare quest'ultimo punto.
Prova a eseguire i tuoi client Lua su varie altre macchine della rete, se possibile. Anche in questo caso avrai bisogno di un buon numero di client Lua per saturare Redis (6-10 dovrebbero andare bene).
In alcuni casi è sufficiente un unico processo Lua:
Ora è possibile saturare Redis con un singolo client Lua se ogni query è abbastanza costosa. Ecco un esempio:
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
Questo programma compila un elenco con 1 milione di elementi, quindi utilizza i comandi lrange per recuperare 10 elementi dal centro dell'elenco (caso peggiore per Redis). Pertanto, ogni volta che viene eseguita una query, il server esegue la scansione di 500.000 elementi. Poiché vengono restituiti solo 10 articoli, sono veloci da analizzare da lua-redis che non consumerà CPU. In questa situazione, tutto il consumo di CPU sarà lato server.
Ultime parole
Probabilmente esistono client Redis più veloci di redis-lua:
- https://github.com/agladysh/lua-hiredis (basato su rentaldis)
- https://github.com/agladysh/ljffi-hiredis (basato su rentaldis, utilizzando luajit FFI)
Potresti volerle provare.