記事ディレクトリ
1.重要なデータ構造
続い内層の外側からストレージ構造の多くの重要なRedisのデータ構造は、ありますredisDb
、dict
、dictht
、dictEntry
デフォルトでは16個のredisDbがあります。各redisDbにはdictデータ構造が含まれています。dictにはdictht配列が含まれています。配列の数は2で、主にハッシュ展開に使用されます。dicthtには、内部dictEntryの配列が含まれています。競合チェーンアドレスの法則を解決する場合、dictEntryは実際にはキー値ノードハッシュテーブルです。
1.1 redisServer
データ構造redisServer
は、で定義されserver.h
ているように、redisサーバーの抽象化です。redisServer
には多くの属性があります。以下は抜粋の一部であり、簡単な紹介です
hz
:タイミングタスクのトリガー頻度を再調整する*db
:redisDb配列、デフォルトは16 redisDb*commands
:redisでサポートされているコマンドの辞書*el
:Redisイベントループの例runid[CONFIG_RUN_ID_SIZE+1]
:現在のredisインスタンスのRunid
struct redisServer {
/* General */
pid_t pid; /* Main process pid. */
......
int hz; /* serverCron() calls frequency in hertz */
redisDb *db;
dict *commands; /* Command table */
dict *orig_commands; /* Command table before command renaming. */
aeEventLoop *el;
......
char runid[CONFIG_RUN_ID_SIZE+1]; /* ID always different at every exec. */
......
list *clients; /* List of active clients */
list *clients_to_close; /* Clients to close asynchronously */
list *clients_pending_write; /* There is to write or install handler. */
list *clients_pending_read; /* Client has pending read socket buffers. */
list *slaves, *monitors; /* List of slaves and MONITORs */
client *current_client; /* Current client executing the command. */
......
};
1.2 redisDb
redisDb
抽象redisデータベース定義server.h
、より重要なプロパティは次のとおりです
*dict
:データを保存するための辞書*expires
:有効期限付きのキーを保存します
typedef struct redisDb {
dict *dict; /* The keyspace for this DB */
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
unsigned long expires_cursor; /* Cursor of the active expire cycle. */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;
1.3ディクト
dict
Redisは辞書にあり、dict.h
ファイルの定義は次のとおりです。主な属性は次のとおりです。
ht[2]
:ハッシュテーブル配列。拡張の便宜のために、2つの要素があり、一方のハッシュテーブルは通常データを格納し、もう一方のハッシュテーブルは空であり、空のハッシュテーブルは再ハッシュ時に使用されます。rehashidx
:rehashインデックス、再ハッシュが進行中でない場合、値は-1です。
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
unsigned long iterators; /* number of iterators currently running */
} dict;
1.4ディクト
dictht
ハッシュテーブル構造はdict.h
ファイルで定義されています。次の重要なプロパティ
**table
:キー値キー値ペアノード配列、JavaのHashMapの基になる配列と同様size
:ハッシュテーブルの容量サイズsizemask
:常にサイズ1に等しく、インデックス値の計算に使用されますused
:ハッシュテーブルに実際に格納されているdictEntryの数
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
1.5 dictEntry
dictEntry
キーredisノードのキーと値のペアであり、ノードデータは実際にdict.h
ファイルに保存され、次の重要なプロパティがファイルに定義されます。
*key
:キーオブジェクト、常に文字列タイプのオブジェクト*val
:値オブジェクト。どのタイプのオブジェクトでもかまいません。*next
:テールポインタ、次のノードを指す
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
2.データタイプ
2.1Redisデータオブジェクトの構造
Redisデータベースのすべてのデータはキー値ノードとして保存dictEntryキーと値はredisObject
構造オブジェクトですが、常にキー文字列タイプのオブジェクトである場合、オブジェクト値は任意のタイプのデータにすることができます。以下に示すredisObject
構造で定義されていserver.h
ます
構造内の重要な属性は次のとおりです。異なるオブジェクトには異なるタイプがあり、同じタイプのタイプには異なるストレージフォームエンコーディングがあります
type
:この属性は、文字列、リストなどのデータオブジェクトのタイプを示します。encoding
:この属性は、オブジェクトの基礎となるストレージ構造を示します。たとえば、ZSetタイプのオブジェクトの可能なストレージ構造はZIPLISTとSKIPLISTです。*ptr
:基盤となるストレージ構造へのポインタ
typedef struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount;
void *ptr;
} robj;
2.2Redisのデータタイプとストレージ構造
データタイプとそのストレージ構成に関連して上に示したRedis、server.h
ファイル内のFIGマクロ
/* The actual Redis Object */
#define OBJ_STRING 0 /* String object. */
#define OBJ_LIST 1 /* List object. */
#define OBJ_SET 2 /* Set object. */
#define OBJ_ZSET 3 /* Sorted set object. */
#define OBJ_HASH 4 /* Hash object. */
/* The "module" object type is a special one that signals that the object
* is one directly managed by a Redis module. In this case the value points
* to a moduleValue struct, which contains the object value (which is only
* handled by the module itself) and the RedisModuleType struct which lists
* function pointers in order to serialize, deserialize, AOF-rewrite and
* free the object.
*
* Inside the RDB file, module types are encoded as OBJ_MODULE followed
* by a 64 bit module type ID, which has a 54 bits module-specific signature
* in order to dispatch the loading to the right module, plus a 10 bits
* encoding version. */
#define OBJ_MODULE 5 /* Module object. */
#define OBJ_STREAM 6 /* Stream object. */
/* Objects encoding. Some kind of objects like Strings and Hashes can be
* internally represented in multiple ways. The 'encoding' field of the object
* is set to one of this fields for this object. */
#define OBJ_ENCODING_RAW 0 /* Raw representation */
#define OBJ_ENCODING_INT 1 /* Encoded as integer */
#define OBJ_ENCODING_HT 2 /* Encoded as hash table */
#define OBJ_ENCODING_ZIPMAP 3 /* Encoded as zipmap */
#define OBJ_ENCODING_LINKEDLIST 4 /* No longer used: old list encoding. */
#define OBJ_ENCODING_ZIPLIST 5 /* Encoded as ziplist */
#define OBJ_ENCODING_INTSET 6 /* Encoded as intset */
#define OBJ_ENCODING_SKIPLIST 7 /* Encoded as skiplist */
#define OBJ_ENCODING_EMBSTR 8 /* Embedded sds string encoding */
#define OBJ_ENCODING_QUICKLIST 9 /* Encoded as linked list of ziplists */
#define OBJ_ENCODING_STREAM 10 /* Encoded as a radix tree of listpacks */
2.2.1文字列オブジェクト文字列
OBJ_STRING
文字列オブジェクトの基礎となるデータ構造は、一般的にシンプルダイナミックストリング(SDS)、ただし、その保存方法は次のようOBJ_ENCODING_INT
にOBJ_ENCODING_EMBSTR
なります。またOBJ_ENCODING_RAW
、異なる保存方法は、異なるオブジェクトメモリ構造を表します。
OBJ_ENCODING_INT
保存された文字列の場合長さは20未満で、整数として解析できます、次に、この整数はredisObject
のptr
プロパティに直接保存されますOBJ_ENCODING_EMBSTR
44未満の文字列(OBJ_ENCODING_EMBSTR_SIZE_LIMIT)はシンプルダイナミックストリング(SDS) ストレージの形式ですが、mallocメソッドを使用してメモリを1回割り当て、redisObjectオブジェクトヘッダーとSDSオブジェクトは引き続き共存しますOBJ_ENCODING_RAW
文字列はで始まりますシンプルダイナミックストリング(SDS) ストレージの形式では、メモリを割り当てるために2つのmallocが必要です。redisObjectオブジェクトヘッダーとSDSオブジェクトは、通常、メモリアドレスで不連続です。
- Redisでは、長い浮動小数点数と二重浮動小数点数が文字列オブジェクトにカプセル化されてから保存されます
OBJ_ENCODING_RAW
OBJ_ENCODING_EMBSTR
違いは、生のメモリの割り当てと解放は、より良いのキャッシュの利点を活用するために、連続したメモリブロックembstr加えているので、embstr一度だけ、2つの操作を必要とすることですOBJ_ENCODING_EMBSTR
エンコードされたオブジェクトは読み取り専用であり、変更されると、にトランスコードされますOBJ_ENCODING_RAW
2.2.2リストオブジェクトリスト
OBJ_LIST
リストオブジェクトの基盤となるストレージ構造の3つの実装が行われている、すなわちOBJ_ENCODING_LINKEDLIST
、OBJ_ENCODING_ZIPLIST
およびOBJ_ENCODING_QUICKLIST
、その中で、OBJ_ENCODING_LINKEDLISTはバージョン3.2以降で廃止されました
OBJ_ENCODING_LINKEDLIST
最下層は両端リンクリストによって実装され、各リンクリストノードは文字列オブジェクトを格納し、要素は各文字列オブジェクトに格納されますOBJ_ENCODING_ZIPLIST
基礎となる実装は配列に似ており、特性属性を使用して、リスト全体が占めるメモリサイズ、リストに保存されたデータの開始位置、リストに保存されたデータの数など、リスト全体のメタ情報を格納します。保存されたデータはにカプセル化されます。zlentry
ziplistを使用するには、2つの条件を満たす必要があります
- リストオブジェクトによって保存されるすべての文字列要素の長さが64バイト未満です
- リストオブジェクトに格納されている要素の数が512未満です
OBJ_ENCODING_QUICKLIST
最下層は両端のリンクリスト構造を使用しますが、各リンクリストノードはzipリストを保存し、データはzipリストに保存されます
2.2.3セット
OBJ_SET
そこコレクション・オブジェクトのための基盤となるストレージ構造の2種類があり、OBJ_ENCODING_HT
かつOBJ_ENCODING_INTSET
OBJ_ENCODING_INTSET
コレクションに格納されているすべての要素は整数値です。このストレージ構造が使用されますが、コレクションオブジェクトに格納されている要素の数がを超える場合512(server.set_max_intset_entriesによって構成されます)OBJ_ENCODING_HTに変換されますOBJ_ENCODING_HT
dict
Java HashSetの辞書の下部、キー値に対応する保存キーとしての辞書データがNULLなど。
2.2.4 ZSet
OBJ_ZSET
順序付けられたオブジェクトのセットへのストレージ構造OBJ_ENCODING_SKIPLIST
とOBJ_ENCODING_ZIPLIST
OBJ_ENCODING_ZIPLIST
zsetの基礎となるストレージ構造としてziplistを使用する場合、各セット要素は、隣接する2つの圧縮リストノードを使用して保存されます。最初のノードは要素値を保存し、2番目の要素は要素のスコアを保存します。スコアは小さいです。テーブルの頭の近く、テーブルの端の近くに大きい
- 順序付けられたコレクションオブジェクトは、ziplistを使用して保存する必要があります次の2つの条件を同時に満たし、いずれの条件も満たさない場合はスキップリストを使用します
- すべての要素の長さが64バイト未満です(server.zset_max_ziplist_value構成)
- 要素の数が128未満です(server.zset-max-ziplist-entries構成)
OBJ_ENCODING_SKIPLIST
基礎となる実装は、辞書と組み合わせたジャンプテーブルです。各ジャンプテーブルノードは、スコアの降順で配置されたコレクション要素を保存します。ノードのオブジェクト属性は要素の値を保存し、スコア属性はスコアを保存します。辞書の各キーと値のペアは、コレクション要素、要素値を保存します。辞書キーとしてパックされ、要素スコアは辞書値として保存されます
skiplist 同时使用跳跃表和字典实现的原因
- スキップテーブルの利点は順序ですが、クエリスコアの複雑さはO(logn)です。辞書クエリスコアの複雑さはO(1)ですが、2つを組み合わせると、補完的な利点が得られます。
- セットの要素メンバーとスコアは共有され、ジャンプテーブルと辞書はポインターを介して同じアドレスを指すため、メモリが無駄になりません
2.2.5ハッシュオブジェクト
OBJ_HASH
構造は、ストレージに分かれているOBJ_ENCODING_ZIPLIST
とOBJ_ENCODING_HT
され、以下を実現します:
OBJ_ENCODING_ZIPLIST
データをziplist構造で格納するハッシュオブジェクトでは、キーと値のキーと値のペアは、密接に接続された方法で圧縮リンクリストに格納されます。キーは最初にテーブルの最後に配置され、次に値が配置されます。キーと値のペアは常にテーブルの最後に追加されます。
- ハッシュオブジェクトは、データを格納するためにziplistを使用する必要があります次の2つの条件を同時に満たす、いずれも満たさない、dict構造を使用する
- すべてのキーと値のペアのキーと値の文字列の長さが64(server.hash_max_ziplist_value構成)バイト未満です。
- キーと値のペアの数が512未満です(server.hash-max-ziplist-entries)
OBJ_ENCODING_HT
dict
ディクショナリの下部では、各オブジェクトはキーとキーの値のペアをハッシュし、ディクショナリdictEntry
を使用して格納します。ディクショナリのキーと値は文字列オブジェクトです。
2.2.6ストリームオブジェクトストリーム
OBJ_ENCODING_STREAM
ストリームオブジェクトは、バージョン5.0で導入された新しいデータオブジェクトです。リストオブジェクトのリストと非常によく似ていますが、サブスクライブおよび公開する機能を備えた、より強力な機能を備えています。ストレージ構造OBJ_ENCODING_STREAM
他のストレージ構造との使用が異なる
OBJ_ENCODING_STREAM
文字列要素を格納するための圧縮プレフィックスツリー(基数ツリー)の使用の基礎となる、ソースファイルのrax.h
コメントからわかるように、基数ツリーは実際には辞書ツリー(Trieツリー)の圧縮最適化バージョンです。子ノードが1つしかない複数の連続するノードによって保存された文字を1つのノードに圧縮します
- Trie Treeの原理は、
各文字列要素キーを1つの文字に従って分割し、各ブランチに対応します。このようにして、ブランチのルートノードからリーフノードにトラバースされ、渡されたすべてのノードによって保存された文字の文字列が、このブランチに対応する要素キーになります。
Trie tree :
* (f) ""
* \
* (o) "f"
* \
* (o) "fo"
* \
* [t b] "foo"
* / \
* "foot" (e) (a) "foob"
* / \
* "foote" (r) (r) "fooba"
* / \
* "footer" [] [] "foobar"
Radix tree:
["foo"] ""
* |
* [t b] "foo"
* / \
* "foot" ("er") ("ar") "foob"
* / \
* "footer" [] [] "foobar"