Redis + Gevent - scarsa performance - cosa sto sbagliando?
-
11-12-2019 - |
Domanda
Ho appena scritto un semplice pezzo di codice a Perf Test Redis + Gevent per vedere come ASYNC aiuta la performance ed io siamo rimasti sorpresi di trovare cattive prestazioni.Ecco il mio codice.Se ti sbarazzi delle prime due righe a Monkey Patch questo codice, vedrai il tempismo "Esecuzione normale".
Su un Ubuntu 12.04 LTS VM, sto vedendo un tempismo di
senza patch monkey - 54 secondi Con patch di scimmia - 61 secondi
C'è qualcosa di sbagliato nel mio codice / approccio?C'è un problema perf qui?
#!/usr/bin/python
from gevent import monkey
monkey.patch_all()
import timeit
import redis
from redis.connection import UnixDomainSocketConnection
def UxDomainSocket():
pool = redis.ConnectionPool(connection_class=UnixDomainSocketConnection, path = '/var/redis/redis.sock')
r = redis.Redis(connection_pool = pool)
r.set("testsocket", 1)
for i in range(100):
r.incr('testsocket', 10)
r.get('testsocket')
r.delete('testsocket')
print timeit.Timer(stmt='UxDomainSocket()',
setup='from __main__ import UxDomainSocket').timeit(number=1000)
. Soluzione
Questo è previsto.
Esegui questo benchmark su una VM, su cui il costo delle chiamate di sistema è superiore a quello su hardware fisico. Quando Gevent è attivato, tende a generare più chiamate di sistema (per gestire il dispositivo EPOLL), in modo da finire con meno prestazioni.
È possibile controllare facilmente questo punto usando Strace sullo script.
Senza Gevent, il loop interno genera:
recvfrom(3, ":931\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
recvfrom(3, ":941\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
.
Con Gevent, avrai iscritti di:
recvfrom(3, ":221\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
recvfrom(3, 0x7b0f04, 4096, 0, 0, 0) = -1 EAGAIN (Resource temporarily unavailable)
epoll_ctl(5, EPOLL_CTL_ADD, 3, {EPOLLIN, {u32=3, u64=3}}) = 0
epoll_wait(5, {{EPOLLIN, {u32=3, u64=3}}}, 32, 4294967295) = 1
clock_gettime(CLOCK_MONOTONIC, {2469, 779710323}) = 0
epoll_ctl(5, EPOLL_CTL_DEL, 3, {EPOLLIN, {u32=3, u64=3}}) = 0
recvfrom(3, ":231\r\n", 4096, 0, NULL, NULL) = 6
sendto(3, "*3\r\n$6\r\nINCRBY\r\n$10\r\ntestsocket\r"..., 41, 0, NULL, 0) = 41
.
Quando la chiamata RecvFrom è bloccata (EAGAIN), Gevent torna al loop dell'evento, quindi vengono eseguite ulteriori chiamate per attendere gli eventi dei descrittori di file (EPOLL_WAIT).
Si prega di notare che questo tipo di benchmark è un caso peggiore per qualsiasi sistema di loop evento, poiché hai solo un descrittore di file, quindi le operazioni di attesa non possono essere fattilizzate su diversi descrittori. Inoltre, Async I / O non può migliorare nulla qui poiché tutto è sincrono.
È anche un caso peggiore per Redis perché:
- .
-
Genera molte antaintropie al server
-
Si collega sistematicamente / disconnetti (1000 volte) perché il pool è dichiarato in funzione UXDomainSocket.
In realtà il tuo benchmark non testerà Gevent, Redis o Redis-Py: esercita la capacità di una VM per sostenere un gioco Ping-Pong tra 2 processi.
Se si desidera aumentare le prestazioni, è necessario:
- .
-
Utilizzare tubazioni per diminuire il numero di antaintrici
-
Rendi la piscina persistenti attraverso l'intero benchmark
Ad esempio, considerare con il seguente script:
.#!/usr/bin/python from gevent import monkey monkey.patch_all() import timeit import redis from redis.connection import UnixDomainSocketConnection pool = redis.ConnectionPool(connection_class=UnixDomainSocketConnection, path = '/tmp/redis.sock') def UxDomainSocket(): r = redis.Redis(connection_pool = pool) p = r.pipeline(transaction=False) p.set("testsocket", 1) for i in range(100): p.incr('testsocket', 10) p.get('testsocket') p.delete('testsocket') p.execute() print timeit.Timer(stmt='UxDomainSocket()', setup='from __main__ import UxDomainSocket').timeit(number=1000)
Con questo script, ottengo circa 3 volte prestazioni migliori e quasi nessun sovraccarico con Gevent.
-