2012-05-18 11 views
20

मैंने पेर्फ टेस्ट रेडिस + गीवेंट को कोड का एक साधारण टुकड़ा लिखा है, यह देखने के लिए कि एसिंक कैसे छिद्रण में मदद करता है और मैं खराब प्रदर्शन खोजने में आश्चर्यचकित था। यहाँ मेरा कोड है। यदि आप इस कोड को बंदर पैच करने के लिए पहली दो पंक्तियों से छुटकारा पा लेते हैं तो आपको "सामान्य निष्पादन" समय दिखाई देगा।redis + gevent - खराब प्रदर्शन - मैं क्या गलत कर रहा हूँ?

एक Ubuntu 12.04 LTS वी एम पर, मैं

के समय देख रहा हूँ बंदर पैच के बिना - 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) 

उत्तर

47

यह उम्मीद है।

आप इस बेंचमार्क को वीएम पर चलाते हैं, जिस पर सिस्टम कॉल की लागत भौतिक हार्डवेयर से अधिक है। जब गीवेंट सक्रिय होता है, तो यह अधिक सिस्टम कॉल उत्पन्न करता है (एपोल डिवाइस को संभालने के लिए), ताकि आप कम प्रदर्शन के साथ समाप्त हो जाएं।

आप स्क्रिप्ट पर स्ट्रेस का उपयोग करके आसानी से इस बिंदु की जांच कर सकते हैं।

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/Os यहां कुछ भी सुधार नहीं कर सकता क्योंकि सब कुछ तुल्यकालिक है।

यह भी Redis के लिए एक सबसे खराब स्थिति है क्योंकि:

  • यह सर्वर के लिए कई roundtrips उत्पन्न

  • इसे व्यवस्थित जोड़ता है/डिस्कनेक्ट (1000 बार), क्योंकि पूल UxDomainSocket समारोह में घोषित किया जाता है ।

वास्तव में अपने बेंचमार्क परीक्षण नहीं होता gevent, redis या redis-py: यह एक वी एम की क्षमता अभ्यास 2 प्रक्रियाओं के बीच एक पिंगपांग खेल बनाए रखने के लिए।

आप प्रदर्शन में वृद्धि करना चाहते हैं, तो आप की जरूरत है:

  • उपयोग पाइपलाइनिंग roundtrips की संख्या में कमी करने के लिए

  • पूल पूरे बेंचमार्क

भर में लगातार बनाने उदाहरण के लिए, निम्न स्क्रिप्ट के साथ विचार करें:

#!/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 बेहतर प्रदर्शन मिलता है और लगभग गेवेंट के साथ कोई ओवरहेड नहीं मिलता है।

+0

विस्तृत प्रतिक्रिया के लिए धन्यवाद। अगर मैं गहराई से मुद्दा समझता हूं जो मैंने किया है, वह केवल एक "ऑब्जेक्ट" है जिस पर इंतजार किया जा सकता है - उदाहरण के लिए मेरे पास रेडिस कनेक्शन का एक पूल था और मैं गीवेंट का उपयोग करता हूं तो यह मुझे बेहतर प्रदर्शन देगा (मानते हुए रेडिस रख सकते हैं)। बीटीडब्ल्यू वीएम (और यूएक्स सॉकेट) केवल परीक्षण के लिए था। उत्पादन अलग-अलग उदाहरण होंगे, – vivekv

+0

यदि पाइपलाइन का उपयोग किया जाता है, तो "रेडिस लॉक" का उपयोग कैसे करें – Tallmad

संबंधित मुद्दे