sql >> Database teknologi >  >> NoSQL >> Redis

redis + gevent - Dårlig ydeevne - hvad gør jeg forkert?

Dette forventes.

Du kører dette benchmark på en VM, hvor omkostningerne ved systemopkald er højere end på fysisk hardware. Når gevent er aktiveret, har det en tendens til at generere flere systemopkald (for at håndtere epoll-enheden), så du ender med mindre ydeevne.

Du kan nemt kontrollere dette punkt ved at bruge strace på scriptet.

Uden gavt genererer den indre sløjfe:

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

Med gevent vil du have forekomster af:

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

Når recvfrom-kaldet blokerer (EAGAIN), går gevent tilbage til hændelsesløkken, så yderligere opkald udføres for at vente på filbeskrivelseshændelser (epoll_wait).

Bemærk venligst, at denne type benchmark er et worst case for ethvert hændelsesløkkesystem, fordi du kun har én filbeskrivelse, så venteoperationerne kan ikke faktoriseres på flere deskriptorer. Desuden kan asynkrone I/O'er ikke forbedre noget her, da alt er synkront.

Det er også et worst case for Redis, fordi:

  • det genererer mange rundrejser til serveren

  • den forbinder/afbryder systematisk (1000 gange), fordi puljen er deklareret i UxDomainSocket-funktionen.

Faktisk tester dit benchmark ikke gevent, redis eller redis-py:det udøver en VM's evne til at opretholde et ping-pong-spil mellem 2 processer.

Hvis du vil øge ydeevnen, skal du:

  • brug pipelining til at reducere antallet af rundrejser

  • gøre poolen vedvarende på tværs af hele benchmark

Overvej for eksempel med følgende 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)

Med dette script får jeg omkring 3 gange bedre ydeevne og næsten ingen overhead med givet.




  1. Sømløs skala til dine MongoDB-servere

  2. Sådan opretter du RedisCacheManager i spring-data 2.0.x

  3. Hvordan konfigureres Node Redis-klienten til at smide fejl med det samme, når forbindelsen er mislykket? [LÆS DETALJER]

  4. Jedis Ændrer Redis' semantik?