ホームページ  >  記事  >  データベース  >  Redis ナレッジ ポイントを分析する方法

Redis ナレッジ ポイントを分析する方法

WBOY
WBOY転載
2023-06-03 20:02:111008ブラウズ

これは型ではなくデータ構造です

多くの記事では、redis が一般的に使用される 5 つのデータ型をサポートしていると書かれていますが、これは実際には大きなあいまいさです。 Redis に格納されているすべてのバイナリ データは、実際にはバイト配列 (byte[]) です。これらのバイト データにはデータ型がありません。文字列、整数、またはオブジェクトに変換できるのは、適切な形式でデコードした後でのみです。データ型を持っています。

これは覚えておかなければなりません。したがって、バイト配列 (byte[]) に変換できるものはすべて Redis に保存できます。文字列、数値、オブジェクト、画像、音声、動画、ファイルなど、バイト配列に変換されていれば処理可能です。

つまり、redis の String は文字列を参照するのではなく、実際には最も単純なデータ構造を表しており、1 つのキーは 1 つの値にのみ対応します。ここでのキーと値は両方ともバイト配列ですが、通常、キーは文字列から変換されたバイト配列であり、値は実際のニーズに応じて決定されます。

特定の状況では、値にもいくつかの要件があります。たとえば、自動インクリメントまたは自己デクリメント操作を実行する場合、値に対応するバイト配列をデコードできる必要があります。数値に変換しないと、エラーが報告されます。

List のデータ構造は、実際には 1 つのキーに複数の値が対応し、値が順番に並び、値の値を繰り返すことができることを意味します。

Setは、1つのキーが複数の値に対応でき、値の間に順序がなく、値の繰り返しができないことを示すデータ構造です。

ハッシュは、1 つのキーが複数のキーと値のペアに対応できることを示すデータ構造です。現時点では、これらのキーと値のペア間の順序には一般にほとんど意味がありません。これは、名前のセマンティクスに従ってアクセスされます。位置セマンティクスではなくデータ構造。

Sorted Set は、キーが複数の値に対応できることを示すデータ構造で、値はサイズによってソートされ、値は重複できません。各値はスコアと呼ばれる浮動小数点数に関連付けられます。要素の並べ替え規則は次のとおりです。最初にスコアで並べ替え、次に値で並べ替えます。

これで、これら 5 つのデータ構造についてより明確に理解できたと思います。その後、それらに対応するコマンドは小さなケースになります。

クラスターによってもたらされる問題と解決策

クラスターによってもたらされる利点は、容量の増加、処理能力の向上、必要に応じた動的な拡張や縮小など、明らかです。しかし、それはまた、少なくとも次の 2 つの新たな問題も引き起こすでしょう。

データ割り当てには、保存中にデータが保存されるノードの決定と、取得中にデータがクエリされるノードの決定が含まれます。 2 つ目はデータの移動です。クラスターが拡大して新しいノードが追加されると、ノード上のデータはどこから来たのか、クラスターが縮小してノードが削除されると、ノード上のデータはどこに行くのかということです。

上記の 2 つの質問には 1 つの共通点があります。それは、データとノード間のマッピング関係をどのように記述して保存するかということです。データの場所はキーによって決定されるため、問題の発展は、各キーとクラスター内のすべてのノードとの間の関連付けを確立する必要があることにあります。

クラスター内のノードは比較的固定されており、数は少ないですが、ノードの追加や削除はあります。クラスターでは、保存されるキーの数は膨大で、完全にランダム、不規則、予測不可能で、ほとんどが些細なものです。

これは、大学とそのすべての学生との関係に似ています。大学と学生が直結していたら、間違いなく混乱するでしょう。実際には、それらの間にはいくつかの層が追加されており、最初に学科があり、次に専攻があり、次に学年があり、最後にクラスがあります。これら 4 つのレベルのマッピングの後、関係はより明確になります。

レイヤーを追加すれば解決できない問題はない、これは非常に重要な結論です。その場合は、別のレイヤーを追加します。コンピュータでも同様です。

Redis は、データとノードの間にスロットと呼ばれる別のレイヤーを追加します。スロットは主にハッシュに関連するため、ハッシュ スロットとも呼ばれます。

***ノード上にスロットが配置され、そのスロットにデータが配置されます。スロットは粒度の問題を解決します。これは粒度を大きくすることと同じであり、データの移動が容易になります。ハッシュ テクノロジは、マッピングの問題を解決するために使用され、キーのハッシュ値を使用してキーが配置されているスロットを計算し、データの配布を容易にします。

あなたの学習机の上には本が山積みになっていて、非常に乱雑で、その中から 1 冊を見つけるのが非常に困難です。大きな収納箱をいくつか購入し、タイトルの長さに応じて本をさまざまな箱に分類し、テーブルの上に置きます。

つまり、テーブルの上に収納ボックスがあり、その収納ボックスの中に本があります。これにより、本の移動が簡単になり、箱を持ち上げて移動するだけです。タイトルの長さを測り、対応するボックスに向かうだけで、必要な本を簡単に見つけることができます。

実は、私たちは何もしていませんでした。いくつかの箱を購入し、一定のルールに従って本を箱に詰めただけです。たったこれだけの簡単な行動で、当初混乱していた状況は一変しました。ちょっと魔法のようではありませんか?

クラスターには、0 ~ 16383 の番号が付いた 16384 個のスロットのみを含めることができます。これらのスロットはクラスター内のすべてのマスター ノードに割り当てられ、割り当てポリシーの要件はありません。どの番号付きスロットをどのマスター ノードに割り当てるかを指定できます。クラスターは、ノードとスロット間の対応する関係を記録します。

次に、キーをハッシュし、結果を 16384 で割って剰余を取得する必要があります。剰余によって、キーがどのスロットに分類されるかが決まります。スロット = CRC16(キー) % 16384。

スロット単位でデータを移動する スロット数が固定なので処理が楽になり、データ移動の問題が解決します。

ハッシュ関数を使用してキーのハッシュ値を計算し、対応するスロットを計算できるようにします。その後、スロットとクラスターに格納されているノード間のマッピング関係を使用して、キーが格納されているノードをクエリします。スロットが配置され、データとノードがマッピングされるため、データ割り当ての問題は解決されます。

私が言いたいのは、一般の人はさまざまなテクノロジーを学ぶだけで、専門家はテクノロジーの外にどう飛び出て、解決策や思考の方向性を模索し、その方向に進むかに関心があり、答えを見つけることができるということです。あなたが欲しいのです。

クラスタのコマンド操作の選択

クライアントはクラスタ内のノードとリンクを確立している限り、クラスタ全体のすべてのノード情報を取得できます。さらに、すべてのハッシュスロットとノードの対応関係情報が取得されますが、この情報データは非常に有用であるため、クライアント上にキャッシュされます。

クライアントは任意のノードにリクエストを送信できるため、キーを取得した後、どのノードにリクエストを送信する必要がありますか? 実際、これはキーとノードの間のマッピング関係の理論を動かすためです。クラスターをクライアントに送信するだけです。

そのため、クライアント側でもクラスタ側と同様にハッシュ関数を実装する必要があり、まずキーのハッシュ値を計算し、16384の余りを計算することで、キーに対応するハッシュスロットを取得します。用途 クライアントがキャッシュしたスロットとノードの対応関係情報に基づいて、キーに対応するノードを見つけることができます。

リクエストを送信するだけです。キーとノード間のマッピング関係をキャッシュすることもでき、次回キーをリクエストすると、再計算することなく、対応するノードを直接取得できます。

クライアントのキャッシュは更新されていませんが、クラスターは変化しており、理論と現実のギャップが示されています。対応するノードから要求されたキーは、そのノード上に存在しない可能性が非常に高くなります。この時点でこのノードは何をすべきでしょうか?

このノードは、キーが実際に存在するノードに移動してデータを取得し、それをクライアントに返すことができます。また、キーが次のものであることをクライアントに直接伝えることもできます。 HTTP の 302 リダイレクトと同様に、クライアントに現在のノード情報を再度要求させます。

これは実際には選択の問題であり、哲学的な質問です。結果として、redis クラスターは後者を選択しました。したがって、ノードは自分が所有するキーのみを処理し、所有していないキーの場合はリダイレクト エラー (-MOVED key 127.0.0.1:6381) を返し、クライアントはこの新しいノードにリクエストを再送信します。

つまり、選択は哲学であり、知恵なのです。これについては後で詳しく説明します。まず、この問題といくつかの類似点がある別の状況を見てみましょう。

Redis には、MGET など、一度に複数のキーを取得できるコマンドがあり、これらをマルチキー コマンドと呼んでいます。このマルチキー コマンドのリクエストはノードに送信されます。ここに潜在的な問題があります。考えたことがあるでしょうか。つまり、このコマンドの複数のキーは同じノード上に存在する必要があるということです。

これは 2 つの状況に分けられます。複数のキーが同じノード上にない場合、ノードはリダイレクト エラーのみを返すことができます。ただし、複数のキーが複数の異なるノード上にある可能性があります。このとき、リダイレクトはエラーを返します非常に混乱するため、redis クラスターはこの状況をサポートしないことを選択します。

同一ノード上に複数のキーが存在しても理論上は問題ありませんが、Redis クラスターがサポートしているかどうかは Redis のバージョンに依存しますので、使用する際はご自身でテストしてください。

このプロセス中に、非常に意味のあることを発見しました。つまり、関連するキーのグループを同じノードにマップすることが非常に必要であるということです。これにより、効率が向上し、一度に複数のキー コマンドを渡すことができます。価値観。

そこで問題は、同じノードに属するようにこれらのキーにどのように名前を付けるかということですが、最初にハッシュ値を計算してから剰余を計算する必要があるでしょうか? それは面倒すぎます。もちろん、これは当てはまりません。redis はすでにそれを解決しています。

単純な推論では、2 つのキーを同じノード上に置きたい場合、それらのハッシュ値は同じでなければなりません。ハッシュ値が同じであるためには、ハッシュ関数に渡される文字列が同じである必要があります。 2 つの同一の文字列のみを渡した場合、2 つの文字列は同じキーとして扱われ、後続のデータが前のデータを上書きします。

ここでの問題は、キー全体を使用してハッシュ値を計算するため、ハッシュ値の計算に関与するキーと文字列が結合されてしまうことです。キーと関与する文字列 文字列のハッシュの計算は関連していますが、異なります。

Redis は、キー ハッシュ タグと呼ばれる、この原則に基づくソリューションを提供します。まず、{user1000}.following、{user1000}.followers の例を見てみましょう。ハッシュ値の計算に参加するために Key 内の { と } の間の文字列のみを使用するというトリックはすでにお分かりいただけたと思います。

これにより、ハッシュ値が同じであり、同じノードに存在することが保証されます。ただし、キーは異なるため、互いにカバーすることはできません。ハッシュ タグを使用して関連するキーのセットを関連付けることにより、問題は楽しく簡単に解決されます。

問題を解決するには、優れたテクノロジーやアルゴリズムを使用するのではなく、独創的な創造性とアイデアが必要です。小さいながらもパワフルな小強です。

最後に、選択の哲学について話しましょう。 Redis の主な機能は、一般的に使用されるデータ構造へのキーと値のストレージとアクセスを可能な限り短時間で実装し、これらのデータ構造に対して関連する操作を実行することです。コアと関係のないもの、またはコアを引きずるようなものは処理を弱めるか処理しないことを選択します。これは、コアがシンプル、高速、安定していることを保証するために行われます。

実際、広さと深さに直面して、redis は深さを選択しました。したがって、ノードは所有していないキーを処理せず、クラスターは複数のキーに対するコマンドをサポートしません。このようにして、一方ではクライアントに迅速に応答でき、他方ではクラスター内での大量のデータ送信とマージを回避できます。

シングルスレッド モデル

Redis クラスターの各ノードには、クライアントから送信されたすべてのリクエストの受け入れと実行を担当するスレッドが 1 つだけあります。技術的には、Linux の epoll 機能を使用して多重 I/O が使用され、1 つのスレッドで多数のソケット接続を管理できます。

さらに、シングル スレッドを選択する理由は次のとおりです:

1. Redis はメモリ上で動作し、非常に高速です (10W QPS)

2、全体の時間主にネットワーク送信で消費されます

3. 複数のスレッドが使用される場合、マルチスレッドの同期が必要になり、実装が複雑になります

4. スレッドのロック時間は、メモリ操作

5. マルチスレッド コンテキストの頻繁な切り替えには、より多くの CPU 時間が必要になります

6. さらに、シングル スレッドはアトム操作を自然にサポートしており、シングル スレッド コードの記述は簡単です

トランザクション

トランザクションとは、複数の操作をまとめて実行するか、すべて実行する (成功) か、どれも実行しない (ロールバック) ことであることは誰もが知っています。 Redis はトランザクションもサポートしていますが、それはあなたが望むものではないかもしれません。

Redis トランザクションは、トランザクションの定義とトランザクションの実行という 2 つのステップに分けることができます。トランザクションを開始した後、実行するすべてのコマンドを順番に追加します。これによりトランザクションが定義されます。この時点で exec コマンドを使用してトランザクションを実行することも、discard コマンドを使用してトランザクションを破棄することもできます。

関心のあるキーがトランザクションの開始前に他の人によって操作されたくないことを望むかもしれません。その後、watch コマンドを使用してこれらのキーを監視できます。これらのキーが開始前に他のコマンドによって操作された場合実行するとトランザクションはキャンセルされます。 unwatch コマンドを使用して、これらのキーの監視をキャンセルすることもできます。

Redis トランザクションには次の特性があります:

1. トランザクションの開始前にエラーが発生した場合、すべてのコマンドは実行されません。

2. 開始されると、すべてのコマンドが実行されます。 1 回の実行が保証されています。中断されずに順番に実行されます。

3. 実行中にエラーが発生しても、実行は停止せずに続行されます。

4. 実行中に発生したエラーについては、ロールバックは行われません

上記の説明を読むと、これをトランザクションと呼んでよいのか疑問が生じます。明らかに、これは私たちが通常トランザクションとして理解しているものとはまったく異なります。アトミックであることさえ保証されていないからです。 Redis はロールバックをサポートしていないためアトミック性をサポートしていませんが、この機能がサポートされていないのには理由があります。

ロールバックをサポートしない理由:

1. Redis は、不適切なコマンドの使用が失敗の原因であると考えています

2. Redis は、内部実装をシンプルに保つためにこれを行っています。

#3. Redis は、ロールバックですべての問題を解決できるわけではないとも考えています。

ははは、これはオーバーロード句なので、Redis トランザクションを使用する人はあまり多くないようです

#Pipeline

クライアントとクラスター間の対話プロセスはシリアル ブロッキングです。つまり、クライアントはコマンドを送信した後、応答が返されるまで待機してから 2 番目のコマンドを送信する必要があります。往復の時間。コマンドがたくさんあり、それを 1 つずつ実行すると、非常に遅くなります。

Redis は、クライアントがサーバーからの応答を待たずに複数のコマンドを一度に送信できるパイプライン テクノロジを提供します。すべてのコマンドが送信された後、これらのコマンドに対するすべての応答が順番に受信されます。これにより、時間が大幅に節約され、効率が向上します。

賢明な方は、別の問題に気づきましたか? 複数のコマンドは複数のキーです。これは、上で説明した複数キー操作ではありませんか? では、問題は、これらの複数のキーをどのように確保するかということです。すべて同じノード上にあります。ははは、Redis クラスターはパイプラインのサポートを再び放棄しました。

ただし、クライアント側でシミュレーションすることは可能です。つまり、複数の接続を使用して複数のノードに同時にコマンドを送信し、すべてのノードが応答を返すのを待ってから、それらを順番に並べ替えます。コマンドが送信され、ユーザーコードに返されます。おっと、面倒ですね。

プロトコル

Redis プロトコルと Redis データ送信形式を簡単に理解します。

リクエスト送信プロトコル:

*パラメータ数 CRLF$パラメータ 1 のバイト数 CRLF パラメータ 1 のデータ CRLF...$パラメータ N のバイト数 CRLF パラメータ N のデータCRLF

たとえば、SET name lixinjie の場合、送信される実際のデータは次のとおりです:

##*3\r\n$3\r\nSET\r\n$4\r\nname\r\n$8 \r\nlixinjie\r\n

応答を受け入れるためのプロトコル:

単一行の応答、*** バイトは

エラー メッセージ、*** バイトです -

整数、最初のバイトは:

バッチ応答、*** バイトは $

複数のバッチ応答、** * バイトは *

たとえば、

OK\r\n

-ERR に対する操作\r\n

:1000\r\ n

$6\ r\nfoobar\r\n

*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n

redis プロトコルが非常にシンプルになるように設計されていることがわかります。

以上がRedis ナレッジ ポイントを分析する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。