복붙노트

[REDIS] 레디 스 + gevent을 - 성능이 저하 - 내가 잘못 뭐하는 거지?

REDIS

레디 스 + gevent을 - 성능이 저하 - 내가 잘못 뭐하는 거지?

난 그냥 비동기가 perforamance을하는 데 도움이 나는 나쁜 성능을 찾기 위해 놀랐다 방식을 볼 수 반환 한 테스트 레디 스 +의 gevent에 코드의 간단한 조각을 썼다. 여기에 내 코드입니다. 당신은 원숭이 패치에 처음 두 줄의 코드를 제거하는 경우에 당신은 "정상적인 실행"타이밍을 볼 수 있습니다.

우분투 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)

해결법

  1. ==============================

    1.이는 예상된다.

    이는 예상된다.

    당신은 시스템 호출의 비용이 물리적 하드웨어에보다 높은에서 VM에이 벤치 마크를 실행합니다. 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를 여기에 아무것도 개선되지 수 있습니다.

    또한 레디 스 때문에위한 최악의 경우입니다 :

    실제로 벤치 마크는하지 테스트 gevent을 수행 레디 스 또는 레디 스-평 : 그것은 두 프로세스 사이의 탁구 게임을 유지하기 위해 VM의 기능을 행사한다.

    당신이 성능을 향상하려면 다음을 수행해야합니다

    예를 들어, 다음 스크립트를 고려 :

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

    이 스크립트, 나는 gevent 거의 오버 헤드 3 배 성능 향상에 대해 얻을합니다.

  2. from https://stackoverflow.com/questions/10656953/redis-gevent-poor-performance-what-am-i-doing-wrong by cc-by-sa and MIT license