redis容量推定
4360 ワード
仕事でredisをストレージ型のkvストレージとしてよく使うのですが、どのように合理的にスペースを推定しますか?
まずredisの記憶原理を見てみると、redisの記憶時にkvは文字列や文字配列に処理され、redisはappend、rehashなどの操作を容易に行うsdsタイプを実現している.
この注記はsdshdr 5では使用しませんが、sizeが2^5-1未満の文字列ではSDS_が使用されます.TYPE_5.
各ヘッダの定義に最後にchar buf[]があります.これはフレキシブル配列(flexible array member)であり、flagsフィールドの後ろに文字配列があり、メモリ領域を占有しないことを示すタグとして機能します.
ここを見てSDS_TYPE 5のヘッダは1バイトしか占めていませんが、SDS_TYPE_8は3バイト
sds上にrobjもカプセル化されており、以下のように定義されている.
読み取りを迅速に格納するために、すべてのkvはdict構造に保存され、各dictEntryはこのような形式である.
keyは「aaa」のsdsポインタであり、vは「bbb」を含むrobjを指すポインタ、すなわちdictEntryが24バイトを占め、1つのkeyがsdsがsdshader+自体のコンテンツ+エンドマーク(1)を占め、1つのvがrobjがsdsとrobjの空間を占め、約12バイトである.
たとえば、ユーザーログインのtokenを格納するテーブルがあります.
どのくらいのスペースを占有しますか?ユーザID 19ビット、token 50ビットを仮定すると、keyはSDS_TYPE_5,1+19+1=21バイト、valueはSDS_TYPE_8になり、robj、すなわち3+12+50+1=66に包装され、dictEntry 24バイト
合計111バイトということで、1つのレコードが占めるスペースをおおよそ算出し、データ量を見積もって計算することができます
まずredisの記憶原理を見てみると、redisの記憶時にkvは文字列や文字配列に処理され、redisはappend、rehashなどの操作を容易に行うsdsタイプを実現している.
sds.h
には、typedef char *sds;
という定義が見られる.このように普通の文字列と変わらないように見えますが、実際にsdsにはheaderの概念があり、同じsdsにあります.h奥/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};
この注記はsdshdr 5では使用しませんが、sizeが2^5-1未満の文字列ではSDS_が使用されます.TYPE_5.
各ヘッダの定義に最後にchar buf[]があります.これはフレキシブル配列(flexible array member)であり、flagsフィールドの後ろに文字配列があり、メモリ領域を占有しないことを示すタグとして機能します.
ここを見てSDS_TYPE 5のヘッダは1バイトしか占めていませんが、SDS_TYPE_8は3バイト
sds上にrobjもカプセル化されており、以下のように定義されている.
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
int refcount;
void *ptr;
} robj;
読み取りを迅速に格納するために、すべてのkvはdict構造に保存され、各dictEntryはこのような形式である.
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
keyは「aaa」のsdsポインタであり、vは「bbb」を含むrobjを指すポインタ、すなわちdictEntryが24バイトを占め、1つのkeyがsdsがsdshader+自体のコンテンツ+エンドマーク(1)を占め、1つのvがrobjがsdsとrobjの空間を占め、約12バイトである.
たとえば、ユーザーログインのtokenを格納するテーブルがあります.
どのくらいのスペースを占有しますか?ユーザID 19ビット、token 50ビットを仮定すると、keyはSDS_TYPE_5,1+19+1=21バイト、valueはSDS_TYPE_8になり、robj、すなわち3+12+50+1=66に包装され、dictEntry 24バイト
合計111バイトということで、1つのレコードが占めるスペースをおおよそ算出し、データ量を見積もって計算することができます