Redis
 sql >> база данни >  >> NoSQL >> Redis

redis + gevent - Лоша производителност - какво правя нередно?

Това се очаква.

Изпълнявате този бенчмарк на виртуална машина, на която цената на системните повиквания е по-висока, отколкото на физическия хардуер. Когато gevent е активиран, той има тенденция да генерира повече системни обаждания (за обработка на устройството epoll), така че в крайна сметка имате по-ниска производителност.

Можете лесно да проверите тази точка, като използвате strace в скрипта.

Без gevent, вътрешният цикъл генерира:

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

С gevent ще имате случаи на:

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

Когато повикването recvfrom е блокирано (EAGAIN), gevent се връща към цикъла на събитията, така че се извършват допълнителни повиквания, за да се изчакат събития на файлови дескриптори (epoll_wait).

Моля, имайте предвид, че този вид бенчмарк е най-лошият случай за всяка система за цикъл на събития, тъй като имате само един файлов дескриптор, така че операциите на изчакване не могат да бъдат разложени на фактори на няколко дескриптора. Освен това асинхронните I/O не могат да подобрят нищо тук, тъй като всичко е синхронно.

Това също е най-лошият случай за Redis, защото:

  • той генерира много двупосочни пътувания до сървъра

  • той систематично се свързва/прекъсва (1000 пъти), защото пулът е деклариран във функцията UxDomainSocket.

Всъщност вашият бенчмарк не тества gevent, redis или redis-py:той упражнява способността на VM да поддържа пинг-понг игра между 2 процеса.

Ако искате да увеличите производителността, трябва да:

  • използвайте конвейер, за да намалите броя на двупосочните пътувания

  • направете пула постоянен в целия еталон

Например, помислете със следния скрипт:

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

С този скрипт получавам около 3 пъти по-добра производителност и почти никакви излишни разходи с gevent.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Прескачащи ключове за сканиране на Redis

  2. Инсталиране на Redis на CentOS 7

  3. Изсушаване на общ RedisTemplate през пролетта 4

  4. Конфигурация за внедряване на Redis - главна подчинена репликация

  5. Запитване с Redis?