본문 바로가기

좋아하는 것_매직IT/9.redis

20.Redis, 레디스 인코딩 중 리스트 데이터 인코딩 에 대해서 알아볼께요.^^

반응형

리스트 데이터 인코딩에 대해서..

  • 버전 3.2.0 이전 ZIPLIST(small lists), LINKEDLIST 이었음. 
    • OBJ_ENCODING_ZIPLIST
    • OBJ_ENCODING_LINKEDLIST
  • but, 버전 3.2.0 부터 QUICKLIST하나로 통일되어 사용됨.
    • OBJ_ENCODING_QUICKLIST
  • 인코딩 타입에 대한 선언 소스 코드
    • server.h

인코딩에 대한 설명

  • 레디스 버전 3.2.0 이전
    • OBJ_ENCODING_ZIPLIST
      • member 갯수가 512개 까지이거나, 값의 길이가 64까지는 ziplist이다.
        • 이것은 redis.conf에 list-max-ziplist-entries 512, list-max-ziplist-value 64 로 설정할 수 있다.
    • OBJ_ENCODING_LINKEDLIST
      • member 갯수가 513개 이상이거나, 값의 길이가 65부터는 LINKEDLIST이다.
    • 여기서 ZIPLIST와 LINKEDLIST차이점을 간단히 살펴보면,
      • ZIPLIST의 장점은 내부적으로 포인터를 안써서 메모리 절약이 된다는 점이고, 단점으로는 리스트 중간에 노드를 추가/삭제를 하게되면 메모리 재할당, 복사/이동이 일어난다.
      • LINKEDLIST의 장점은 추가/삭제가 쉽다는 점이고, 단점으로는 작은 값(예:4 byte)을 추가하는데 실제 값보다 더 많은 메타데이타?(예: prev, next 포인터, 8 byte)를 사용한다.

      • 즉, 정리하자면, ZIPLIST는 소위 말하는 배열로 구현한 것이고, LINKEDLIST 는 소위 말하는 포인터로 구현한 것임.

    • 특이점이 있다면,

      • ZIPLIST -> LINKEDLIST변환은 되는데 LINKEDLIST-> ZIPLIST 변환은 안됨.

  • 레디스 버전 3.2.0 부터

    • 위의 두 가지를 합한 OBJ_ENCODING_QUICKLIST 하나만 사용함.

    • QUICKLIST 란?

      • 각 노드를 ZIPLIST로 구성하고 적정 크기로 유지하면서 각각의 노드는 포인터로 연결하는 자료구조임.

        • 데이타를 ZIPLIST에 추가하다 조건이 충족되면 노드를 하나 더 생성해서 새로운 노드에 데이타를 저장하거나 노드를 split한후 데이타를 저장하고 Merge하는 작업을 하게 구현되어 있음.

        • ZIPLIST에서 더 아끼기위해 압축도 한다고 함. ^^;; 역시 Redis 개발자 ^^b

      • QUICKLIST 구조체 소스 (quicklist.h 헤더파일에서 정의되어 있음)

  • 인코딩에 대한 예제.

      • object enconding 명령을 통해서 인코딩 타입이 quicklist 임을 확인할 수 있음.

  • 리스트 데이터의 push 명령을 위한 함수 정의 (t_list.c 파일에 존재함)

/*-----------------------------------------------------------------------------
 * List Commands
 *----------------------------------------------------------------------------*/

void pushGenericCommand(client *c, int where) {
    int j, pushed = 0;
    robj *lobj = lookupKeyWrite(c->db,c->argv[1]);

    if (lobj && lobj->type != OBJ_LIST) {
        addReply(c,shared.wrongtypeerr);
        return;
    }

    for (j = 2; j < c->argc; j++) {
        if (!lobj) {
            lobj = createQuicklistObject();
            quicklistSetOptions(lobj->ptr, server.list_max_ziplist_size,
                                server.list_compress_depth);
            dbAdd(c->db,c->argv[1],lobj);
        }
        listTypePush(lobj,c->argv[j],where);
        pushed++;
    }
    addReplyLongLong(c, (lobj ? listTypeLength(lobj) : 0));
    if (pushed) {
        char *event = (where == LIST_HEAD) ? "lpush" : "rpush";

        signalModifiedKey(c->db,c->argv[1]);
        notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[1],c->db->id);
    }
    server.dirty += pushed;
}

void lpushCommand(client *c) {
    pushGenericCommand(c,LIST_HEAD);
}

void rpushCommand(client *c) {
    pushGenericCommand(c,LIST_TAIL);
}

void pushxGenericCommand(client *c, int where) {
    int j, pushed = 0;
    robj *subject;

    if ((subject = lookupKeyWriteOrReply(c,c->argv[1],shared.czero)) == NULL ||
        checkType(c,subject,OBJ_LIST)) return;

    for (j = 2; j < c->argc; j++) {
        listTypePush(subject,c->argv[j],where);
        pushed++;
    }

    addReplyLongLong(c,listTypeLength(subject));

    if (pushed) {
        char *event = (where == LIST_HEAD) ? "lpush" : "rpush";
        signalModifiedKey(c->db,c->argv[1]);
        notifyKeyspaceEvent(NOTIFY_LIST,event,c->argv[1],c->db->id);
    }
    server.dirty += pushed;
}

void lpushxCommand(client *c) {
    pushxGenericCommand(c,LIST_HEAD);
}

void rpushxCommand(client *c) {
    pushxGenericCommand(c,LIST_TAIL);
}
  • lpush, rpush, lpushx, rpushx 의 명령어를 수행할 때 위의 함수가 호출됨.
  • 리스트 데이터의 저장을 위한 listTypePush 함수 소스는 아래와 같음.(역시 t_list.c 파일에 있음)

결론

  • Redis의 리스트 데이터 인코딩은 버전 3.2.0 이전과 이후가 달라지게 됨.
  • 리스트 데이터를 사용할 때, 위의 소스코드를 알고 있으면 내부 에서 어떻게 동작하는지 명확하게 보임.
  • Redis 소스코드를 볼때마다 개발자로써 경이로움. ^^; 이래서 Redis 를 많이 사용하는 구나 !

  • 오늘의 명언 한마디
    • 좋은 기회를 남들보다 빨리 선점해 투자 수익률을 높이려면, 중개사와의 관계에 있어서도 평소에 꾸준한 관심과 노력을 기울여야 한다. - 신현강(부룡)지음, "부동산투자이렇게쉬웠어?" 중에서..

  • 오늘의 영어 한마디
    • 질문) What are you sore about?
      • 왜 그리 화가 나있는거야?
    • 대답) Hmph! You wouldn't understand!
      • 흥, 말해봤자 네가 알겠어?
    • 해설
      • sore 는 따끔따끔 쑤시다. 라는 의미의 형용사
        • 예문에는 화내고 있다라고 쓰임.
      • "I have a sore throat." 목이 쑤시다, 와 같은 경우엔, 육체적으로 아프다라는 의미
      • sore-head 는 "다혈질"이라는 표현으로도 쓰임.
728x90
300x250