Jeg tvivler på, at maksimering af CPU-brug af Redis vil gavne dit backend-design. Det rigtige spørgsmål er snarere, om Redis er effektiv nok til at opretholde din gennemstrømning ved en given forsinkelse. Redis er en single-threaded server:Ved 80 % CPU-forbrug vil forsinkelsen sandsynligvis være meget dårlig.
Jeg foreslår, at du måler latens, mens redis-benchmark arbejder for at se, om det er acceptabelt for dine behov, før du forsøger at øge Redis CPU-forbrug. --latency muligheden for redis-cli kan bruges til dette:
- start redis-server
- prøv redis-cli --latency, noter gennemsnitsværdien, stop det
- i et andet vindue, start benchmark, og sørg for, at det kører i et stykke tid
- prøv redis-cli --latency, noter gennemsnitsværdien, stop det
- stop benchmark
- sammenlign de to gennemsnitsværdier
Nu, hvis du virkelig ønsker at øge Redis CPU-forbruget, har du brug for enten et effektivt klientprogram (som redis-benchmark), der er i stand til at håndtere flere forbindelser samtidigt, enten flere forekomster af dit klientprogram.
Lua er et hurtigt fortolket sprog, men det er stadig et fortolket sprog. Det vil være en eller to størrelsesordener langsommere end C-koden. Redis er meget hurtigere til at parse/generere sin protokol end lua-redis, så du vil ikke være i stand til at mætte Redis med en unik Lua-klient (undtagen hvis du bruger O(n) Redis-kommandoer - se senere).
webdis er implementeret i C med et effektivt klientbibliotek, men skal parse http/json-protokollerne, som tilfældigvis er mere omfattende og komplekse end Redis-protokollen. Det bruger sandsynligvis mere CPU end Redis selv til de fleste operationer. Så igen, du vil ikke mætte Redis med en enkelt webdis-instans.
Her er nogle eksempler på at mætte Redis med flere Lua-klienter.
Hvis det ikke allerede er gjort, foreslår jeg, at du tog et kig på Redis benchmark-siden først.
Hvis du kører dit benchmark på samme boks som Redis:
Nøglepunktet er at dedikere en kerne til Redis og køre klientprogrammerne på de andre kerner. På Linux kan du bruge opgavesæt-kommandoen til dette.
# 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
Lua-programmet bør bruge pipelining til at maksimere gennemløbet og reducere systemaktiviteten.
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
På mit system tager Lua-programmet mere end 4 gange så meget CPU som Redis, så du har brug for mere end 4 kerner for at mætte Redis med denne metode (en boks med 6 kerner burde være i orden).
Hvis du kører dit benchmark på en anden boks end Redis:
Bortset fra hvis du kører på CPU-udsultede virtuelle maskiner, vil flaskehalsen sandsynligvis være netværket i så fald. Jeg tror ikke, du kan mætte Redis med noget mindre end et 1 GbE-link.
Sørg for at pipeline dine forespørgsler så langt du kan (se det tidligere Lua-program) for at undgå flaskehalsen med netværksforsinkelse og reducere omkostningerne ved netværksafbrydelser på CPU'en (udfyldning af ethernet-pakker). Prøv at køre Redis på en kerne, der ikke er bundet til netværkskortet (og behandler netværksafbrydelser). Du kan bruge værktøjer som htop til at kontrollere dette sidste punkt.
Prøv at køre dine Lua-klienter på forskellige andre maskiner på netværket, hvis du kan. Igen skal du bruge et stort antal Lua-klienter for at mætte Redis (6-10 burde være fint).
I nogle tilfælde er en unik Lua-proces nok:
Nu er det muligt at mætte Redis med en enkelt Lua-klient, hvis hver forespørgsel er dyr nok. Her er et eksempel:
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
Dette program udfylder en liste med 1M elementer og bruger derefter lrange-kommandoer til at hente 10 elementer fra midten af listen (worst case for Redis). Så hver gang en forespørgsel udføres, scannes 500.000 elementer af serveren. Fordi kun 10 varer returneres, er de hurtige at parse af lua-redis, som ikke bruger CPU. I denne situation vil alt CPU-forbrug være på serversiden.
Sidste ord
Der er sandsynligvis hurtigere Redis-klienter end redis-lua:
- https://github.com/agladysh/lua-hiredis (baseret på hiredis)
- https://github.com/agladysh/ljffi-hiredis (baseret på hirdis, ved hjælp af luajit FFI)
Du vil måske prøve dem.