Redis
 sql >> Teknologi Basis Data >  >> NoSQL >> Redis

redis + gevent - Performa buruk - apa yang saya lakukan salah?

Ini diharapkan.

Anda menjalankan tolok ukur ini pada VM, yang biaya panggilan sistemnya lebih tinggi daripada perangkat keras fisik. Saat gevent diaktifkan, ia cenderung menghasilkan lebih banyak panggilan sistem (untuk menangani perangkat epoll), sehingga performa Anda akan berkurang.

Anda dapat dengan mudah memeriksa poin ini dengan menggunakan strace pada skrip.

Tanpa gevent, loop dalam menghasilkan:

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

Dengan gevent, Anda akan mengalami kejadian:

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

Saat panggilan recvfrom memblokir (EAGAIN), gevent kembali ke loop peristiwa, jadi panggilan tambahan dilakukan untuk menunggu peristiwa deskriptor file (epoll_wait).

Harap dicatat benchmark semacam ini adalah kasus terburuk untuk sistem loop peristiwa apa pun, karena Anda hanya memiliki satu deskriptor file, sehingga operasi menunggu tidak dapat difaktorkan pada beberapa deskriptor. Selanjutnya, I/O async tidak dapat meningkatkan apa pun di sini karena semuanya sinkron.

Ini juga merupakan kasus terburuk bagi Redis karena:

  • itu menghasilkan banyak perjalanan pulang pergi ke server

  • itu secara sistematis menghubungkan/memutuskan (1000 kali) karena kumpulan dideklarasikan dalam fungsi UxDomainSocket.

Sebenarnya tolok ukur Anda tidak menguji gevent, redis, atau redis-py:tolok ukur ini melatih kemampuan VM untuk mempertahankan permainan ping-pong di antara 2 proses.

Jika Anda ingin meningkatkan kinerja, Anda perlu:

  • gunakan pipelining untuk mengurangi jumlah perjalanan pulang pergi

  • membuat kumpulan tetap ada di seluruh tolok ukur

Misalnya, pertimbangkan dengan skrip berikut:

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

Dengan skrip ini, saya mendapatkan kinerja sekitar 3x lebih baik dan hampir tidak ada overhead dengan gevent.




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Bagaimana cara berkomunikasi dynos Web dan Worker dengan Node.js di Heroku?

  2. Kesalahan tidak terikat elemen Integrasi JHipster Redis

  3. Menggunakan Replikasi Redis pada mesin yang berbeda (multi master)

  4. Redis mencoba terhubung ke localhost di Heroku alih-alih REDIS_URL

  5. Bagaimana Anda mencari kunci dengan nilai? Misalnya dapatkan semua KUNCI di mana nilainya adalah beberapa nilai