본문 바로가기

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

19.Redis, 레디스 인코딩 중 문자열 데이터 인코딩 에 대해서 알아볼께요.^^

반응형

레디스 인코딩에 대해서..

  • Redis 는 데이터의 주 저장소로 메모리를 사용함.
    • 메모리
      • 운영 체제의 관점에서 한정적인 자원이며 매우 비싼 리소스임.
  • Redis 개발자는 제한적인 환경에서 데이터를 효율적으로 저장하기 위해서 인코딩을 사용함.

문자열 데이터 인코딩

  • 문자열을 저장하기 위해서 3가지 인코딩을 사용함.
    • OBJ_ENCODING_INT
    • value가 정수임을 나타낸다. 실수(소숫점 포함)는 string으로 분류된다.
    • 단, 숫자가 0으로 시작하면 string이다. 예를 들어 123은 int이고 0123은 embstr이다.
    • 그리고, 64bit 환경에서 long int형의 max 값(9223372036854775807)을 벗어나면 embstr 임.
    • 참고#1) 64bit 환경의 long int형 범위
      • -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807
      • The number 9,223,372,036,854,775,807 is the integer equal to 263 − 1.
    • 참고#2) C 언어에 type에 대한 size
    • OBJ_ENCODING_EMBSTR
      • value가 string이고 44문자 이하임을 나타낸다.
      • embedded string, embstr은 3.0부터 표시된다.
      • 이전 버전은 raw로 표시되었음.
    • OBJ_ENCODING_RAW
      • value가 string이고 45문자 이상임을 나타낸다.
  • 인코딩 확인 object 명령
    • redis> object encoding [key]
        • 위 예제를 통해서 redis 의 문자열 데이터 인코딩에 대해서 확인 해볼 수 있음.
        • thub:key:1 의 값
          • Redis는 10000보다 작은 숫자를 미리 공유객체 상수로 등록해 두어 같은 객체를 재사용함.
          • 공유객체상수를 쓰면, 동일한 값을 가지는 데이터를 한 번만 저장하므로 메모리 낭비를 막을 수 있음.
          • 다시말해서, 1000개의 key에 10000보다 작은 동일한 숫자 1181 를 저장하면, Redis는 1181의 데이터를 별도의 공간에 저장하지 않음.
          • 자세한 사항은, 추후에 정리할 "Redis 공유객체" 편에서 자세히 설명하겠습니다. ^^; 잠시만 기둘려주세욤
          • thub:key:2 의 값
            • long int형의 max 값(9223372036854775807) 을 벗어나지 않았으므로 int 인코딩
          • thub:key:3 의 값
            • long int형의 max 값(9223372036854775807) 을 벗어났으므로 embstr 인코딩
          • thub:key:4 의 값
            • 44문자 이하이므로 embstr 인코딩
          • thub:key:5 의 값
            • 45문자 이상이므로 raw 인코딩
  • Redis 의 SET 명령 소스
    • t_string.c 파일의 setCommand() 함수에서 수행됨.
      • setCommand 함수는 명령 수행을 위한 데이터 검증이 완료된 후 tryObjectEncoding()라는 함수를 수행하여 적당한 인코딩을 선택하는 로직으로 구성됨.
        • 즉, 입력된 데이터에 대해서 가능한 한 적은 메모리를 사용하는 인코딩을 선택함.
      • 참고) tryObjectEncoding() 함수
        • 단, object.c 파일에 정의되어 있음
robj *tryObjectEncoding(robj *o) {
    long value;
    sds s = o->ptr;
    size_t len;

    /* Make sure this is a string object, the only type we encode
     * in this function. Other types use encoded memory efficient
     * representations but are handled by the commands implementing
     * the type. */
    serverAssertWithInfo(NULL,o,o->type == OBJ_STRING);

    /* We try some specialized encoding only for objects that are
     * RAW or EMBSTR encoded, in other words objects that are still
     * in represented by an actually array of chars. */
    if (!sdsEncodedObject(o)) return o;

    /* It's not safe to encode shared objects: shared objects can be shared
     * everywhere in the "object space" of Redis and may end in places where
     * they are not handled. We handle them only as values in the keyspace. */
     if (o->refcount > 1) return o;

    /* Check if we can represent this string as a long integer.
     * Note that we are sure that a string larger than 20 chars is not
     * representable as a 32 nor 64 bit integer. */
    len = sdslen(s);
    if (len <= 20 && string2l(s,len,&value)) {
        /* This object is encodable as a long. Try to use a shared object.
         * Note that we avoid using shared integers when maxmemory is used
         * because every object needs to have a private LRU field for the LRU
         * algorithm to work well. */
        if ((server.maxmemory == 0 ||
            !(server.maxmemory_policy & MAXMEMORY_FLAG_NO_SHARED_INTEGERS)) &&
            value >= 0 &&
            value < OBJ_SHARED_INTEGERS)
        {
            decrRefCount(o);
            incrRefCount(shared.integers[value]);
            return shared.integers[value];
        } else {
            if (o->encoding == OBJ_ENCODING_RAW) sdsfree(o->ptr);
            o->encoding = OBJ_ENCODING_INT;
            o->ptr = (void*) value;
            return o;
        }
    }

    /* If the string is small and is still RAW encoded,
     * try the EMBSTR encoding which is more efficient.
     * In this representation the object and the SDS string are allocated
     * in the same chunk of memory to save space and cache misses. */
    if (len <= OBJ_ENCODING_EMBSTR_SIZE_LIMIT) {
        robj *emb;

        if (o->encoding == OBJ_ENCODING_EMBSTR) return o;
        emb = createEmbeddedStringObject(s,sdslen(s));
        decrRefCount(o);
        return emb;
    }

    /* We can't encode the object...
     *
     * Do the last try, and at least optimize the SDS string inside
     * the string object to require little space, in case there
     * is more than 10% of free space at the end of the SDS string.
     *
     * We do that only for relatively large strings as this branch
     * is only entered if the length of the string is greater than
     * OBJ_ENCODING_EMBSTR_SIZE_LIMIT. */
    trimStringObjectIfNeeded(o);

    /* Return the original object. */
    return o;
}
  • 설명
    • redis.conf 환경설정 파일에 maxmemory 설정이 지정되어 있지 않으면, 지정하려는 값이 레디스 공유 객체 상수의 숫자범위안에 포함되는지 검사함.
    • 미리 지정되어 있는 숫자상수의 범위는 0 ~ 9999 
    • server.h 에 아래가 정의되어 있음.
      • #define OBJ_SHARED_INTEGERS 10000
    • 즉, maxmemory 설정을 지정하지 않으면 시스템에서 제공하는 메모리를 최대한 사용함.
    • 결과적으로 redis.conf 환경설정에 메모리 사용 제한이 되어 있지않으면서, 10000보다 크거나 같은 수를 저장하면 별도의 메모리 공간을 할당하여 OBJ_ENCODING_INT 인코딩으로 저장함.
    • 10000보다 작은 숫자는 동일한 객체를 참조하기 때문에 추가적인 저장공간을 사용하지 않고 10000보다 크더라도 long 범위 안에 포함되는 숫자면 OBJ_ENCODING_INT 인코딩을 사용하여 저장하기 때문에 더 효율적인 메모리 사용량을 보이게됨.
    • 소스의 주요 요지는 효율적인 메모리 사용을 위한 인코딩을 Redis 는 지향한다임.

결론

  • Redis 는 문자열 데이터를 3가지 방법으로 인코딩해서 사용함.
    • OBJ_ENCODING_INT
    • OBJ_ENCODING_EMBSTR
    • OBJ_ENCODING_RAW
  • 인코딩을 확인하는 명령어를 지원함.
    • object encoding [key]
  • 소스에 구현된 주요 내용에 대해서 말하자면,
    • Redis 는 효율적인 메모리 사용을 위한 인코딩을 지향하고 그렇게 구현되어 있음.

  • 오늘의 명언 한마디
    • 내가먼저 적극적인 관심과 인간적인 모습을 보이고, 상대방에게 도움이 될 사람이라는 것을 어필해야한다. -신형강(부룡)지음, "부동산 투자 이렇게 쉬웠어?" 중에서...

  • 오늘의 영어 한마디
    • 질문) Sorry, I'm late!
      • 늦어서 미안해.
    • 대답) We were afraid you wouldn't make it on time!
      • 걱정했자나..
    • 해설
      • sorry 는 "미안" 이라고 해석함.
      • "We were afraid ~" 는 직역하면, "네가 시간에 맞추지 못할 것 같아 걱정했다."
      • be afraid 는 "걱정하여(염려하여, 두려워하여)" 임.
      • make it 은 "성공하다" 라는 의미이지만, 시간을 주제로 할 땐 "제시간에 맞추다"라는 의미가 됨.
728x90
300x250