記事ディレクトリ
前書き
-
以前のデータ構造に基づいてオブジェクトシステムを作成します。文字列オブジェクト、リストオブジェクト、ハッシュオブジェクト、コレクションオブジェクト、順序付けされたコレクションオブジェクトを含む
-
コマンドを実行する前に、オブジェクトタイプに基づいて、オブジェクトが特定のコマンドを実行できるかどうかを判断できます。
-
さまざまな使用シナリオに応じて、さまざまなシナリオでオブジェクトの使用効率を最適化するために、達成するオブジェクトにさまざまな異なるデータ構造を設定できます。
-
参照カウントに基づくメモリリサイクルメカニズムを実装し、メモリ共有メカニズムを実装し、複数のデータベースキーが同じオブジェクトを共有してメモリを節約できるようにします。
-
オブジェクトにはアクセス時間の記録情報があり、データベースキーのアイドル時間を記録します
オブジェクトタイプとエンコーディング
オブジェクトを使用して、データベースのキーと値を表します。新しいキーと値のペアが作成されると、キーと値をそれぞれ表すために2つのオブジェクトが作成されます
typedef struct redisObject
{
unsigned type:4;//类型
unsigned encoding:4;//编码
void * ptr;//指向底层实现数据结构的指针
}
の種類
type属性は、オブジェクトのタイプ、つまり5つのオブジェクトタイプの1つを記録します。
キーと値のペアの場合、キーは常に文字列オブジェクトであり、値は5つのオブジェクトタイプのいずれかになります。
コーディングと低レベルの実装
- オブジェクトのptrポインターは、オブジェクトの基礎となる実装データ構造を指し、これらのデータ構造は、オブジェクトのエンコード属性、つまり以前に学習されたいくつかのデータ構造によって決定されます
- オブジェクトのタイプごとに少なくとも2つの異なるエンコーディングが使用されます
- encoding属性を使用して、使用するエンコーディングを設定します。これにより、柔軟性と効率が大幅に向上します。特定のシーンでのオブジェクトの効率を最適化するために、さまざまな使用シナリオに応じてオブジェクトに異なるエンコーディングを設定できます
文字列オブジェクト
- 文字列オブジェクトのエンコーディングは、int、raw、embstrにすることができます
- 文字列オブジェクトが整数値を保持し、longで表すことができる場合、整数値はptrに格納され、encondingはintに設定されます
- 文字列値が保存され、長さが39バイトを超える場合、SDSで保存され、rawに設定されます。
- 文字列値が保存され、長さが39バイト未満の場合、embstrエンコーディングで保存され、embstrに設定されます
embstr
短い文字列を保存するために特別に使用される最適化されたエンコード方法
。SDSとはほとんど異なります。これは、連続するスペースを割り当てるためにメモリ割り当て関数を1回だけ呼び出す点です。次に、スペースにはredisObjectとsdshdrが含まれます。構造
上の2つの利点:メモリ割り当てと解放時間2回から1回に変更されました。文字列のすべてのデータは連続メモリに保存され、キャッシュをより効果的に使用します
エンコーディング変換
- 操作後、intエンコードされた文字列オブジェクトが整数値ではなく文字列値である場合、エンコーディングは未加工になります
- embstrによってエンコードされた文字列オブジェクトは読み取り専用です。その上で実行された変更コマンドはすべてrawとしてプログラムされます
リストオブジェクト
エンコーディングは、ziplist、linkedlistのいずれかです。Ziplistは圧縮リストを最下層の実装として使用し、linkedlistは両端リンクリストを最下層の実装として使用します。各両端リンクリストノードは文字列オブジェクトを保持します
文字列オブジェクトは、他の4つのオブジェクトによってネストされる5つのタイプのRedisオブジェクトの中で唯一のオブジェクトです
エンコーディング変換
ziplistエンコーディングを使用:
- リストオブジェクトによって保存されたすべての文字列要素が64バイト未満である
- リストに保存されている要素の数が512未満です
ハッシュオブジェクト
エンコーディングには、ziplist、hashtableを使用できます。
ziplistを使用して、キーと値のペアをリストの最後にプッシュします。キーと値のペアは隣り合っており、最初にキーがあり、後ろに値があります。同様のキュー
ハッシュテーブルエンコーディングは、最下層にディクショナリを使用して実装されています。ディクショナリの各キーと値は文字列オブジェクトです
エンコーディング変換
ziplistエンコーディングを使用:
- リストオブジェクトによって保存されたすべての文字列要素が64バイト未満である
- リストに保存されている要素の数が512未満です
コレクションオブジェクト
エンコーディングは、intset、hashtableにすることができます。
intsetでエンコードされたセットは、基本の実装として整数のセットを使用します
ハッシュテーブルによってエンコードされたコレクションは、基礎となる実装として辞書を使用し、各キーは文字列オブジェクトであり、値はNULLに設定されます
エンコーディング変換
intsetエンコーディングを使用:
- リストオブジェクトはすべて整数値です
- リストに保存されている要素の数が512未満です
オブジェクトの順序付けられたコレクション
順序付けられたセットのエンコーディングは、ziplistまたはskiplistにすることができます
ziplistエンコーディングでは、2つの圧縮されたリストノードを使用して、各セット要素が保存されます。最初のノードは要素のメンバーを保存し、2番目のノードは要素のスコアを保存します
スキップリストコーディングで実装
typedef struct zset
{
zskiplist *zsl;
dict * dict;
} zset;
zsetのzslジャンプテーブルは、すべてのセット要素を小から大まで保存します
各ジャンプテーブルノードでは、object属性は要素のメンバーを保持し、score属性は要素のスコアを保持します
さらに、dictでは、辞書のキーに要素のメンバーが格納され、値に要素のスコアが格納されます。このように、特定のメンバーのスコアは、O(1)複雑度の辞書を介して見つけることができます。
これらのデータ構造は両方とも、ポインタを介して同じ要素のメンバーとスコアを共有しているため、ジャンプテーブルと辞書を使用してコレクション要素を格納しても、メンバーやスコアが重複することはなく、追加のメモリを無駄にすることもありません
エンコーディング変換
ziplistエンコーディングを使用:
- 順序付きセットに格納されているすべての要素の長さが64バイト未満です
- 順序付きセットに格納されている要素の数が128未満です
型チェックとコマンドのポリモーフィズム
タイプの特定のコマンドを実行する前に、サーバーは入力データベースキーの値オブジェクトがコマンドの実行に必要な命令であるかどうかをチェックし、そうである場合、サーバーはキーで指定されたコマンドを実行します。それ以外の場合は、コマンドの実行を拒否し、タイプエラーをクライアントに返します。
型チェックは、redisObject構造体のtype属性を通じて実現されます
ポリモーフィックコマンドの実装
キーが値オブジェクトのタイプに従って指定された命令を実行できるかどうかを判断することに加えて、Redisは適切なコマンド実装コードを選択して、値オブジェクトのエンコード方法に従ってコマンドを実行します
たとえば、LLENコマンドはポリモーフィックです。LLENコマンドがリストキーによって実行される限り、値オブジェクトがziplistエンコーディングを使用しているか、linkedlistエンコーディングを使用しているかに関係なく、コマンドは正常に実行できます。
DELやTYPEなどのコマンドもポリモーフィックコマンドであり、これらのコマンドは、入力するキーのタイプに関係なく、通常どおり実行できます。違いは、DELやTYPEなどのコマンドはタイプのポリモーフィズムに基づいていることです。1つのコマンドは複数の異なるタイプのキーを処理できます。LLenコマンドはコーディングポリモーフィズムに基づいています。1つのコマンドを使用して、複数の異なるコードを同時に処理できます。
メモリの再利用
メモリ回復メカニズムを実現する参照カウント方法に基づいて、オブジェクトの参照カウント情報を追跡することにより、オブジェクトは自動的に解放され、適切なときにメモリが回復されます
- 参照カウントが1のオブジェクトを作成する
- オブジェクトは新しいプログラムによって使用され、参照カウント値は+1です
- オブジェクトはプログラムで使用されていません。参照カウント値は-1です
- 参照カウント値が0の場合、オブジェクトが占有していたメモリを解放します
オブジェクトの共有
一歩
複数のキーが同じ値オブジェクトのステップを共有できるようにします。
- データベースキーの値を既存の値オブジェクトにポイントする
- 共有する値オブジェクト参照カウント値+1
組み込み整数
Redisがサーバーを初期化すると、10,000の文字列オブジェクトが作成され、整数値[0,9999]が格納されます。これらの文字列オブジェクトが必要な場合、サーバーは新しいオブジェクトを作成する代わりにこれらの共有オブジェクトを使用します。
これらの共有オブジェクトは、文字列キーだけでなく、データ構造にネストされた文字列オブジェクトを持つオブジェクトにも使用できます。
文字列を含むオブジェクトを共有しないのはなぜですか
共有オブジェクトとターゲットオブジェクトがまったく同じ場合にのみ、プログラムは共有オブジェクトをキーの値オブジェクトとして使用します
共有オブジェクトによって格納される値が複雑になるほど、共有オブジェクトとターゲットオブジェクトが同じであることを確認するために必要な複雑さが高くなります。
- 共有オブジェクトは整数値の文字列オブジェクトであり、検証操作はO(1)O(1)です。O (1 )
- 共有オブジェクトは文字列値を格納する文字列オブジェクトであり、検証操作はO(N)O(N)です。O (N )
- 共有オブジェクトは、複数の値(リストなど)を含むオブジェクトであり、検証操作はO(N 2)O(N ^ 2)です。O (N2)
オブジェクトのアイドル時間
redisObject構造には属性lruが含まれています。この属性には、コマンドプログラムによってオブジェクトに最後にアクセスした時間が記録されます。アイドル時間は、現在の時間-キーの値オブジェクトのlru時間から取得できます。
、検証操作はO(1)O(1)O (1 )
2.共有オブジェクトは文字列値を格納する文字列オブジェクトであり、検証操作はO(N)O(N)です。O (N )
3.共有オブジェクトは複数の値(リストなど)を含むオブジェクトであり、検証操作はO(N 2)O(N ^ 2)です。O (N2)
オブジェクトのアイドル時間
redisObject構造には属性lruが含まれています。この属性には、コマンドプログラムによってオブジェクトに最後にアクセスした時間が記録されます。アイドル時間は、現在の時間-キーの値オブジェクトのlru時間から取得できます。
サーバーが占有するメモリー量がmaxmemoryの上限を超えると、アイドル時間が長いキーの部分が最初にサーバーによって解放され、それによってメモリーが解放されるように設定できます。