Redis + Gevent - плохой производительность - что я делаю не так?
-
11-12-2019 - |
Вопрос
Я только что написал простой кусок кода для Perf Test Redis + Gevent, чтобы увидеть, как Async помогает перфорамс, и я был удивлен, чтобы найти плохую производительность.Вот мой код.Если вы избавитесь от первых двух линий к Bonkey Patch этот код, вы увидите время «нормальное исполнение».
на Ubuntu 12.04 LTS VM, я вижу время
без обезьян патч - 54 секунды С обезьяной патч - 61 секунд
Есть что-то не так с моим кодом / подходом?Здесь возникает ли совершенная проблема?
#!/usr/bin/python
from gevent import monkey
monkey.patch_all()
import timeit
import redis
from redis.connection import UnixDomainSocketConnection
def UxDomainSocket():
pool = redis.ConnectionPool(connection_class=UnixDomainSocketConnection, path = '/var/redis/redis.sock')
r = redis.Redis(connection_pool = pool)
r.set("testsocket", 1)
for i in range(100):
r.incr('testsocket', 10)
r.get('testsocket')
r.delete('testsocket')
print timeit.Timer(stmt='UxDomainSocket()',
setup='from __main__ import UxDomainSocket').timeit(number=1000)
. Решение
Это ожидается.
Вы запускаете этот тест на VM, на котором стоимость системных вызовов выше, чем на физическом оборудовании. Когда Gevent активирован, он имеет тенденцию генерировать больше системных вызовов (для обработки устройства EPOLL), поэтому вы заканчиваете менее производительностью.
Вы можете легко проверить эту точку, используя stroace на скрипте.
без 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
.
Когда вызов RECVROM блокирует (eaegain), Gevent возвращается к контуру события, чтобы дождаться дополнительные вызовы, чтобы дождаться события дескрипторов файлов (Epoll_Wait).
Обратите внимание, что этот вид ориентира является худшим случаем для любой системы цикла событий, поскольку у вас есть только один файловый дескриптор, поэтому операции ожидания не могут быть факторизованы на нескольких дескрипторах. Кроме того, Async I / OS не может больше улучшить здесь, так как все синхронно.
Это также худший случай для Redis, потому что:
- .
-
Это генерирует много круглых игр к серверу
-
Это систематически соединяет / отключает (1000 раз), потому что пул объявлен в функции Uxdomainsocket.
На самом деле ваш ориентир не тестирует Gevent, Redis или Redis-Py: он осуществляет возможность VM для поддержания игры Ping-Pong между 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)
с этим скриптом, я получаю около 3x лучшую производительность и практически не накладки с Gevent.
-