[Redis研究ノート(4)]圧縮リスト、オブジェクトシステムの詳細な説明

この記事は公式アカウント[DevelopingPigeon]から公開されています!フォローへようこそ!


古いルール-姉妹都市都市:

1。圧縮リスト

(I.概要

        圧縮リストは、リストキーとハッシュキーの基本的な実装の1つです。いわゆるリストキーは、キーの値のリストを指します。同様に、ハッシュキーは、キーの値がハッシュであることを示します。 。リストキーに含まれるリストアイテムの数が少なく、各リストアイテムが小さい整数値または短い文字列の場合、圧縮リストがリストキーの実装として使用されます。

(2)圧縮リストの構成

        圧縮リストは、メモリを節約するためにRedisによって開発されたもので、特別にコード化された一連の連続メモリブロックで構成されるシーケンシャル構造です。圧縮リストには複数のノードを含めることができ、各ノードにはバイト配列または整数値を格納できます。圧縮リストには、リストが占有するメモリのバイト数、レコードの終了ノードの位置、含まれるノードの数、各ノードの内容、およびリストの終了を示すバイトが含まれます。

(3)圧縮リストノードの構成

        各圧縮リストノードはバイト配列または整数値を格納し、各ノードは前のノードの長さ、ノードのコード、およびノー​​ドのコンテンツで構成されます。

1.前のノードの長さ

        バイト単位で、圧縮リスト内の前のノードの長さが記録されます。前のノードの長さが254バイト未満の場合は、1バイトのレコード長が使用されます。それ以外の場合は、最初の5バイトのレコード長が使用されます。 wordセクションは0xFEに設定され、次の4バイトが実際の長さを記録します。この長さに基づいて前のノードの開始位置を計算でき、テーブルの終わりからテーブルの先頭までトラバースできます。

2.エンコーディング

        ノードのコンテンツ属性に格納されているデータのタイプと長さが記録されます。00、01、または10で始まるものはバイト配列コードであり、バイト配列がコンテンツに格納されていることを示します。11で始まるものは整数コードです。

3.コンテンツ

        ノードのcontent属性は、ノードの値を格納する役割を果たし、ノード値はバイト配列または整数にすることができます。


二。オブジェクト

(I.概要

        以前、Redisに多くのデータ構造を導入しました。Redisはこれらのデータ構造を直接使用してキーと値のペアのデータベースを実装するのではなく、これらの構造に基づいてオブジェクトシステムを実装します。このシステムには、文字列オブジェクト、リストオブジェクト、オブジェクトには、コレクションオブジェクトと順序付きコレクションオブジェクトの5種類があります。各オブジェクトには少なくとも1つの基礎となる実装があり、さまざまな使用シナリオのオブジェクトにさまざまな実装を設定できます。

        オブジェクトシステムは、カウントに基づくメモリリサイクルメカニズムも実装しています。プログラムがオブジェクトを使用しなくなると、オブジェクトが占有していたメモリが自動的に解放されます。また、参照カウントによるオブジェクト共有メカニズムを実装してメモリを節約し、アクセス時間レコード情報を持つオブジェクトを使用してデータベースキーのアイドリング期間を計算し、これらのキーを最初に削除します。

(2)オブジェクトのタイプとコード

        Redisはオブジェクトを使用してデータベース内のキーと値を表します。キーと値のペアが作成されるたびに、少なくとも2つのオブジェクトが作成されます。1つはキーオブジェクト、もう1つは値オブジェクトであり、キーオブジェクトは常に文字列オブジェクトであり、値オブジェクトは次のとおりです。5種類のオブジェクトのいずれかになります。Redisの各オブジェクトは、redisObject構造によって表されます。この構造には、オブジェクトタイプ属性、オブジェクトエンコーディング属性、および基になるデータ構造へのポインタの3つの属性が格納されます。

1.オブジェクトタイプの属性

        ただし、データベースキーを文字列キーと呼ぶ場合、このキーに対応する値が文字列オブジェクトであることを意味します。TYPEコマンドについても同様です。データベースキーに対してTYPEコマンドを実行すると、そのキーに対応する値オブジェクト型が返されます。

2.コーディングと低レベルの実装

        オブジェクトptrポインターは、オブジェクトの基礎となる実装データ構造を指します。これらのデータ構造は、encoding属性、つまり、オブジェクトの実装に使用されるデータ構造によって指定されます。

エンコーディングには次のタイプがあります。

REDIS_ENCODING_INT: long类型的整数
REDIS_ENCODING_EMBSTR: embstr编码的简单动态字符串
REDIS_ENCODING_RAW: 简单动态字符串
REDIS_ENCODING_HT: 字典
REDIS_ENCODING_LINKEDLIST: 双端链表
REDIS_ENCODING_ZIPLIST: 压缩链表
REDIS_ENCODING_INTSET: 整数集合
REDIS_ENCODING_SKIPLIST: 跳跃表和字典

        オブジェクトのタイプごとに、少なくとも2つの異なるエンコーディングが使用されます。

字符串对象(STRING):INT, EMBSTR, RAW
列表(LIST):压缩列表,双端链表
哈希表(HASH):压缩列表,字典
集合(SET):整数集合,字典
有序集合(ZSET):压缩列表,跳跃表和字典

        OBJECT ENCODINGコマンドを使用して、データベースキーの値オブジェクトのエンコーディングを表示します。

(3)文字列オブジェクト

        文字列オブジェクトに対応するコードはINT、EMBSTR、RAWであり、longlong型で表される浮動小数点数も文字列オブジェクトとして格納されます。

1.INT

        文字列オブジェクトが整数値を格納し、この整数値をlong型で表すこともできる場合、整数値は文字列オブジェクト構造のptr属性に格納され、コードはINTに設定されます。

2. EMBSTR

        保存されるのは文字列値で、長さが39バイト以下の場合、embstrエンコーディングが使用されます。このエンコーディングは短い文字列の保存専用です。RAWと同様に、redisObject構造とsdshdr構造の両方を使用して文字列オブジェクトを表しますが、rawエンコーディングはメモリ割り当て関数を2回呼び出して2つの構造を作成し、embstrは1回呼び出して連続部分を割り当てます。メモリ。スペース。このように、スペースを解放するために必要な操作は1つだけであり、連続したメモリが使用されるため、キャッシュをより有効に活用できます。

3.RAW

        文字列値を保存し、長さが39バイトを超える場合は、SDSを使用して文字列値を保存し、エンコーディングをRAWに設定します。


4.エンコーディング変換

        以下に示すように、intとembstrの両方がrawエンコーディングに変換されます。

        intエンコーディングの場合、保存されたオブジェクトが整数値ではなく文字列値の場合、エンコーディングはrawに変換されます
        。embstrエンコーディングの場合、Redisは変更プログラムを書き込まないため、embstrを変更すると読み取り専用になります。文字列オブジェクトをエンコードする場合、エンコードは最初にrawに変換され、次に変更が実行されます。

5.文字列コマンド

set: 保存键对应的值
get:返回键对应的值
append: 追加字符串到末尾
incrbyfloat: 对浮点数进行加法运算
incrby: 对整数进行加法运算
decrby: 对整数进行减法运算
strlen: 计算字符串的长度

(4)リストオブジェクト

        リストオブジェクトのエンコーディングは、ziplistとlinkedlistにすることができます。

1.ジップリスト

        圧縮リストは基礎となる実装として使用され、各圧縮リストノードはリスト要素を格納します。


2.リンクリスト

        基になる実装として両端リンクリストを使用すると、各ノードは文字列オブジェクトを格納し、各文字列オブジェクトはリスト要素を格納します。

3.コード変換

        リストオブジェクトが次の2つの条件を同時に満たす場合は、ziplistエンコーディングを使用します。

        (1)リストオブジェクトに格納されているすべての文字列要素の長さが64バイト未満です。

        (2)リストオブジェクトに格納されている要素の数が512未満です。

        条件を満たせないリンクリストエンコーディングを使用してください。つまり、文字列要素の長さが64バイト以上であるか、数値が512以上です。1つの条件が満たされない限り、オブジェクトのエンコード変換操作が実行され、元々圧縮リストに格納されていたすべてのリスト要素が転送されて両端リンクリストに保存され、エンコードもリンクリストになります。 。ziplistは短い文字列に適しており、要素の数が少ないのに対し、linkedlistは長い文字列に適しており、要素の数が多いことがわかります。


4.リストコマンド

        リストコマンドはすべてLで始まります。

LPUSH: 将新元素加入表头;
RPUSH: 将新元素加入表尾;
LPOP: 定位表头节点,删除表头节点;
RPOP: 定位表尾节点,删除表尾节点;
LINDEX: 定位指定节点,返回节点保存的值;
LLEN: 返回列表的长度;
LINSERT: 插入元素;
LREM: 遍历删除给定元素节点;
LTRIM: 删除所有不在给定索引范围内的节点;
LSET: 替换指定索引的节点

(5)ハッシュオブジェクト

        ハッシュオブジェクトのエンコーディングは、ziplistまたはhashtableにすることができます。

1.ジップリスト

        基盤となる実装として圧縮リストを使用します。ハッシュオブジェクトに追加する新しいキーと値のペアがある場合は常に、最初にキーを保存する圧縮リストノードを圧縮リストノードにプッシュし、次に保存する圧縮リストノードをプッシュします。圧縮への値リストの最後では、キーと値のペアは常に相互に接続されています。

2.ハッシュテーブル

        基盤となる実装として辞書を使用すると、Haxinオブジェクトのキーと値のペアは、辞書のキーと値のペアを使用して格納されます。辞書の各キーは文字列オブジェクトであり、各値も文字列オブジェクトです。

3.コード変換

        ハッシュオブジェクトが次の2つの条件を同時に満たす場合は、ziplistエンコーディングを使用します。

        (1)すべてのキーと値の文字列の長さが64バイト未満です;
        (2)キーと値のペアの数が512未満です

        ハッシュテーブルエンコーディングの使用が不十分です。ziplistは短い文字列に適しており、要素の数が少ないのに対し、hashtableは長い文字列に適しており、要素の数が多いことがわかります。


4.ハッシュコマンド

        ハッシュコマンドはすべてHで始まります。

HSET: 保存键值对;
HGET: 查找指定键的值;
HEXISTS: 查找指定键对应的节点;
HDEL: 删除指定键的键值对;
HLEN: 返回所有键值对数量;
HGETALL: 遍历返回所有键值对;

(6)コレクションオブジェクト

        コレクションオブジェクトのエンコーディングでは、intsetまたはhashtableを使用できます。

1.intset

        基になる実装として整数コレクションを使用すると、コレクションオブジェクトに含まれるすべての要素が整数コレクションに格納されます。


2.ハッシュテーブル

        基礎となる実装としてディクショナリを使用すると、ディクショナリの各キーは文字列オブジェクトであり、各文字列オブジェクトにはコレクション要素が含まれ、ディクショナリの値はNULLに設定されます。


3.エンコーディング変換

        コレクションオブジェクトが同時に次の条件を満たすことができる場合は、intsetエンコーディングを使用します。

        (1)コレクションオブジェクトによって保存されるすべての要素は整数値です。

        (2)コレクションオブジェクトに格納されている要素の数が512を超えていない。

        これら2つの条件を満たすことができないコレクションオブジェクトは、ハッシュテーブルエンコーディングを使用します。整数を格納するためにintsetエンコーディングが使用され、少数の要素にintsetエンコーディングが使用されることがわかります。ハッシュテーブルは、多数の文字列が格納される状況に対応します。


4.4。コマンドの設定

        集合コマンドはすべてSで始まります。

SADD: 将所有新元素添加到整数集合中;
SCARD: 返回整数集合包含的元素数量;
SISMEMBER: 查找给定的元素;
SMEMBERS: 遍历整数集合,返回所有的集合元素;
SRANDMEMBERS: 随机返回一个元素;
SPOP: 随机取出元素,并删除该元素;
SREM: 删除所有指定元素;

(7)オブジェクトの順序付けられたコレクション

        順序セットのエンコーディングは、ziplistまたはskiplistにすることができます。

1.ジップリスト

        圧縮リストは基礎となる実装として使用され、各セット要素は隣接する2つの圧縮リストノードによって保存されます。最初のノードは要素のメンバーを保存し、2番目のノードは要素のスコアを保存します。コレクション要素は、スコアのサイズに従って小さいものから大きいものへと並べ替えられます。


2番目の船のリスト

        基礎となる実装としてzset構造を使用します。zset構造には、ディクショナリとジャンプテーブルが同時に含まれます。ジャンプテーブルは、スコア値に応じて小さいものから大きいものまですべてのコレクション要素を保存します。各ジャンプテーブルノードはコレクション要素を保存します。ジャンプテーブルノードのオブジェクト属性は要素のメンバーを保存し、スコア属性はスコア値を保存します。ジャンプテーブルを介して、範囲操作を順序付きセットで実行できます。辞書は、メンバーから順序付きセットのスコアへのマッピングを作成します。辞書内の各キーと値のペアは、メンバーからスコアへのマッピングを格納します。辞書では、O(1)Complexityを使用して、特定のメンバーのスコアを見つけることができます。

        順序集合の各要素のメンバーは文字列オブジェクトであり、スコアは倍精度浮動小数点数です。ジャンプテーブルと辞書の両方にセット要素が格納されますが、同じ要素のメンバーとポイントはポインタ。値。なぜ2つの構造を使用して同時に保存するのですか?利点を維持するために、ジャンプテーブルの利点は、範囲操作を実行して非常に遠いノードにジャンプできることですが、メンバーに基づいてスコアを見つけることはO(1)の複雑さではありません。辞書の利点はクエリスコアは高速ですが、コレクション要素が故障しています。


3.エンコーディング変換

        順序付けされたコレクションオブジェクトが次の2つの条件を満たす場合は、ziplistエンコーディングを使用します。

        (1)要素の数が128未満である。

        (2)すべての要素メンバーの長さが64バイト未満です。

        上記の2つの条件を満たすことができない順序付けされたコレクションオブジェクトは、スキップリストエンコーディングを使用します。


4.注文された収集コマンド

        順序付けられた収集コマンドはすべてZで始まります。

ZADD: 插入成员和分值;
ZCARD: 获取集合长度;
ZCOUNT: 统计分值在给定范围内的节点数量;
ZRANGE: 从表头向表尾遍历,返回给定索引范围内的所有元素;
ZREVRANGE: 从表尾向表头遍历,返回给定索引范围内的所有元素;
ZRANK: 从表头向表尾遍历,返回某个成员的排名,以0开头的;
ZREVRANK: 从表尾向表头遍历,返回某个成员的排名;
ZREM: 遍历删除给定元素;
ZSCORE: 遍历查找给定元素;

(8)型チェックとコマンドポリモーフィズム

        Redisがキーを操作するために使用するコマンドは2つのタイプに分けることができます.1つのタイプはDEL、EXPIRE、RENAME、TYPE、OBJECTコマンドなどの任意のタイプのキーで実行でき、もう1つは特定のタイプのキーでのみ実行できます、5種類など。キーコマンドの種類。タイプ固有のコマンドを実行する前に、Redisは最初に入力キーのタイプが正しいかどうかを確認し、次に指定されたコマンドを実行するかどうかを決定します。型チェックは、redisObject構造体のtype属性を介して行われます。

        Redisは、値オブジェクトのタイプに応じてキーが指定されたコマンドを実行できるかどうかを判断するだけでなく、値オブジェクトのエンコード方法に従ってコマンドを実行するための正しいコマンド実装コードも選択します。コーディングの実装が異なれば、APIインターフェースも異なります。

(9)メモリの回復

        Redisは、オブジェクトシステムでの参照カウントによって実装されるメモリ回復メカニズムを構築します。このメカニズムにより、プログラムは、redisObjectのrefcount属性によって記録されるオブジェクトの参照カウント情報を追跡することにより、ペアを自動的に解放し、メモリをリサイクルできます。構造、参照カウント時0になると自動的に解放されます。


(10)オブジェクト共有

        オブジェクト参照カウントには、オブジェクト共有の効果もあります。Redisでは、複数のキーに同じ値オブジェクトを共有させるには、次の手順があります。

        1.データベースキーの値ポインタを既存の値オブジェクトにポイントします。

        2.共有される値オブジェクトの参照カウント+1

        現在、Redisはサーバーの初期化時に0から9999までのすべての整数値を含む10,000個の文字列オブジェクトを作成し、必要に応じてこれらの共有オブジェクトを直接使用します。この結論を検証する方法は?値2のキーAを作成し、OBJECT REFCOUNTを介してその参照カウントを確認すると、2であることがわかります。これは、1つがこの値オブジェクトを保持するサーバープログラムであり、もう1つがキーAであることを示しています。この値オブジェクトを共有します。

        現在、Redisは整数値の文字列オブジェクトの共有のみをサポートしています。これは、共有オブジェクトとターゲットオブジェクトが完全に同じである場合にのみ、共有オブジェクトがKey Valueオブジェクトとして使用されるためです。これには検証操作が必要であり、CPU時間が消費されます。したがって、より複雑なオブジェクトはより多くのCPU時間を消費します。


(11)オブジェクトのアイドリング時間

        また、redisObject構造には属性lruがあり、コマンドプログラムによってオブジェクトが最後にアクセスされた時刻が記録されます。objectidletimeコマンドを使用して、特定のキーのアイドル時間を出力し、からlru時間を差し引いて計算します。現在の時刻。もちろん、メモリが十分でない場合は、この属性を使用して、アイドル時間が最も長いキーを削除することもできます。

おすすめ

転載: blog.csdn.net/Mrwxxxx/article/details/114004723