복붙노트

[REDIS] 비동기 레디 스는 libevent를 사용하여 풀링

REDIS

비동기 레디 스는 libevent를 사용하여 풀링

나는 레디 스 + Hiredis +의 libevent에서 최대한 얻을합니다.

나는 (어떤 검사없이 짧게) 다음 코드를 사용하고 있습니다

#include <stdlib.h>
#include <event2/event.h>
#include <event2/http.h>
#include <event2/buffer.h>
#include <hiredis/hiredis.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libevent.h>

typedef struct reqData {
  struct evhttp_request* req;
  struct evbuffer* buf;
} reqData;

struct event_base* base;
redisAsyncContext* c;

void get_cb(redisAsyncContext* context, void* r, void* data) {
  redisReply* reply = r;
  struct reqData* rd = data;

  evbuffer_add_printf(rd->buf, "%s", reply->str);
  evhttp_send_reply(rd->req, HTTP_OK, NULL, rd->buf);

  evbuffer_free(rd->buf);
  redisAsyncDisconnect(context);
}

void cb(struct evhttp_request* req, void* args) {
  struct evbuffer* buf;
  buf = evbuffer_new();

  reqData* rd = malloc(sizeof(reqData));
  rd->req = req;
  rd->buf = buf;

  c = redisAsyncConnect("0.0.0.0", 6380);
  redisLibeventAttach(c, base);

  redisAsyncCommand(c, get_cb, rd, "GET name");
}

int main(int argc, char** argv) {
  struct evhttp* http;
  struct evhttp_bound_socket* sock;

  base = event_base_new();
  http = evhttp_new(base);
  sock = evhttp_bind_socket_with_handle(http, "0.0.0.0", 8080);

  evhttp_set_gencb(http, cb, NULL);

  event_base_dispatch(base);

  evhttp_free(http);
  event_base_free(base);
  return 0;
}

, 사용의 gcc -o 주요 -levent -lhiredis main.c의 가정 libevent을 컴파일하려면, 레디 스 및 시스템에 hiredis.

호기심 나는 내가 redisAsyncConnect을해야 할 때? 각 콜백의 main () 또는 일단 (예를 들어 방송과 같은)이다. 내가 성능을 향상하기 위해 할 수있는 일이 있나요?

나는 6000-7000 필수 / S에 대한 얻고있다. 벤치 마크이에 AB를 사용하여 물건을 복잡하게 (예를 들어 10,000 REQS) 큰 숫자를 시도 할 때 -이 완료 벤치 마크 및 정지를 할 수 없습니다. 같은 일을하고 있지만 방법을 차단의 결과는 5000-6000 필수 / S입니다.

나는 맥 OS X 라이온을 사용하고 10000 -n 제한에 의해 최대 파일 열기를 확장했습니다.

해결법

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

    1.그것은 한 번 레디 스 연결을 열고 최대한 재사용하려고 물론 훨씬 더이다.

    그것은 한 번 레디 스 연결을 열고 최대한 재사용하려고 물론 훨씬 더이다.

    임시 포트 범위에서 무료로 포트의 수를 소모하기 때문에 제공되는 프로그램으로, 나는 벤치 마크 동결을 생각한다. 레디 스에 새로운 연결을 개폐 할 때마다, 해당 소켓 TIME_WAIT 모드의 시간 (이 점은 netstat 명령을 사용하여 확인할 수있다) 보낸다. 커널은 그들에게 충분히 빨리를 수거하여 재활용 할 수 없습니다. 당신이 그들을 너무 많이있을 때, 더 이상 클라이언트 연결이 시작되지 않을 수 있습니다.

    또한 프로그램의 메모리 누수가 다음 reqData 구조는 각 요청에 대해 할당 및 할당 해제되지 않습니다. 무료는 get_cb에 없습니다.

    레디 스에 사용되는 것들, 서버에 연결하는 벤치 마크 도구로 연 사람 : 사실,이 가능 TIME_WAIT 소켓의 근원이있다. 레디 스 연결은 프로그램에 인수 분해되어야한다. 벤치 마크 도구는 HTTP 1.1과 keepalived 연결을 사용하도록 구성해야합니다.

    개인적으로, 나는 벤치 마크의이 종류를 실행 AB 이상 포위 공격을 사용하는 것을 선호합니다. AB는 HTTP 서버를 벤치마킹에 관심이있는 대부분의 사람들이 순진 도구로 간주됩니다.

    나의 오래된 리눅스 PC, 초기 프로그램에서 50 개 keepalived 연결의 결과로 벤치 마크 모드에서 포위 공격에 대해 실행 :

    Transaction rate:            3412.44 trans/sec
    Throughput:                     0.02 MB/sec
    

    우리가 완전히 레디 스에 대한 호출을 제거하면, 단지 더미 결과를 반환, 우리가 얻을 :

    Transaction rate:            7417.17 trans/sec
    Throughput:                     0.04 MB/sec
    

    이제, 레디 스 연결을 인수 분해 할 수있는 프로그램을 수정하자, 자연스럽게 파이프 라인 혜택을 누릴 수 있습니다. 소스 코드는 여기에서 확인할 수 있습니다. 우리가 얻는 이유는 여기에 있습니다 :

    Transaction rate:            7029.59 trans/sec
    Throughput:                     0.03 MB/sec
    

    즉, 체계적인 연결 / 분리 이벤트를 제거하여, 우리는 두 배의 처리량을 달성 할 수있다. 레디 스 호출로 성능은 성능보다 지금까지하지 않습니다 우리는 어떤 레디 스 호출하지 않고 얻을.

    더욱 최적화하기 위해, 당신은 당신의 서버와 레디 스 사이 유닉스 도메인 소켓을 사용하는 것이 좋습니다 및 / 또는 CPU 소비를 줄이기 위해 동적으로 할당 된 객체를 풀 수 있습니다.

    최신 정보:

    유닉스 도메인 소켓을 실험하기 위해, 간단합니다 : 당신은 단지 구성 파일을 업데이트하여 레디 스 자체에 지원을 활성화해야합니다 :

    # Specify the path for the unix socket that will be used to listen for
    # incoming connections. There is no default, so Redis will not listen
    # on a unix socket when not specified.
    #
    unixsocket /tmp/redis.sock
    unixsocketperm 755
    

    다음 연결 기능을 대체 :

    c = redisAsyncConnect("0.0.0.0", 6379);
    

    으로:

    c = redisAsyncConnectUnix("/tmp/redis.sock");
    

    참고 : 영향은 낮을 것이다, 그래서 여기에 hiredis 비동기은 (연결이 영구적으로 제공하는) 명령을 파이프 라이닝에서 좋은 작업을 수행합니다.

  2. from https://stackoverflow.com/questions/9958589/async-redis-pooling-using-libevent by cc-by-sa and MIT license