Redisの基本的なデータタイプ
- 文字列:Redisは、C言語の従来の文字列表現を直接使用しませんが、代わりに単純な動的文字列SDSと呼ばれる抽象型を実装します。C言語の文字列は独自の長さ情報を記録しませんが、SDSは長さ情報を保存するため、文字列の長さを取得する時間がO(N)からO(1)に短縮され、バッファオーバーフローが回避され、変更された文字が削減されます。文字列の長さに必要なメモリ再割り当ての数。
- リンクリストリンクリスト:Redisリンクリストは双方向の非循環リンクリスト構造です。多くの公開およびサブスクライブ、低速クエリ、および監視機能はリンクリストを使用して実装されます。各リンクリストノードはlistNode構造で表され、各ノードには先頭へのポインタがあります。セットノードとリアノードのポインタ、およびヘッダーノードのフロントノードとリアノードはどちらもNULLを指します。
- 辞書ハッシュテーブル:キーと値のペアを格納するために使用される抽象的なデータ構造。Redisは、基盤となる実装としてハッシュテーブルを使用します。各辞書には、通常の使用と再ハッシュ用に2つのハッシュテーブルがあります。ハッシュテーブルは、チェーンアドレス方式を使用してキーの競合を解決し、同じインデックス位置にある複数のキーと値のペアに割り当てられます。単一リンクリストが形成されます。ハッシュテーブルを拡張または縮小する場合、サービスの可用性のために、再ハッシュプロセスは一度に完了するのではなく、徐々に完了します。
- スキップリスト:スキップリストは、順序付きコレクションの基本的な実装の1つです。Redisは、順序付きコレクションキーとクラスターノードの内部構造でスキップリストを使用します。redisスキップリストはzskiplistとzskiplistNodeで構成されます。zskiplistはスキップリストの情報(ヘッダー、テールノード、長さなど)を格納するために使用され、zskiplistNodeはテーブルのスキップノードを表すために使用され、各スキップリストの高さは1〜32でランダムです。同じジャンプテーブル内で、複数のノードに同じスコアを含めることができますが、各ノードのメンバーオブジェクトは一意である必要があります。ノードはスコアに従って並べ替えられます。スコアが同じ場合は、メンバーオブジェクトのサイズで並べ替えられます。 。
- Integer collection intset:整数値のコレクションの抽象的なデータ構造であり、重複する要素は表示されず、最下層は配列として実装されます。
- 圧縮リストziplist:圧縮リストは、メモリを節約するために開発されたシーケンシャルデータ構造です。複数のノードを含めることができ、各ノードにバイト配列または整数値を格納できます。
これらの基本的なデータ構造に基づいて、redisは、文字列オブジェクト文字列、リストオブジェクトリスト、ハッシュオブジェクトハッシュ、コレクションオブジェクトセット、順序付きコレクションオブジェクトzsetなど、独自のオブジェクトシステムをカプセル化します。各オブジェクトは少なくとも1つの基準を使用します。データ構造。
Redisは、encoding属性を使用してオブジェクトのエンコード形式を設定し、柔軟性と効率を向上させます。Redisは、さまざまなシナリオに基づいてオブジェクトを自動的に最適化します。さまざまなオブジェクトのエンコードは次のとおりです。
文字列オブジェクト文字列:int整数、embstrコード化された単純な動的文字列、生の単純な動的文字列
- リストオブジェクトリスト:ziplist、linkedlist
- ハッシュオブジェクトハッシュ:ziplist、hashtable
- コレクションオブジェクトセット:intset、hashtable
- 順序付けられたコレクションオブジェクトzset:ziplist、skiplist
なぜRedisは速いのですか?
redisの速度は非常に高速です。スタンドアロンのredisは、1秒あたり数万の同時実行をサポートできます。mysqlと比較すると、そのパフォーマンスはmysqlの数十倍です。高速にはいくつかの理由があります。
- 完全にメモリ操作に基づく
- C言語の実装、最適化されたデータ構造、いくつかの基本的なデータ構造に基づいて、redisは多くの最適化、高性能を実行しました
- シングルスレッドを使用し、コンテキスト切り替えのコストはかかりません
- ノンブロッキングIO多重化メカニズムに基づく
Redis 6.0以降でマルチスレッドを使用するのはどうですか?
Redisのマルチスレッドの使用は、シングルスレッドを完全に放棄することではありません。Redisは引き続きシングルスレッドモデルを使用してクライアント要求を処理します。マルチスレッドを使用してデータの読み取りと書き込み、およびプロトコル分析を処理し、コマンドの実行は引き続きシングルスレッドを使用します。
これは、redisのパフォーマンスのボトルネックがCPUではなくネットワークIOにあるためです。マルチスレッドを使用すると、IOの読み取りと書き込みの効率が向上し、redis全体のパフォーマンスが向上します。
ホットキーとは何か知っていますか?ホットキーの問題を解決する方法は?
いわゆるホットキーの問題は、突然、redisの特定のキーにアクセスするための数十万の要求が発生し、トラフィックが集中しすぎて物理ネットワークカードの上限に達し、redisサーバーがダウンして雪崩が発生することです。
ホットキーのソリューション:
- プレッシャーを軽減するために、事前にホットキーを別のサーバーに配布します
- セカンダリキャッシュに参加し、ホットキーデータを事前にメモリにロードします。redisがダウンしている場合は、メモリクエリを使用します。
キャッシュの内訳、キャッシュの浸透、キャッシュのなだれ
キャッシュの内訳
キャッシュブレークダウンの概念は、単一のキーの同時アクセスが高すぎることであり、有効期限が切れると、すべてのリクエストがDBに直接ヒットします。これはホットキーの問題に似ていますが、有効期限が切れるとすべてのリクエストがDBにヒットします。
解決:
- クエリAを要求してキャッシュにないことを確認するなど、更新をロックし、キーAをロックすると同時に、データベース内のデータをクエリし、キャッシュに書き込んでからユーザーに返します。これにより、後続のリクエストでキャッシュからデータを取得できます。
- 有効期限の組み合わせを値に書き込み、このような現象を防ぐために、非同期で有効期限を継続的に更新します。
キャッシュの浸透
キャッシュペネトレーションとは、キャッシュに存在しないデータをクエリすることを指し、キャッシュが存在しないかのように、すべての要求がDBにヒットします。
この問題に対応して、ブルームフィルターのレイヤーを追加します。ブルームフィルターの原理は、データを保存するときに、ハッシュ関数を介してビット配列のKポイントにマップされ、それらが1に設定されることです。
このようにして、ユーザーが再びAにクエリを実行し、Aのブルームフィルター値が0の場合、直接戻り、DBにヒットするブレークダウン要求は生成されません。
明らかに、ブルームフィルターを使用した後、それは配列自体であり、同じ位置に複数の値が入る可能性があるため、誤判定の問題が発生します。理論的には、配列の長さが十分に長い限り、誤判定が発生します確率は低くなりますが、この種の問題は実際の状況に基づいている必要があります。
雪崩をキャッシュする
キャッシュサービスがダウンした場合など、特定の瞬間に大規模なキャッシュ障害が発生すると、多数のリクエストがDBに直接ヒットし、システム全体がクラッシュする可能性があります。これはアバランシェと呼ばれます。雪崩は故障やホットキーの問題と同じではなく、大規模なキャッシュが期限切れになったことを意味します。
なだれのいくつかの解決策:
- 同時有効期限を回避するために、キーごとに異なる有効期限を設定します
- 現在の制限。redisがダウンしている場合は、電流を制限して、同時に多数のリクエストでDBがクラッシュしないようにすることができます。
- セカンダリキャッシュ、同じホットキースキーム。
Redisの有効期限戦略
怠惰な削除
遅延削除とは、キーを照会するときにキーがチェックされ、有効期限に達した場合に削除されることを意味します。明らかに、これらの期限切れのキーにアクセスしないと削除できず、常にメモリを占有するという欠点があります。
定期的に削除する
定期的な削除とは、Redisが定期的にデータベースをチェックし、期限切れのキーを削除することを意味します。ポーリングですべてのキーを削除することは不可能であるため、redisはランダムにいくつかのキーを選択してチェックし、毎回削除します。
では、期限切れのキーが定期的に+怠惰に削除されない場合はどうすればよいですか?
redisがランダムにキーを照会するたびにredisが削除されず、これらのキーが照会されないと仮定すると、これらのキーは常にredisに格納され、削除できません。このとき、redisのメモリ除去メカニズムに移動します。
- Volatile-lru:有効期限が削除用に設定されているキーから、最も使用頻度の低いキーを削除します
- Volatile-ttl:有効期限を設定したキーから有効期限が切れるキーを削除します
- Volatile-random:有効期限が設定されているキーから削除するキーをランダムに選択します
- allkeys-lru:キーから最も使用頻度の低いキーを選択して削除します
- allkeys-random:削除するキーからランダムにキーを選択します
- noeviction:メモリがしきい値に達すると、新しい書き込み操作でエラーが報告されます
永続化方法とは何ですか?違いは何ですか?
RDB
RDBの永続性は、構成に応じて手動または定期的に実行できます。その機能は、特定の時点でのデータベースの状態をRDBファイルに保存することです。RDBファイルは、特定の時点でのデータベースを復元できる圧縮バイナリファイルです。状態。RDBファイルはハードディスクに保存されているため、redisがクラッシュしたり終了したりしても、RDBファイルが存在する限り、データベースの状態を復元するために使用できます。
SAVEまたはBGSAVEを介してRDBファイルを生成できます。
SAVEコマンドは、RDBファイルが生成されるまでredisプロセスをブロックします。プロセスブロック中、redisはコマンド要求を処理できません。これは明らかに不適切です。
BGSAVEは子プロセスをフォークし、子プロセスがRDBファイルの生成を担当します。親プロセスは、プロセスをブロックせずにコマンド要求を処理し続けることができます。
AOF
AOFはRDBとは異なります。AOFは、redisサーバーによって実行された書き込みコマンドを保存することによってデータベースの状態を記録します。
AOFは、追加、書き込み、同期の3つのステップを通じて永続化メカニズムを実装します。
- AOF永続性がアクティブ化され、サーバーが書き込みコマンドの実行を終了すると、書き込みコマンドがaof_bufバッファーの最後に追加されます。
- サーバーが各イベントループを終了する前に、flushAppendOnlyFile関数が呼び出され、aof_bufのコンテンツをAOFファイルに保存するかどうかが決定されます。これは、appendfsyncを構成することで決定できます。
always ##aof_buf内容写入并同步到AOF文件
everysec ##将aof_buf中内容写入到AOF文件,如果上次同步AOF文件时间距离现在超过1秒,则再次对AOF文件进行同步
no ##将aof_buf内容写入AOF文件,但是并不对AOF文件进行同步,同步时间由操作系统决定
設定されていない場合、デフォルトのオプションはeverysecになります。これは、常に最も安全ですが(1つのイベントループ書き込みコマンドのみが失われます)、パフォーマンスが低下し、everysecモードでは1秒のデータしか失われないためです。 noモードの効率はeverysecの効率と同様ですが、AOFファイルの最後の同期後のすべての書き込みコマンドデータが失われます。
Redisの高い可用性を実現するにはどうすればよいですか?
高可用性を実現するには、1台のマシンでは絶対に不十分であり、redisは高可用性を確保する必要があります。2つのオプションがあります。
マスタースレーブアーキテクチャ
マスタースレーブモードは、高可用性を実現するための最も簡単なソリューションであり、コアはマスタースレーブ同期です。マスタースレーブ同期の原理は次のとおりです。
- スレーブは同期コマンドをマスターに送信します
- マスターは同期を受信した後、bgsaveを実行して完全なRDBファイルを生成します
- マスターはスレーブの書き込みコマンドをキャッシュに記録します
- bgsaveが実行された後、RDBファイルをスレーブに送信すると、スレーブは実行されます。
- マスターはバッファー内の書き込みコマンドをスレーブに送信し、スレーブは実行します
ここで書いたコマンドはsyncですが、redis 2.8バージョン以降は、syncの代わりにpsyncが使用されています。これは、syncコマンドがシステムリソースを消費し、psyncの方が効率的であるためです。
歩哨
マスタースレーブソリューションの欠点は依然として明らかです。マスターがダウンしているとデータを書き込めず、スレーブはその機能を失い、アーキテクチャ全体が使用できなくなります。手動で切り替えない限り、主な理由は自動障害が発生しないことです。転送メカニズム。センチネルの機能は、単純なマスタースレーブアーキテクチャの機能よりもはるかに包括的であり、自動フェイルオーバー、クラスターモニタリング、メッセージ通知などの機能を備えています。
番兵は複数のマスターサーバーとスレーブサーバーを同時に監視でき、監視対象のマスターがオフラインになると、自動的にスレーブをマスターに昇格させ、新しいマスターは引き続きコマンドを受信します。全体のプロセスは次のとおりです。
- 歩哨を初期化し、通常のredisコードを歩哨の特別なコードに置き換えます
- マスター辞書とサーバー情報を初期化します。サーバー情報は主にip:portを保存し、インスタンスのアドレスとIDを記録します。
- マスターとの2つの接続、コマンド接続とサブスクリプション接続を作成し、sentinel:helloチャネルにサブスクライブします
- infoコマンドを10秒ごとにマスターに送信して、マスターとその下にあるすべてのスレーブの現在の情報を取得します。
- マスターに新しいスレーブがあることが判明すると、センチネルと新しいスレーブも2つの接続を確立し、10秒ごとにinfoコマンドを送信して、マスター情報を更新します。
- Sentinelは1秒ごとにすべてのサーバーにpingコマンドを送信します。サーバーが構成された応答時間内に無効な応答を継続的に返す場合、オフラインとしてマークされます。
- リーダーセンチネルの選出、リーダーセンチネルはセンチネルの半分以上の同意を必要とします
- リーダー歩哨はオフラインマスターのスレーブの1つを選択し、それをマスターに変換します
- すべてのスレーブに新しいマスターからデータをコピーさせます
- 元のマスターを新しいマスターのスレーブサーバーとして設定し、元のマスターが再接続すると、新しいマスターのスレーブサーバーになります
Sentinelは、1秒ごとにすべてのインスタンス(マスタースレーブサーバーと他のセンチネルを含む)にpingコマンドを送信し、応答に基づいてオフラインであるかどうかを判断します。この方法は、主観的オフラインと呼ばれます。オフラインと判断された場合は、監視対象の他の番兵に質問し、投票の半分以上がオフラインと見なされた場合、客観的なオフライン状態としてマークされ、フェイルオーバーがトリガーされます。
redisクラスターの原理
センチネルを使用してredisの高い可用性を実現できる場合、大量のデータに対応しながら高い同時実行性をサポートする場合は、redisクラスターが必要です。Redisクラスターは、redisが提供する分散データストレージソリューションです。クラスターは、データシャーディングを使用してデータを共有すると同時に、レプリケーションおよびフェイルオーバー機能を提供します。
ノード
redisクラスターは複数のノードで構成され、複数のノードがclustermeetコマンドを介して接続されます。ノードのハンドシェイクプロセス:
- ノードAは、クライアントからclustermeetコマンドを受信します
- Aは、受信したIPアドレスとポート番号に従ってBに会議メッセージを送信します
- ノードBは会議メッセージを受信し、ポンを返します
- Aは、Bが会議メッセージを受信してpingメッセージを返したことを認識し、ハンドシェイクが成功します。
- 最後に、ノードAはゴシッププロトコルを介してノードBの情報をクラスター内の他のノードに拡散し、他のノードもBと握手を交わします。
スロット
Redisは、クラスターシャーディングの形式でデータを保存します。クラスターデータベース全体が16384スロットに分割されます。クラスター内の各ノードは0-16384スロットを処理できます。データベース内の16384スロットがノードによって処理されると、クラスターはオンラインになります。ステータス。それ以外の場合、スロットが処理されない限り、オフラインステータスが処理されます。スロットは、clusteraddslotsコマンドを使用して処理するために対応するノードに割り当てることができます。
スロットはビット配列で、配列の長さは16384/8 = 2048で、配列の各ビットは1を使用してノードによって処理されることを示し、0は処理されないことを示します。図に示すように、Aノードが0〜7個のスロットを処理することを意味します。
クライアントがノードにコマンドを送信するときに、スロットが現在のノードに属していることが判明した場合、ノードはコマンドを実行します。それ以外の場合、ノードはMOVEDコマンドをクライアントに返し、クライアントを正しいノードに誘導します。(MOVEDプロセスは自動です)
ノードを追加または削除すると、スロットの再配布に非常に便利です。Redisは、スロットの移行を実現するためのツールを提供します。プロセス全体が完全にオンラインであり、サービスを停止する必要はありません。
フェイルオーバー
ノードAがノードBにpingメッセージを送信し、ノードBが指定された時間内にpongに応答しない場合、ノードAはノードBをpfailの疑いのあるオフラインステータスとしてマークし、同時にBのステータスをメッセージの形式で他のノードに送信します。 Bをpfail状態としてマークしたノードの半分以上、Bをfailオフライン状態としてマークします。この時点で、フェイルオーバーが発生し、より複製されたデータを持つスレーブノードを選択してマスターノードになり、オフラインを引き継ぎます。ノードのスロット、プロセス全体は、選挙用のRaftプロトコルに基づく歩哨のスロットと非常に似ています。
Redisトランザクションメカニズム
Redisは、MULTI、EXEC、WATCH、およびその他のコマンドを介してトランザクションメカニズムを実装します。トランザクション実行プロセスは、一連の複数のコマンドを一度に順番に実行し、実行中にトランザクションが中断されることも、クライアントからの他の要求を実行することもありません。すべてのコマンドが実行されるまで。トランザクションの実行プロセスは次のとおりです。
- サーバーはクライアント要求を受信し、トランザクションはMULTIで始まります
- クライアントがトランザクション状態の場合、トランザクションはキューに入れられ、クライアントQUEUEDに返されます。それ以外の場合、コマンドは直接実行されます。
- クライアントEXECコマンドを受信すると、WATCHコマンドは、トランザクション全体のキーが変更されたかどうかを監視します。失敗を示す空の応答がある場合は、redisはトランザクションキュー全体をトラバースし、キューに保存されているすべてのコマンドを実行します。最後に結果をクライアントに返します
WATCHメカニズム自体はCASメカニズムであり、監視対象のキーはリンクリストに保存されます。キーが変更されると、REDIS_DIRTY_CASフラグがオンになり、サーバーはトランザクションの実行を拒否します。