Redis
 sql >> Baza danych >  >> NoSQL >> Redis

redis + geven - Słaba wydajność - co robię źle?

Jest to oczekiwane.

Ten test porównawczy uruchamiasz na maszynie wirtualnej, na której koszt wywołań systemowych jest wyższy niż na sprzęcie fizycznym. Gdy gevent jest aktywowany, ma tendencję do generowania większej liczby wywołań systemowych (w celu obsługi urządzenia epoll), dzięki czemu uzyskujesz mniejszą wydajność.

Możesz łatwo sprawdzić ten punkt, używając strace w skrypcie.

Bez gevent wewnętrzna pętla 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

W przypadku geven wystąpią następujące zdarzenia:

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

Gdy wywołanie recvfrom jest blokowane (EAGAIN), gevent wraca do pętli zdarzeń, więc wykonywane są dodatkowe wywołania w celu oczekiwania na zdarzenia deskryptorów plików (epoll_wait).

Należy pamiętać, że ten rodzaj testu porównawczego jest najgorszym przypadkiem dla każdego systemu pętli zdarzeń, ponieważ masz tylko jeden deskryptor pliku, więc operacji oczekiwania nie można rozłożyć na kilka deskryptorów. Co więcej, asynchroniczne wejścia/wyjścia nie mogą niczego poprawić, ponieważ wszystko jest synchroniczne.

Jest to również najgorszy przypadek dla Redis, ponieważ:

  • generuje wiele podróży w obie strony do serwera

  • systematycznie łączy/rozłącza (1000 razy), ponieważ pula jest zadeklarowana w funkcji UxDomainSocket.

Właściwie twój benchmark nie testuje gevent, redis ani redis-py:wykorzystuje zdolność maszyny wirtualnej do podtrzymania gry ping-pong między dwoma procesami.

Jeśli chcesz zwiększyć wydajność, musisz:

  • użyj potokowania, aby zmniejszyć liczbę podróży w obie strony

  • spraw, aby pula była trwała w całym benchmarku

Rozważmy na przykład następujący skrypt:

#!/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)

Dzięki temu skryptowi uzyskuję około 3 razy lepszą wydajność i prawie zerowe koszty związane z gevent.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. ServiceStack.Net Redis:przechowywanie powiązanych obiektów w porównaniu z powiązanymi identyfikatorami obiektów

  2. Architektura dla pamięci podręcznej Redis i Mongo dla trwałości

  3. Błąd:połączenie Redis z 127.0.0.1:6379 nie powiodło się - połącz ECONNREFUSED 127.0.0.1:6379

  4. Czy redis na Heroku jest możliwy bez dodatku?

  5. Redis filtruj według zakresu, sortuj i zwróć najpierw 10