[입 개발] Redis Internals : sds

몇일 전에 Redis의 아이템 하나의 메모리 한계가 512MB 라고 말씀드렸습니다. 그러면, 오늘은 왜 그런가와 이걸 수정하려고 하면 Redis에서 어떤 부분이 바뀌어야 할 것인지에 대해서 설명을 하려고 합니다. 그리고 그러기 위해서 우리는 sds 라는 Redis에서 사용하는 string 구조체를 알 필요가 있습니다. 사실 sds 는 그냥 char * 입니다. 실제로 정의는 다음과 같이 sds.h 에 존재합니다.


typedef char *sds;

 

그리고 이를 관리하기 위해서 sdshdr 이라는 구조체를 사용하는 데 다음과 같습니다. len, free, buf 세 개의 변수를 가지고, len 현재 sds의 길이 free는 sds의 남은 용량, buf는 실제 버퍼를 가리키는 pointer 입니다. 즉 최초에 sdshdr을 하나 할당하고, 다시 거기에 buf를 할당해서 buf만 돌려주는게 sds의 핵심입니다. (잡담하나, 이런 구조를 만드시면 memory alignment에 신경을 써야 합니다. 예전에 이런 형태에 앞에 len을 2 bytes로 잡아서 처리한 적이 있는데, 일반 윈도우 장비에서는 문제가 없다가 ARM인지 하드디스크 드라이버가 특이한 곳에 갔더니, 데이터가 전부 0으로 들어오는 버그가 ㅋㅋ, 그냥 이렇게 4byte 단위로 alignment 되는 크기를 잡으시면 됩니다.)

sds_1

 

그래서 이 sds 관련 함수들은 이 sdshdr 을 적절히 핸들링하게 됩니다. 예를 들어 sds의 길이를 알고 싶다면 strlen을 써도 되지만, 다음과 같이 sdslen 함수를 이용하면 훨씬 빠르게 됩니다. 이미 len을 가지고 있어서 그렇습니다.

 


static inline size_t sdslen(const sds s) {
struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));
return sh->len;
}

 

그럼 이게 왜 문제가 되는가하면? 32bit에서는 메모리 한계가 2G 이므로, 더 이상의 메모리 할당이 안됩니다. 즉 기존의 char *형태로 사용하는 sds 는 2G 이상을 처리하지 못한다는 결론이 나옵니다.(32bit 에서만), 즉 아이템의 크기 제한을 없애기 위해서는 간단하게 64bit 만 사용하게 하든지, 아니면 내부적으로 사용하는 이 sds 형태를 완전히 새롭게 뜯어고쳐야 합니다. redis 내부적으로  sds를 상당히 많이 사용하므로, 전체적인 구조 조정이 될것 같습니다.  그럼 sds 에 대한 설명을 마칩니다.