Wątpię, aby maksymalizacja wykorzystania procesora przez Redis była korzystna dla twojego projektu zaplecza. Właściwym pytaniem jest raczej, czy Redis jest wystarczająco wydajny, aby utrzymać przepustowość przy danym opóźnieniu. Redis jest serwerem jednowątkowym:przy 80% zużyciu procesora opóźnienie będzie prawdopodobnie bardzo złe.
Proponuję zmierzyć opóźnienie, gdy test Redis działa, aby sprawdzić, czy jest on akceptowalny dla twoich potrzeb, zanim spróbujesz zwiększyć zużycie procesora Redis. W tym celu można użyć opcji --latency z redis-cli:
- uruchom serwer redis
- spróbuj redis-cli --latency, zanotuj średnią wartość, zatrzymaj ją
- w innym oknie uruchom test porównawczy i upewnij się, że działa przez chwilę
- spróbuj redis-cli --latency, zanotuj średnią wartość, zatrzymaj ją
- zatrzymaj test porównawczy
- porównaj dwie średnie wartości
Teraz, jeśli naprawdę chcesz zwiększyć zużycie procesora Redis, potrzebujesz wydajnego programu klienckiego (takiego jak redis-benchmark), zdolnego do obsługi wielu połączeń jednocześnie, albo wielu wystąpień programu klienckiego.
Lua jest językiem szybko tłumaczonym, ale nadal jest językiem tłumaczonym. Będzie o jeden lub dwa rzędy wielkości wolniejszy niż kod C. Redis jest znacznie szybszy w przetwarzaniu/generowaniu swojego protokołu niż lua-redis, więc nie będziesz w stanie nasycić Redisa unikalnym klientem Lua (z wyjątkiem sytuacji, gdy używasz poleceń O(n) Redis – zobacz dalej).
Webdis jest zaimplementowany w C, z wydajną biblioteką kliencką, ale musi analizować protokoły http/json, które są bardziej szczegółowe i złożone niż protokół Redis. Prawdopodobnie zużywa więcej procesora niż sam Redis dla większości operacji. Więc znowu, nie nasycisz Redisa pojedynczą instancją webdis.
Oto kilka przykładów nasycenia Redis wieloma klientami Lua.
Jeśli jeszcze tego nie zrobiono, sugeruję, abyś najpierw zajrzał na stronę testu Redis.
Jeśli uruchamiasz test porównawczy na tym samym polu, co Redis:
Kluczowym punktem jest dedykowanie rdzenia Redis i uruchamianie programów klienckich na pozostałych rdzeniach. W systemie Linux możesz użyć do tego polecenia taskset.
# 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
Program Lua powinien wykorzystywać potokowanie, aby zmaksymalizować przepustowość i zmniejszyć aktywność systemu.
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
W moim systemie program Lua zajmuje więcej niż 4 razy więcej procesora niż Redis, więc potrzebujesz więcej niż 4 rdzeni, aby nasycić Redis tą metodą (pole 6 rdzeni powinno wystarczyć).
Jeśli uruchamiasz test porównawczy na innym polu niż Redis:
Z wyjątkiem sytuacji, gdy korzystasz z maszyn wirtualnych pozbawionych procesora, w tym przypadku wąskim gardłem będzie prawdopodobnie sieć. Nie sądzę, że można nasycić Redis czymkolwiek mniejszym niż łącze 1 GbE.
Pamiętaj, aby potokować zapytania tak daleko, jak to możliwe (zobacz poprzedni program Lua), aby uniknąć wąskiego gardła opóźnień w sieci i zmniejszyć koszt przerwań sieciowych w procesorze (wypełnianie pakietów ethernetowych). Spróbuj uruchomić Redis na rdzeniu, który nie jest powiązany z kartą sieciową (i przetwarza przerwania sieciowe). Możesz użyć narzędzi takich jak htop, aby sprawdzić ten ostatni punkt.
Spróbuj uruchomić klientów Lua na różnych innych komputerach w sieci, jeśli możesz. Ponownie będziesz potrzebować dużej liczby klientów Lua do nasycenia Redisa (6-10 powinno wystarczyć).
W niektórych przypadkach wystarczy unikalny proces Lua:
Teraz możliwe jest nasycenie Redis jednym klientem Lua, jeśli każde zapytanie jest wystarczająco drogie. Oto przykład:
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
Ten program wypełnia listę 1 mln pozycji, a następnie używa poleceń lrange, aby pobrać 10 pozycji ze środka listy (najgorszy przypadek dla Redis). Tak więc za każdym razem, gdy wykonywane jest zapytanie, serwer skanuje 500 000 elementów. Ponieważ zwracanych jest tylko 10 elementów, można je szybko przeanalizować przez lua-redis, co nie zużywa procesora. W tej sytuacji całe zużycie procesora będzie po stronie serwera.
Końcowe słowa
Prawdopodobnie istnieją szybsze klienty Redis niż redis-lua:
- https://github.com/agladysh/lua-hiredis (na podstawie Hiredis)
- https://github.com/agladysh/ljffi-hiredis (na podstawie Hireddis, używając luajit FFI)
Możesz je wypróbować.