sql >> Databáze >  >> NoSQL >> Redis

redis + gevent - Špatný výkon - co dělám špatně?

To se očekává.

Tento benchmark spustíte na virtuálním počítači, na kterém jsou náklady na systémová volání vyšší než na fyzickém hardwaru. Když je gevent aktivován, má tendenci generovat více systémových volání (pro obsluhu zařízení epoll), takže skončíte s nižším výkonem.

Tento bod můžete snadno zkontrolovat pomocí strace ve skriptu.

Bez gevent vnitřní smyčka generuje:

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

S gevent budete mít výskyty:

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

Když je volání recvfrom blokováno (EAGAIN), gevent se vrátí zpět do smyčky událostí, takže se provedou další volání, aby se čekalo na události deskriptorů souborů (epoll_wait).

Upozorňujeme, že tento druh benchmarku je nejhorším případem pro jakýkoli systém smyčky událostí, protože máte pouze jeden deskriptor souboru, takže operace čekání nelze faktorizovat na několik deskriptorů. Navíc asynchronní I/O zde nemohou nic zlepšit, protože vše je synchronní.

Pro Redis je to také nejhorší případ, protože:

  • generuje mnoho zpátečních cest na server

  • systematicky se připojuje/odpojuje (1000krát), protože fond je deklarován ve funkci UxDomainSocket.

Váš benchmark ve skutečnosti netestuje gevent, redis nebo redis-py:využívá schopnost virtuálního počítače udržet ping-pongovou hru mezi 2 procesy.

Pokud chcete zvýšit výkon, musíte:

  • použijte pipelining ke snížení počtu zpátečních cest

  • zajistit, aby fond byl trvalý v celém benchmarku

Zvažte například následující 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)

S tímto skriptem mám asi 3x lepší výkon a téměř žádnou režii s gevent.




  1. Snížení velikosti souboru databáze MongoDB

  2. Odstraňte duplikáty z MongoDB

  3. Hiredis čeká na zprávu

  4. vlastní řazení mongoose/mongodb