今日共有された質問は、Weilai の実際のインタビューの質問から来ています。
Java の面接で Redis について聞かないことは不可能 Redis について聞かれたときに Redis の一般的なデータ型を聞かないことは不可能 Redis の一般的なデータ型について聞かれたときにジャンプ テーブルについて聞かないことは不可能 そして処理を追加するため、この質問に対する答えを一緒に見てみましょう。
Redis の順序付きコレクション ZSet は、ziplist (圧縮リスト) または Skiplist (スキップ リスト) で構成されます。
- 圧縮リスト ziplist は本質的にバイト配列です。メモリを節約するために Redis によって設計された線形データ構造です。複数の要素を含めることができ、各要素はバイト配列または整数にすることができます。
- スキップ リスト Skiplist は順序付けされたデータ構造であり、各ノード内で他のノードへの複数のポインタを維持することでノードに迅速にアクセスするという目的を達成します。ジャンプ テーブルは、平均 O(logN) および最悪 O(N) の複雑さによるノード ルックアップをサポートし、順次操作を通じてノードをバッチで処理することもできます。
ジャンプテーブルの紹介
スキップ リスト ジャンプ テーブルとも呼ばれるスキップ リストは、順序付けされた要素のコレクションで効率的な検索操作を行うためのデータ構造です。多層リンク リストを追加することで、空間を時間と交換して検索を高速化する方法を提供します。
スキップ リストは、複数のレベルのノードを含むリンク リストで構成され、各レベルは元のリンク リストのサブセットになります。最下層は、すべての要素を含む完全な順序付きリンク リストです。いくつかの要素をスキップするための追加のポインターを追加することにより、上位レベルのそれぞれが下位レベルのサブセットになります。これらの追加のポインターは「ジャンプ ポインター」と呼ばれ、他のノードへの高速アクセスが可能になり、検索に必要な比較の数が減ります。
スキップ テーブルの平均ルックアップ時間の複雑さは O(log n) です (n は要素の数です)。これにより、通常のソートされたリンク リストよりも高速な検索パフォーマンスが得られ、赤黒ツリーなどの平衡二分探索ツリーよりも実装が簡単になります。
簡単なジャンプ テーブルを以下に示します。
ジャンプテーブル追加処理
事前知識: ノードのランダムな層数
ジャンプ テーブルを追加するプロセスについて話し始める前に、まず、ノードのランダムなレイヤーの数という概念を理解する必要があります。 いわゆるレイヤの乱数とは、各ノードが追加される前に生成される現在のノードのランダムなレイヤの数を指し、生成された乱数に従って現在のノードのレイヤの数がリンク リストに格納されます。層の。
なぜこのように設計されているのでしょうか?
この設計の目的は、Redis の実行効率を確保することです。
固定ルールを定式化する代わりに、ランダムな数のレイヤーを生成する理由 たとえば、次の図に示すように、上位レイヤーのノードは、下位レイヤーの 2 つのノードにまたがるリンク リストで構成されます。
ルールが策定されている場合、次の図に示すように、新しいノードの追加など、追加または削除時にルールを満たすために追加の処理を実行する必要があります。
このようにすると、上位層のノードが 2 つの下位層ノードを横切るという確立されたルールが満たされなくなり、上位層のすべてのノードを追加で調整する必要が生じ、プログラムの効率が低下するため、乱数のレイヤーが使用され、ルールは適用されないため、サービスの実行時間が占有されないように追加の操作が必要です。
プロセスを追加
Redis にジャンプ テーブルを追加するプロセスを次の図に示します。
- 最初の要素は、一番下の順序のリンク リストに追加されます (一番下の層にはすべての要素データが保存されます)。
- 2 番目の要素によって生成されるランダムなレイヤーの数は 2 なので、レイヤーを 1 つ追加し、この要素を最初の最下位レイヤーに格納します。
- 3 番目の要素によって生成されるランダム レイヤーの数は 4 なので、さらに 2 レイヤーを追加し、ジャンプ テーブル全体が 4 レイヤーになり、この要素をすべてのレイヤーに保存します。
- 4番目の要素で生成されるランダムなレイヤー数は1なので、順番に最後のレイヤーに保存できます。
他の新しく追加されたノードは、類推して推測できます。
ランダムレイヤーのソースコード解析
ランダム レベルのソース コードは、次のように t_zset.c/zslRandomLevel(void) にあります。
int zslRandomLevel(void) {
int level = 1;
while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
level += 1;
return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}
ソースコードから、層の乱数がレベル 1 に割り当てられる確率が 50%、レベル 2 に割り当てられる確率が 25%、レベル 3 に割り当てられる確率が 12.5% であることがわかります。等々。
Redis スキップ テーブルで許可されるデフォルトの最大レベルは 32 で、ZSKIPLIST_MAXLEVEL ソース コードで定義されています。
まとめ
ジャンプ テーブルは、複数の順序付けされたリンク リストで構成されます。最下層にはすべての要素のデータが格納されます。このストレージによりクエリがより効率的になり、クエリの複雑さは O(n) から O(log n) に変化します。ジャンプ テーブルを追加するプロセスは、ノードによって生成された層の乱数に基づいており、それを最下位ノードと上位 N-1 層ノードに挿入します。追加プロセスを説明する鍵は、ランダムな数を理解することです。レイヤーとその背後にある原則。