sql >> Databasteknik >  >> NoSQL >> Redis

redis + gevent - Dålig prestanda - vad gör jag för fel?

Detta förväntas.

Du kör detta riktmärke på en virtuell dator, där kostnaden för systemsamtal är högre än på fysisk hårdvara. När gevent är aktiverat tenderar det att generera fler systemanrop (för att hantera epoll-enheten), så att du får mindre prestanda.

Du kan enkelt kontrollera denna punkt genom att använda strace på skriptet.

Utan gavt genererar den inre slingan:

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 kommer du att ha förekomster av:

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-anropet blockerar (EAGAIN), går gevent tillbaka till händelseslingan, så ytterligare anrop görs för att vänta på filbeskrivningshändelser (epoll_wait).

Observera att den här typen av riktmärke är ett värsta fall för alla händelseloopsystem, eftersom du bara har en filbeskrivning, så väntan operationer kan inte faktoriseras på flera deskriptorer. Dessutom kan asynkrona I/O inte förbättra någonting här eftersom allt är synkront.

Det är också ett värsta fall för Redis eftersom:

  • det genererar många rundresor till servern

  • den ansluter/kopplar från systematiskt (1000 gånger) eftersom poolen deklareras i UxDomainSocket-funktionen.

Egentligen testar ditt riktmärke inte gevent, redis eller redis-py:det utövar en virtuell dators förmåga att upprätthålla ett pingisspel mellan två processer.

Om du vill öka prestandan måste du:

  • använd pipelining för att minska antalet tur och retur

  • göra poolen beständig över hela riktmärket

Överväg till exempel med följande skript:

#!/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 det här skriptet får jag ungefär 3 gånger bättre prestanda och nästan ingen overhead med gavt.




  1. uppgradera mongodb

  2. 'process.nextTick(function() { throw err; })' - Odefinierad är inte en funktion (mongodb/mongoose)

  3. Implementera referensuppsättningar i Redis

  4. MongoDB C# Driver 2.0 - Uppdatera dokument