ホームページ >データベース >Redis >Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

青灯夜游
青灯夜游転載
2021-09-13 11:06:088495ブラウズ

ゴールデン ナインとシルバー 10 が間もなく登場します。この記事では、Redis の典型的な面接の質問 20 個を紹介します。皆さんのお役に立てれば幸いです。

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

#1. Redis とは何ですか?主に何に使用されますか?

Redis は、正式な英語名は Remote Dictionary Server (リモート辞書サービス) で、ANSI C 言語で書かれたオープンソースで、ネットワークをサポートし、メモリベースにすることができます。永続的なログ タイプ、Key-Value データベースを備え、複数の言語で API を提供します。 [関連する推奨事項: Redis ビデオ チュートリアル ]

MySQL データベースとは異なり、Redis データはメモリに保存されます。読み取りおよび書き込み速度は非常に高速で、1 秒あたり 100,000 回を超える読み取りおよび書き込み操作を処理できます。したがって、Redis はキャッシュに広く使用されているだけでなく、分散ロックにもよく使用されます。さらに、Redis はトランザクション、永続性、LUA スクリプト、LRU 駆動イベント、およびさまざまなクラスター ソリューションをサポートします。

2. Redis の基本的なデータ構造タイプについて話しましょう

Redis には次の 5 つの基本的なタイプがあることはほとんどの友人が知っています:

String (文字列)
  • Hash (ハッシュ)
  • List (リスト)
  • Set (セット)
  • zset (順序付きセット) )
  • これには、3 つの特殊なデータ構造タイプもあります。

地理空間
  • ハイパーログログ
  • ビットマップ
  • 2.1 5 つRedis の基本データ型

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)#String (string)

はじめに: String は Redis の最も基本的なデータ構造型であり、バイナリです。安全で、画像やシリアル化されたオブジェクトを保存できます。保存される最大値は 512M
  • 簡単な使用例:
  • set key value
  • get key など アプリケーション シナリオ: 共有セッション、分散ロック、カウンター、電流制限。
  • 内部エンコードには
  • int (8 バイト長の整数)/embstr (39 バイト以下の文字列)/raw (39 バイトを超える文字列)の 3 種類があります
  • ##C 言語の文字列は
  • char[]
によって実装されますが、Redis は

SDS (単純な動的文字列) カプセル化を使用します。sds のソース コードは次のとおりです。 :

struct sdshdr{
  unsigned int len; // 标记buf的长度
  unsigned int free; //标记buf中未使用的元素个数
  char buf[]; // 存放元素的坑
}
SDS 構造図は次のとおりです:

C 言語ネイティブであるのに、Redis が Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)SDS

構造を選択する理由

char[] いい匂いしませんか? たとえば、SDS では、文字列の長さは O(1) の時間計算量で取得できますが、C 文字列の場合は、文字列全体を走査する必要があり、時間計算量は O です。 (n)

Hash (ハッシュ)

はじめに: Redis では、ハッシュ タイプは、キーと値のペア (k-v) である v (値) 自体を指します。構造

    簡単な使用例:
  • hset キー フィールド値
  • hget キー フィールド#内部エンコーディング: ziplist (圧縮リスト),
  • hashtable (ハッシュ テーブル)
  • アプリケーション シナリオ: ユーザー情報のキャッシュなど。
  • Note
  • : hgetall を開発に使用し、ハッシュ要素が多い場合、Redis がブロックされる可能性があります。hscan を使用できます。一部のフィールドのみを取得したい場合は、hmget を使用することをお勧めします。
  • 文字列型とハッシュ型の比較は次のとおりです:

List (リスト)

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

はじめに:リスト (リスト) タイプは、複数の順序付けされた文字列を格納するために使用され、リストには最大 2^32-1 個の要素を格納できます。

シンプルで実践的な例:
    lpush key value [value ...]
  • ,
  • lrange key start end
  • 内部エンコーディング: ziplist (圧縮リスト) )、linkedlist (リンク リスト)アプリケーション シナリオ: メッセージ キュー、記事リスト、
  • リスト タイプの挿入とポップアップを理解するための 1 つの図:

list アプリケーション シナリオは次を参照します。

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

lpush lpop=Stack (スタック)

lpush rpop=Queue (キュー)
  • lpsh ltrim=Capped Collection (限定コレクション)
  • lpush brpop=Message Queue (メッセージキュー)
  • Set (コレクション)

  • はじめに: set タイプは複数の文字列要素を保存するためにも使用されますが、要素の重複は許可されません
  • 簡単な使用例: sadd key element [element ... ], smembers key
  • 内部エンコード: intset (整数セット) , hashtable (ハッシュ テーブル)
  • Note: smembers、lrange、hgetall はいずれも比較的重いコマンドですが、要素が多すぎて Redis がブロックされる可能性がある場合は、sscan を使用して完了できます。
  • アプリケーション シナリオ: ユーザー タグ、宝くじ用の乱数生成、およびソーシャル ニーズ。

順序付きセット (zset)

  • 概要: ソートされた文字列のセット。要素は繰り返すことができません。
  • 簡単な形式の例: zadd キー スコア メンバー [スコア メンバー ...]zrank キー メンバー
  • 基になる内部エンコード: ziplist (圧縮リスト)skiplist (ジャンプ テーブル)
  • アプリケーション シナリオ: ランキング、ソーシャル ニーズ (ユーザーの好みなど)。

2.2 Redis の 3 つの特別なデータ型

  • Geo: Redis3.2 によって開始された地理的位置測位は、地理的位置情報を保存し、情報の実行操作を保存するために使用されます。
  • HyperLogLog: 統計 Web サイトの UV など、カーディナリティ統計アルゴリズムに使用されるデータ構造。
  • ビットマップ: 1 ビットを使用して要素のステータスをマップします。Redis では、その最下層は文字列型に基づいて実装されます。ビットマップはビット単位の配列に変換できます。

3. Redis はなぜそれほど速いのでしょうか?

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

3.1 メモリ ストレージに基づく実装

メモリの読み取りと書き込みがディスクよりもはるかに高速であることは誰もが知っています。メモリ ストレージ。データはディスク上の MySQL データベースに保存されるため、ディスク I/O の消費がなくなります。

3.2 効率的なデータ構造

効率を向上させるために、Mysql インデックスは B ツリー データ構造を選択することがわかっています。実際、合理的なデータ構造により、アプリケーション/プログラムを高速化できます。まず、Redis のデータ構造と内部エンコード図を見てみましょう。

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

#SDS 単純な動的文字列

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

  • #文字列の長さの処理: Redis は文字列の長さを取得します。時間計算量は O(1) ですが、C 言語では最初からたどる必要があり、計算量は O(n);
  • スペースの事前割り当て : 文字列が変更される頻度が高くなるほど、メモリの割り当ても頻繁になり、パフォーマンスが消費されます。SDS の変更とスペースの拡張により、追加の未使用スペースが割り当てられ、パフォーマンスの損失が軽減されます。
  • Lazy space release: SDS が短縮されると、余分なメモリ領域をリサイクルする代わりに、free に余分な領域が記録されます。その後変更があった場合、free に記録された領域は割り当てを削減するために直接使用されます。
  • バイナリ セーフティ: Redis はバイナリ データを保存できます。C 言語では、文字列は '\0' に遭遇すると終了しますが、SDS では、len 属性が文字列の終わりをマークします。

Dictionary

Redis は K-V 型のメモリ データベースであり、すべてのキー値は辞書に格納されます。ディクショナリは HashMap などのハッシュ テーブルであり、キーを通じて対応する値を直接取得できます。ハッシュテーブルの特徴としては、O(1)の計算量で対応する値が得られる。

ジャンプ テーブル

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

  • スキップ テーブルは Redis の独自のデータ構造であり、リンク リストに基づいて複数のデータを追加します。 -レベルインデックスの改善、検索効率。
  • スキップ テーブルは、平均 O(logN) および最悪の場合の O(N) 複雑さによるノード検索をサポートし、順次操作を通じてノードをバッチで処理することもできます。

3.3 合理的なデータ エンコーディング

Redis は複数のデータ型をサポートしており、各基本型は複数のデータ構造を持つことができます。いつ、どのようなデータ構造を使用するか、どのエンコーディングを使用するかは、Redis デザイナーの要約と最適化の結果です。

  • 文字列: 数値が格納される場合は、int 型のエンコードが使用されます。数値以外が格納される場合は、39 バイト以下の文字列は embstr です。39 バイトより大きい場合は、embstr になります。は生のエンコーディングです。
  • リスト: リスト内の要素の数が 512 未満で、リスト内の各要素の値が 64 バイト (デフォルト) 未満の場合は、ziplist エンコードを使用します。それ以外の場合は、リンクリスト エンコードを使用します。
  • Hash: Ha ハッシュ型要素の数が 512 未満で、すべての値が 64 バイト未満の場合は ziplist エンコーディングを使用し、それ以外の場合はハッシュテーブル エンコーディングを使用します。
  • Set: セット内の要素がすべて整数で、要素の数が 512 未満の場合は、intset エンコーディングを使用します。それ以外の場合は、ハッシュテーブル エンコーディングを使用します。
  • #Zset: 順序付きセット内の要素の数が 128 未満で、各要素の値が 64 バイト未満の場合は、ziplist エンコーディングを使用します。それ以外の場合は、skiplist (スキップ リスト) エンコーディングを使用します
3.4 合理的なスレッド モデル

##I/O 多重化

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)##複数の I/O 多重化このテクノロジーにより、単一のスレッドで複数の接続リクエストを効率的に処理できるようになり、Redis は I/O 多重化テクノロジーの実装として epoll を使用します。さらに、Redis 独自のイベント処理モデルは、ネットワーク I/O にあまり時間を費やすことなく、epoll での接続、読み取り、書き込み、およびシャットダウンをイベントに変換します。

I/O 多重化とは何ですか?

I/O: ネットワーク I/O
    マルチチャネル: 複数のネットワーク接続
  • 多重化: 同じスレッドを再利用します。
  • IO 多重化は実際には同期 IO モデルであり、複数のファイル ハンドルを監視できるスレッドを実装します。ファイル ハンドルの準備が完了すると、対応する読み取りおよび書き込み操作を実行するようにアプリケーションに通知できます。ファイル ハンドルがない場合は、準備ができている場合、アプリケーションはブロックされ、CPU が引き渡されます。
シングル スレッド モデル

Redis はシングル スレッド モデルであり、シングル スレッドにより不必要なコンテキストの切り替えや競合が回避されます。 CPU ロックの消費量。シングルスレッドであるため、特定のコマンド(hgetallコマンドなど)を長時間実行するとブロッキングが発生します。 Redis は、高速実行シナリオのためのデータベースです。 、そのため、smembers、lrange、hgetall などのコマンドは注意して使用する必要があります。

    Redis 6.0 では高速化のためにマルチスレッドが導入されていますが、コマンドとメモリ操作の実行は引き続きシングル スレッドです。
  • 3.5 仮想メモリ機構
Redis は VM 機構を自ら直接構築するため、通常のシステムのようにシステム関数を呼び出したり、移動やリクエストに一定の時間を浪費したりすることはありません。

Redis の仮想メモリ メカニズムとは何ですか?

仮想メモリ メカニズムは、アクセス頻度の低いデータ (コールド データ) をメモリからディスクに一時的に交換し、アクセスする必要がある他のデータ (ホット データ) のために貴重なメモリ領域を解放します。 。 データ)。 VM 機能は、ホット データとコールド データの分離を実現できるため、ホット データはメモリ内に残り、コールド データはディスクに保存されます。これにより、メモリ不足によるアクセス速度の低下の問題を回避できます。

4. キャッシュ ブレークダウン、キャッシュ ペネトレーション、キャッシュ アバランチとは何ですか?

4.1 キャッシュの侵入の問題

まず、キャッシュの一般的な使用方法を見てみましょう: 読み取りリクエストが来たとき、最初にキャッシュを確認します。キャッシュに値がヒットした場合、キャッシュは直接返されます。 ; キャッシュが見つからない場合は、データベースをチェックし、データベースの値をキャッシュに更新してから戻ります。

1Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)キャッシュ侵入

: 存在してはいけないデータのクエリを指します。キャッシュが見つからないため、データベースからクエリを実行する必要があります。データが見つからない場合、キャッシュに書き込まないと、存在しないデータが要求されるたびにデータベース内でクエリされることになり、データベースに負荷がかかります。

平たく言えば、読み取りリクエストがアクセスされるとき、キャッシュにもデータベースにも特定の値がないため、この値に対する各クエリ リクエストがデータベースに侵入します。これがキャッシュの侵入です。 . .

キャッシュの侵入は通常、次の状況によって発生します。

不合理なビジネス設計
    。たとえば、ほとんどのユーザーは Guard を有効にしていませんが、すべてのユーザーが Guard を有効にしていません。作成したリクエストはキャッシュに保存され、特定のユーザー ID が保護されているかどうかがチェックされます。
  • ビジネス/運用/メンテナンス/開発エラー
  • (キャッシュやデータベース データが誤って削除されるなど)。
  • ハッカーによる違法なリクエスト攻撃
  • たとえば、ハッカーは、存在しないビジネス データを読み取るための大量の違法なリクエストを意図的にでっち上げます。
  • キャッシュの侵入を回避するにはどうすればよいですか?
一般に 3 つの方法があります。

  • 1. 不正なリクエストの場合は、API 入口でパラメータを検証し、不正な値を除外します。
  • 2. クエリ データベースが空の場合は、キャッシュに null 値またはデフォルト値を設定できます。ただし、書き込み要求が来た場合は、キャッシュの整合性を確保するためにキャッシュを更新する必要があり、同時に、最終的にキャッシュに適切な有効期限が設定されます。 (ビジネスでよく使用され、シンプルで効果的です)
  • 3. ブルーム フィルターを使用して、データが存在するかどうかをすばやく判断します。つまり、クエリリクエストが来ると、まずブルームフィルターを通して値が存在するかどうかを判断し、その後も存在するかどうかを確認し続けます。

ブルーム フィルターの原理: 初期値 0 のビットマップ配列と N 個のハッシュ関数で構成されます。キーに対して N 個のハッシュ アルゴリズムを実行して N 個の値を取得します。これらの N 個の値をビット配列でハッシュし、1 に設定します。次に、チェック時に、これらの特定の位置がすべて 1 であれば、ブルーム フィルター処理が行われます。サーバーはキーが存在すると判断します。 。

4.2 キャッシュ スノー ランの問題

キャッシュ スノー ラン: とは、キャッシュ内の大量のデータ バッチの有効期限とクエリ データの量を指します。は巨大で、すべてのリクエストはデータベースに直接アクセスされるため、データベースに過剰な負荷がかかったり、マシンがダウンしたりすることがあります。

  • キャッシュスノースノーは一般に、大量のデータが同時に期限切れになることで発生するため、有効期限を均等に設定する、つまり有効期限を比較的離散的に設定することで解決できます。 。たとえば、より大きな固定値とより小さなランダム値 (5 時間、0 ~ 1800 秒) を使用します。
  • Redis の障害により、キャッシュ スノー雪が発生する可能性もあります。これには、Redis 高可用性クラスターを構築する必要があります。

4.3 キャッシュ ブレークダウンの問題

キャッシュ ブレークダウン: とは、ホットスポット キーが特定の時点で期限切れになることを指し、まさにその時点で、このキーには多数の同時リクエストがあるため、大量のリクエストがデータベースにヒットします。

キャッシュのブレークダウンは少し似ています。実際、それらの違いは、キャッシュの降雪は、データベースに過度の圧力がかかっているか、さらにはダウンしていることを意味することです。キャッシュのブレークダウンは、単に DB データベースへの同時リクエストの数が多いだけです。レベル。ブレークダウンはキャッシュ スノーランのサブセットであると考えることができます。一部の記事では、この 2 つの違いは、ブレークダウンが特定のホット キー キャッシュを対象としているのに対し、Xuebeng は多くのキーを対象としている点であると考えられています。

解決策は 2 つあります:

  • 1. ミューテックス ロック スキームを使用します。キャッシュが失敗した場合、データベース データをすぐにロードするのではなく、まず (Redis の setnx) など、成功した場合のアトミック操作コマンドを使用して操作し、成功したら db データベース データをロードしてキャッシュを設定します。それ以外の場合は、キャッシュを再度取得してみてください。
  • 2.「期限切れにならない」 は、有効期限が設定されていないが、ホットスポット データの有効期限が近づくと、非同期スレッドが更新されて有効期限を設定することを意味します。

5. ホット キーの問題とその解決方法

ホット キー とは何ですか? Redisではアクセス頻度の高いキーをホットスポットキーと呼びます。

ホットスポット キーのリクエストがサーバー ホストに送信されると、リクエスト量が特に多いため、ホスト リソースが不足したり、ダウンタイムが発生したりして、通常のサービスに影響を与える可能性があります。

1Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

ホットスポット キーはどのように生成されますか?主な理由は 2 つあります。

  • ユーザーが消費するデータは、速報セール、話題のニュース、その他のシナリオなど、より多くの読み取りとより少ない書き込みが必要なシナリオなど、生成されるデータよりもはるかに大きいためです。
  • リクエストシャーディングが集中し単一のRediサーバーの性能を超え、例えば固定名のキーとハッシュが同一サーバーに落ちてしまうとインスタントアクセス量が膨大になりマシンのボトルネックを超えてしまい、ホットキーの問題を引き起こします。

では、日々の開発においてホットキーを特定するにはどうすればよいでしょうか?

  • どのホット キーがエクスペリエンスに基づいているかを決定する;
  • クライアント統計をレポートする;
  • サービス エージェント層にレポートする

ホットキーの問題を解決するにはどうすればよいですか?

  • Redis クラスターの拡張: シャード コピーを追加して読み取りトラフィックのバランスをとる;
  • ホット キーをさまざまなサーバーに配布する;
  • セカンダリ キャッシュを使用する、つまり、 JVM ローカル キャッシュにより、Redis 読み取りリクエストが削減されます。

6. Redis の有効期限戦略とメモリ削除戦略

1Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

6.1 Redis の有効期限戦略

現在set key の場合、expire key 60 のように有効期限を設定できます。このキーが 60 秒後に期限切れになるように指定します。60 秒後に Redis はそれをどのように処理しますか?まず、いくつかの有効期限戦略を紹介します。

スケジュールされた有効期限

# 有効期限のあるキーごとにタイマーを作成する必要があり、有効期限に達するとキーはすぐにクリアされます。 。この戦略は期限切れのデータを即座にクリアでき、メモリに非常に優しいですが、期限切れのデータを処理するために大量の CPU リソースを占有するため、キャッシュの応答時間とスループットに影響します。

遅延有効期限

キーにアクセスしたときのみ、キーの有効期限が切れているかどうかを判定し、有効期限が切れたらキーをクリアします。この戦略は CPU リソースを最大限に節約できますが、メモリには非常に優しくありません。極端な場合には、期限切れの多数のキーに再度アクセスできなくなり、クリアされずに大量のメモリを占有してしまうことがあります。

定期的な有効期限

一定の時間ごとに、特定の数のデータベースの有効期限切れディクショナリ内の特定の数のキーがスキャンされ、期限切れのキーがクリアされます。 。この戦略は、最初の 2 つの戦略の折衷案です。スケジュールされたスキャンの時間間隔と各スキャンの制限された消費時間を調整することにより、さまざまな状況下で CPU とメモリのリソース間の最適なバランスを実現できます。

expires ディクショナリは、有効期限が設定されたすべてのキーの有効期限データを保存します (key はキー空間内のキーへのポインタ、value はミリ秒精度のキーの UNIX タイムスタンプ)。 。キースペースは、Redis クラスターに保存されているすべてのキーを指します。

Redis は、遅延有効期限と定期有効期限の両方を使用します2 つの有効期限戦略を使用します。

  • Redis には現在 300,000 個のキーが保存されており、すべてに有効期限が設定されていると仮定します。100 ミリ秒ごとにすべてのキーをチェックすると、CPU の負荷が非常に高くなり、最終的にはハングする可能性があります。
  • したがって、redis は定期的な有効期限を使用し、特定の数のキーをランダムに選択して 100 ミリ秒ごとにチェックして削除します。
  • ただし、最終的には、削除されずに期限切れのキーが多数存在する可能性があります。現時点では、redis は遅延削除を使用します。キーを取得すると、redis がそれをチェックします。キーに有効期限が設定されており、有効期限が切れている場合は、この時点で削除されます。

ただし、通常の削除で期限切れのキーが多数失われる場合、遅延削除は実行されません。メモリには期限切れのキーが大量に蓄積され、メモリの爆発の直接の原因となります。あるいは、業務量が増加すると、Redis キーが頻繁に使用され、単純にメモリが不足し、運用保守担当者がメモリの増設を忘れることもあります。 Redis はこのままハングアップしてしまうのでしょうか?しない! Redis は、自身を保護するために 8 つのメモリ削除戦略を使用します~

6.2 Redis のメモリ削除戦略

  • volatile-lru: メモリが新しく書き込まれたデータを収容するのに十分でない場合、有効期限が切れたキーには LRU (最も最近使用されていない) アルゴリズムを使用します;
  • allkeys-lru: メモリが新しく書き込まれたデータを収容するのに不十分な場合は、すべてのキーから LRU (最も最近使用されていない) アルゴリズムを使用します消去法を実行します。
  • volatile-lfu: バージョン 4.0 で新たに追加され、メモリが新しく書き込まれたデータを収容するのに不十分な場合、LFU アルゴリズムを使用して期限切れのキーの中からキーを削除します。
  • allkeys-lfu: バージョン 4.0 で新たに追加され、メモリが新しく書き込まれたデータを収容するのに十分でない場合、LFU アルゴリズムを使用してすべてのキーが削除されます;
  • volatile-random:メモリが不足している場合 新しく書き込まれたデータを収容する場合、有効期限を設定してキーからデータをランダムに削除します。
  • allkeys-random: メモリが新しく書き込まれたデータを収容するのに不十分な場合、データはすべてのキーからランダムに削除されます。
  • volatile-ttl: メモリが新しく書き込まれたデータを収容するのに十分ではない場合、有効期限が設定されているキーは有効期限に従って削除され、有効期限の早いキーが最初に削除されます。
  • noeviction: デフォルト ポリシー。メモリが新しく書き込まれたデータを収容するのに十分でない場合、新しい書き込み操作はエラーを報告します。

7. Redis の一般的なアプリケーション シナリオについて説明します

  • キャッシュ
  • ランキング
  • カウンター アプリケーション
  • 共有セッション
  • 分散ロック
  • ソーシャル ネットワーク
  • メッセージ キュー
  • ビット操作

7.1 キャッシュ

redis というと当然キャッシュが思い浮かびますが、国内外の中大規模の Web サイトはキャッシュと切っても切れない関係にあります。ホットスポット データのキャッシュなど、キャッシュを適切に使用すると、Web サイトのアクセス速度が向上するだけでなく、データベース DB への負荷も軽減されます。さらに、memcached と比較して、Redis は豊富なデータ構造も提供し、RDB や AOF などの最も強力な永続化メカニズムも提供します。

7.2 ランキング

現在のインターネットアプリケーションには、ECサイトの月次売上ランキング、ソーシャルAPPのプレゼントランキング、ミニプログラムの投票ランキングなど、さまざまなランキングが存在します。すぐ。 Redis が提供する zset データ型は、これらの複雑なランキングを実装できます。

たとえば、ユーザーが毎日ビデオをアップロードする場合、「いいね!」のランキング リストは次のように設計できます。

  • 1.用户Jay上传一个视频,获得6个赞,可以酱紫:
zadd user:ranking:2021-03-03 Jay 3
    1. 过了一段时间,再获得一个赞,可以这样:
zincrby user:ranking:2021-03-03 Jay 1
    1. 如果某个用户John作弊,需要删除该用户:
zrem user:ranking:2021-03-03 John
    1. 展示获取赞数最多的3个用户
zrevrangebyrank user:ranking:2021-03-03 0 2

7.3 计数器应用

各大网站、APP应用经常需要计数器的功能,如短视频的播放数、电商网站的浏览数。这些播放数、浏览数一般要求实时的,每一次播放和浏览都要做加1的操作,如果并发量很大对于传统关系型数据的性能是一种挑战。Redis天然支持计数功能而且计数的性能也非常好,可以说是计数器系统的重要选择。

7.4 共享Session

如果一个分布式Web服务将用户的Session信息保存在各自服务器,用户刷新一次可能就需要重新登录了,这样显然有问题。实际上,可以使用Redis将用户的Session进行集中管理,每次用户更新或者查询登录信息都直接从Redis中集中获取。

7.5 分布式锁

几乎每个互联网公司中都使用了分布式部署,分布式服务下,就会遇到对同一个资源的并发访问的技术难题,如秒杀、下单减库存等场景。

  • 用synchronize或者reentrantlock本地锁肯定是不行的。
  • 如果是并发量不大话,使用数据库的悲观锁、乐观锁来实现没啥问题。
  • 但是在并发量高的场合中,利用数据库锁来控制资源的并发访问,会影响数据库的性能。
  • 实际上,可以用Redis的setnx来实现分布式的锁。

7.6 社交网络

赞/踩、粉丝、共同好友/喜好、推送、下拉刷新等是社交网站的必备功能,由于社交网站访问量通常比较大,而且传统的关系型数据不太适保存 这种类型的数据,Redis提供的数据结构可以相对比较容易地实现这些功能。

7.7 消息队列

消息队列是大型网站必用中间件,如ActiveMQ、RabbitMQ、Kafka等流行的消息队列中间件,主要用于业务解耦、流量削峰及异步处理实时性低的业务。Redis提供了发布/订阅及阻塞队列功能,能实现一个简单的消息队列系统。另外,这个不能和专业的消息中间件相比。

7.8 位操作

用于数据量上亿的场景下,例如几亿用户系统的签到,去重登录次数统计,某用户是否在线状态等等。腾讯10亿用户,要几个毫秒内查询到某个用户是否在线,能怎么做?千万别说给每个用户建立一个key,然后挨个记(你可以算一下需要的内存会很恐怖,而且这种类似的需求很多。这里要用到位操作——使用setbit、getbit、bitcount命令。原理是:redis内构建一个足够长的数组,每个数组元素只能是0和1两个值,然后这个数组的下标index用来表示用户id(必须是数字哈),那么很显然,这个几亿长的大数组就能通过下标和元素值(0和1)来构建一个记忆系统。

8. Redis 的持久化机制有哪些?优缺点说说

Redis是基于内存的非关系型K-V数据库,既然它是基于内存的,如果Redis服务器挂了,数据就会丢失。为了避免数据丢失了,Redis提供了持久化,即把数据保存到磁盘。

Redis提供了RDB和AOF两种持久化机制,它持久化文件加载流程如下:

1Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

8.1 RDB

RDB,就是把内存数据以快照的形式保存到磁盘上。

什么是快照?可以这样理解,给当前时刻的数据,拍一张照片,然后保存下来。

RDB持久化,是指在指定的时间间隔内,执行指定次数的写操作,将内存中的数据集快照写入磁盘中,它是Redis默认的持久化方式。执行完操作后,在指定目录下会生成一个dump.rdb文件,Redis 重启的时候,通过加载dump.rdb文件来恢复数据。RDB触发机制主要有以下几种:

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

RDB 的优点

  • 适合大规模的数据恢复场景,如备份,全量复制等

RDB缺点

  • リアルタイムの永続性/第 2 レベルの永続性を実現する方法はありません。
  • 古いバージョンと新しいバージョンには RDB 形式の互換性の問題があります

AOF

##AOF (追加のみのファイル) ログ形式の永続性各書き込み操作を記録してファイルに追加し、AOF ファイル内のコマンドを再実行して、再起動時にデータを回復します。これは主にデータの永続性に関するリアルタイムの問題を解決します。デフォルトでは有効になっていません。

AOF のワークフローは次のとおりです。

1Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

AOF の利点

    データの一貫性とより高い整合性

AOF の欠点

    AOF が記録するコンテンツが増えると、ファイルが大きくなり、データの回復が遅くなります。
9. Redis の高可用性を実現するにはどうすればよいですか?

プロジェクトで Redis を使用する場合、単一ポイントで Redis サービスをデプロイすることは絶対にありません。シングルポイント展開が停止すると、利用できなくなるためです。高可用性を実現するには、データベースの複数のコピーをコピーし、それらを異なるサーバーに展開するのが一般的で、いずれかのサーバーに障害が発生した場合でも、そのサーバーはサービスを提供し続けることができます。 Redis が高可用性を実現するには、

マスター/スレーブ モード、センチネル モード、およびクラスター モードという 3 つのデプロイメント モードがあります。

9.1 マスター/スレーブ モード

マスター/スレーブ モードでは、Redis は複数のマシンをデプロイします。マスター ノードは読み取りおよび書き込み操作を担当し、スレーブ ノードは読み取り操作のみを担当します。スレーブ ノードのデータはマスター ノードから取得されます。実装原理は次のとおりです。

マスター/スレーブ レプリケーション メカニズム

マスター/スレーブ レプリケーションには、フル レプリケーションと増分レプリケーションが含まれます。一般に、スレーブが初めてマスターに接続を開始する場合、または初めての接続とみなされる場合は、

フル コピーが使用されます。フル コピー プロセスは次のとおりです:

1Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

    1.スレーブはマスターに同期コマンドを送信します。
  • 2. マスターは SYNC コマンドを受信した後、bgsave コマンドを実行して完全な RDB ファイルを生成します。
  • 3. マスターはバッファを使用して、RDB スナップショットの生成中にすべての書き込みコマンドを記録します。
  • 4. マスターは bgsave を実行した後、RDB スナップショット ファイルをすべてのスレーブに送信します。
  • 5. スレーブは RDB スナップショット ファイルを受信した後、受信したスナップショットをロードして解析します。
  • 6. マスターはバッファを使用して、RDB 同期中に生成されたすべての書き込みコマンドを記録します。
  • 7.マスター スナップショットが送信された後、バッファ内の書き込みコマンドをスレーブに送信し始めます。
  • 8.salve はコマンド リクエストを受け入れ、マスターからの書き込みコマンドを実行します。 buffer
redis のバージョン 2.8 以降では、sync コマンドはシステム リソースを消費し、psync の方が効率的であるため、

psync が sync の代わりに使用されています。

スレーブがマスターと完全に同期した後、マスター上のデータが再度更新されると、

増分レプリケーションがトリガーされます。

マスター ノードでデータが増加または減少すると、

replicationFeedSalves() 関数がトリガーされます。その後マスター ノードで呼び出される各コマンドは、replicationFeedSlaves()スレーブノードと同期します。この関数を実行する前に、マスターノードはユーザーが実行したコマンドにデータ更新があるかどうかを判断し、データ更新があり、スレーブノードが空でなければ、この関数が実行されます。この関数の機能は次のとおりです。 ユーザーが実行したコマンドをすべてのスレーブ ノードに送信します。そして、スレーブ ノードに実行させます。プロセスは次のとおりです。

1Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

9.2 センチネル モード

マスター/スレーブ モードでは、障害によりマスター ノードがサービスを提供できなくなった場合、マスター ノードは次のことを行う必要があります。スレーブ ノードからマスター ノードに手動で昇格し、マスター ノードのアドレスを更新するようにアプリケーション側に通知します。明らかに、この障害処理方法は、ほとんどのビジネス シナリオでは受け入れられません。 Redis は、この問題を解決するために、2.8 以降、Redis Sentinel (Sentinel) アーキテクチャを正式に提供しています。

Sentinel モード: 1 つ以上の Sentinel インスタンスで構成される Sentinel システム。すべての Redis マスター ノードとスレーブ ノードを監視でき、監視対象のマスター ノードが は、オフライン マスター サーバーの下のスレーブ ノードを新しいマスター ノード に自動的にアップグレードします。ただし、センチネル プロセスが Redis ノードを監視する場合、問題が発生する可能性があります (単一点の問題 )。そのため、複数のセンチネルを使用して Redis ノードを監視することができ、各センチネル間で継続的な通信が行われます。

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

簡単に言えば、センチネル モードには 3 つの機能があります:

    コマンドを送信し、Redis サーバー (マスター サーバーとスレーブを含む) を待ちます。サーバー) を返し、その実行ステータスを監視します。
  • Sentinel はマスター ノードがダウンしていることを検出し、スレーブ ノードからマスター ノードに自動的に切り替え、パブリッシュおよびサブスクライブ モードを通じて他のスレーブ ノードに通知します。構成ファイルを変更してホストを切り替えます。
  • Sentinel は高可用性を実現するために相互監視も行います。

フェイルオーバー プロセスとは何ですか?

メイン サーバーがダウンし、Sentinel 1 がこの結果を最初に検出すると仮定します。システムはすぐにフェイルオーバー プロセスを実行しません。これは、Sentinel 1 が主観的にメイン サーバーが利用できないと信じているだけです。この現象は、主観的なオフライン。後続のセンチネルもメイン サーバーが利用できないことを検出し、その数が特定の値に達すると、センチネル間で投票が行われ、投票の結果に従って 1 つのセンチネルがフェイルオーバー操作を実行します。切り替えが成功すると、各センチネルはパブリッシュ/サブスクライブ モードを使用して、監視するスレーブ サーバーをホストに切り替えます。このプロセスは、客観的オフラインと呼ばれます。このようにして、クライアントに対してすべてが透過的になります。

Sentinel の動作モードは次のとおりです:

  • 各 Sentinel は、マスター、スレーブ、および既知の他の Sentinel インスタンスに 1 秒に 1 回程度メッセージを送信します。 PING コマンド。

  • PING コマンドに対する最後の有効な応答からの時間が、down-after-milliseconds オプションで指定された値を超えた場合、インスタンスは Sentinel によって主観的にオフラインとしてマークされます。

  • マスターが主観的オフラインとしてマークされている場合、マスターを監視しているすべてのセンチネルは、マスターが実際に主観的オフライン状態に入ったことを 1 秒に 1 回確認する必要があります。

  • 十分な数のセンチネル (設定ファイルで指定された値以上) が、マスターが指定された時間範囲内に実際に主観的オフライン状態に入ったことを確認すると、マスターはオフラインの目標としてマークされます。

  • 通常の状況では、各センチネルは、10 秒に 1 回、知っているすべてのマスターとスレーブに INFO コマンドを送信します。

  • マスターが Sentinel によって客観的にオフラインとしてマークされると、Sentinel がオフライン マスターのすべてのスレーブに INFO コマンドを送信する頻度が 10 秒に 1 回から 1 秒に 1 回に変更されます

  • マスターがオフラインであることに同意する十分なセンチネルがいない場合、マスターの客観的なオフライン ステータスは削除されます。マスターがセンチネルの PING コマンドに対して有効な応答を返した場合、マスターの主観的なオフライン ステータスは削除されます。オフラインステータスが削除されます。ステータスが削除されます。

9.3 クラスタクラスタモード

センチネルモードは、マスター/スレーブモードをベースにしており、読み取りと書き込みの分離を実現しており、自動的に切り替えることもでき、システムの可用性を向上させることができます。より高い。ただし、各ノードに保存されるデータは同じであるため、メモリを無駄に消費し、オンラインで拡張するのは簡単ではありません。 そこで、Redis3.0 で追加され、Redis の 分散ストレージ が実装された Cluster クラスターが登場しました。データをセグメント化します。これは、オンライン拡張の問題を解決するために、 各 Redis ノードが異なるコンテンツを格納することを意味します。さらに、レプリケーションおよびフェイルオーバー機能も提供します。

クラスタークラスターノードの通信

Redisクラスターは複数のノードで構成されます。

各ノードはどのように通信しますか? ゴシッププロトコルを通じて!

Redis Cluster クラスターは Gossip プロトコルを通じて通信します。ノードは継続的に情報を交換します。交換される情報には、ノードの障害、新しいノードの参加、マスター/スレーブ ノードの変更情報、スロット情報などが含まれます。一般的に使用されるゴシップ メッセージは、ping、pong、meet、fail の 4 つのタイプに分類されます。

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

#meet メッセージ: 新しいノードに参加するよう通知します。メッセージ送信者は受信者に現在のクラスタへの参加を通知し、meet メッセージ通信が正常に完了すると、受信ノードはクラスタに参加し、定期的な ping および pong メッセージ交換を実行します。
  • Ping メッセージ: クラスター内で最も頻繁に交換されるメッセージ。クラスター内の各ノードは、他の複数のノードに毎秒 ping メッセージを送信します。これは、ノードがオンラインかどうかを検出し、ステータス情報を相互に交換するために使用されます。 。
  • pong メッセージ: ping または meets メッセージを受信すると、メッセージが正常に通信されたことを確認するための応答メッセージとして送信者に返信します。 pong メッセージは、独自のステータス データを内部的にカプセル化します。ノードは、自身の pong メッセージをクラスターにブロードキャストして、クラスター全体にステータスを更新するように通知することもできます。
  • 失敗メッセージ: ノードは、クラスター内の別のノードがオフラインであると判断すると、クラスターに失敗メッセージをブロードキャストします。失敗メッセージを受信した後、他のノードは、対応するノードをオフライン状態に更新します。
特に、各ノードは
クラスターバス(クラスターバス)

を介して他のノードと通信します。通信する場合は、外部サービスのポート番号に 10000 を加えた特別なポート番号を使用します。たとえば、ノードのポート番号が 6379 の場合、他のノードとの通信に使用するポート番号は 16379 になります。ノード間の通信には特別なバイナリ プロトコルが使用されます。 ハッシュ スロット スロット アルゴリズム

分散ストレージなので、クラスター クラスターで使用される分散アルゴリズムは

Consistent Hash

ですか?いいえ、ただし ハッシュ スロット スロット アルゴリズム

スロット アルゴリズムデータベース全体は 16384 個のスロット (スロット) に分割されており、Redis に入力される各キーと値のペアはキーに従ってハッシュされ、16384 個のスロットの 1 つに割り当てられます。使用されるハッシュ マップも比較的単純で、CRC16 アルゴリズムを使用して 16 ビット値を計算し、その後 16384 を法とします。データベース内の各キーはこれら 16384 個のスロットの 1 つに属し、クラスター内の各ノードはこれらの 16384 個のスロットを処理できます。

クラスター内の各ノードは、ハッシュ スロットの一部を担当します。たとえば、現在のクラスターにはノード A、B、および C があり、各ノードのハッシュ スロットの数 = 16384/3、

  • ノード A はハッシュ スロット 0 ~ 5460 を担当します。
  • ノード B はハッシュ スロット 5461 ~ 10922 を担当します。
  • ノード C はハッシュ スロットを担当します。ハッシュスロット 10923~16383

Redis Cluster Cluster

Redis Cluster クラスターでは、16384 スロットに対応するノードが正常に動作していることを確認する必要があります。場合、担当するスロットも失敗し、クラスター全体が機能しなくなります。

したがって、高可用性を確保するために、クラスター クラスターではマスター/スレーブ レプリケーションが導入され、1 つのマスター ノードが 1 つ以上のスレーブ ノードに対応します。他のマスター ノードがマスター ノード A に ping を実行するときに、マスター ノードの半分以上が A との通信がタイムアウトになると、マスター ノード A はダウンしていると見なされます。マスター ノードがダウンすると、スレーブ ノードが有効になります。

Redis の各ノードには 2 つのものがあり、1 つはスロットで、その値の範囲は 016383 です。もう 1 つはクラスターで、クラスター管理プラグインとして理解できます。アクセスするキーが到着すると、Redis は CRC16 アルゴリズムに基づいて 16 ビット値を取得し、結果のモジュロ 16384 を取得します。 Jiangzi の各キーは、016383 の間の番号が付けられたハッシュ スロットに対応します。この値を使用して、対応するスロットに対応するノードを見つけ、アクセスするために対応するノードに自動的にジャンプします。

データは異なるノードに個別に保存されますが、クライアントにとってはクラスター全体が 1 つの全体として認識されます。クライアントは任意のノードに接続し、Redis の単一インスタンスを操作しているように見えます。クライアントが操作したキーが正しいノードに割り当てられていない場合、Redis はリダイレクト命令を返し、最終的に正しいノードをポイントします。これはブラウザー ページの 302 リダイレクト ジャンプに似ています。

2Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

フェイルオーバー

Redis クラスターは高可用性を実現します。クラスター内のノードに障害が発生した場合、フェイルオーバーを使用して、クラスターが確実にサービスを提供できるようにします。通常は外部サービス。

redis クラスターは、ping/pong メッセージを通じて障害の検出を実現します。この環境には、主観的なオフラインと客観的なオフラインが含まれます。

主観的オフライン: ノードは、別のノードが利用できない、つまりオフライン状態であると考えます。この状態は最終的な障害判断ではなく、1 つのノードの意見のみを表すことができます。状況判断を誤る。

2Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

目標オフライン: ノードが実際にオフラインであることを示します。クラスター内の複数のノードは、そのノードが利用できないと考えており、コンセンサスに達します。結果。スロットを保持しているマスター ノードに障害が発生した場合、そのノードに対してフェイルオーバーを実行する必要があります。

  • ノード A がノード B を主観的にオフラインとしてマークした場合、一定時間が経過すると、ノード A はメッセージを通じてノード B のステータスを他のノードに送信します。ノード C がメッセージを受信して​​メッセージ本文を解析すると、 、ノード B の pfail ステータスが検出された場合、目的のオフライン プロセスがトリガーされます;
  • マスター ノードがオフラインの場合、Redis Cluster クラスターはスロットを保持しているマスター ノードの投票をカウントして、スロットを保持しているかどうかを確認します。投票数が半分に達し、オフライン レポートの統計が半分を超えると、目標オフライン ステータスとしてマークされます。

プロセスは次のとおりです:

2Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

障害回復: 障害が発見された後、オフライン ノードがクラスターの高可用性を確保するには、マスター ノードのいずれかを選択して置き換える必要があります。プロセスは次のとおりです。

2Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

  • 資格チェック: スレーブ ノードが障害が発生したマスター ノードを置き換える条件を備えているかどうかを確認します。
  • 選出時間の準備: 資格チェックに合格した後、障害選出をトリガーする時間を更新します。
  • 選挙の開始: フォールト選挙の時間が来たら、選挙を実行します。
  • 選挙投票: スロットを保持している マスター ノード のみが投票を持ちます。スレーブ ノードから十分な投票 (半分以上) が収集された場合、マスター ノードの操作の置換が行われます。

10. Redis 分散ロックを使用したことがありますか?注意すべき点は何ですか?

分散ロックは、分散システム内のさまざまなプロセスを制御して共有リソースに共同でアクセスするロックの実装です。ビジネス シナリオ (フラッシュ販売注文の発行、赤い封筒の取得など) ではすべて、分散ロックの使用が必要です。Redis は、私たちのプロジェクトで分散ロックとしてよく使用されます。

选了Redis分布式锁的几种实现方法,大家来讨论下,看有没有啥问题哈。

  • 命令setnx + expire分开写
  • setnx + value值是过期时间
  • set的扩展命令(set ex px nx)
  • set ex px nx + 校验唯一随机值,再删除

10.1 命令setnx + expire分开写

if(jedis.setnx(key,lock_value) == 1){ //加锁
    expire(key,100); //设置过期时间
    try {
        do something  //业务请求
    }catch(){
  }
  finally {
       jedis.del(key); //释放锁
    }
}

如果执行完setnx加锁,正要执行expire设置过期时间时,进程crash掉或者要重启维护了,那这个锁就“长生不老”了,别的线程永远获取不到锁啦,所以分布式锁不能这么实现。

10.2 setnx + value值是过期时间

long expires = System.currentTimeMillis() + expireTime; //系统时间+设置的过期时间
String expiresStr = String.valueOf(expires);

// 如果当前锁不存在,返回加锁成功
if (jedis.setnx(key, expiresStr) == 1) {
        return true;
} 
// 如果锁已经存在,获取锁的过期时间
String currentValueStr = jedis.get(key);

// 如果获取到的过期时间,小于系统当前时间,表示已经过期
if (currentValueStr != null && Long.parseLong(currentValueStr) < System.currentTimeMillis()) {

     // 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间(不了解redis的getSet命令的小伙伴,可以去官网看下哈)
    String oldValueStr = jedis.getSet(key_resource_id, expiresStr);
    
    if (oldValueStr != null && oldValueStr.equals(currentValueStr)) {
         // 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才可以加锁
         return true;
    }
}
        
//其他情况,均返回加锁失败
return false;
}

笔者看过有开发小伙伴是这么实现分布式锁的,但是这种方案也有这些缺点

  • 过期时间是客户端自己生成的,分布式环境下,每个客户端的时间必须同步。
  • 没有保存持有者的唯一标识,可能被别的客户端释放/解锁。
  • 锁过期的时候,并发多个客户端同时请求过来,都执行了jedis.getSet(),最终只能有一个客户端加锁成功,但是该客户端锁的过期时间,可能被别的客户端覆盖。

10.3: set的扩展命令(set ex px nx)(注意可能存在的问题)

if(jedis.set(key, lock_value, "NX", "EX", 100s) == 1){ //加锁
    try {
        do something  //业务处理
    }catch(){
  }
  finally {
       jedis.del(key); //释放锁
    }
}

这个方案可能存在这样的问题:

  • 锁过期释放了,业务还没执行完。
  • 锁被别的线程误删。

10.4 set ex px nx + 校验唯一随机值,再删除

if(jedis.set(key, uni_request_id, "NX", "EX", 100s) == 1){ //加锁
    try {
        do something  //业务处理
    }catch(){
  }
  finally {
       //判断是不是当前线程加的锁,是才释放
       if (uni_request_id.equals(jedis.get(key))) {
        jedis.del(key); //释放锁
        }
    }
}

在这里,判断当前线程加的锁和释放锁是不是一个原子操作。如果调用jedis.del()释放锁的时候,可能这把锁已经不属于当前客户端,会解除他人加的锁

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

一般也是用lua脚本代替。lua脚本如下:

if redis.call(&#39;get&#39;,KEYS[1]) == ARGV[1] then 
   return redis.call(&#39;del&#39;,KEYS[1]) 
else
   return 0
end;

这种方式比较不错了,一般情况下,已经可以使用这种实现方式。但是存在锁过期释放了,业务还没执行完的问题(实际上,估算个业务处理的时间,一般没啥问题了)。

11. 使用过Redisson嘛?说说它的原理

分布式锁可能存在锁过期释放,业务没执行完的问题。有些小伙伴认为,稍微把锁过期时间设置长一些就可以啦。其实我们设想一下,是否可以给获得锁的线程,开启一个定时守护线程,每隔一段时间检查锁是否还存在,存在则对锁的过期时间延长,防止锁过期提前释放。

当前开源框架Redisson就解决了这个分布式锁问题。我们一起来看下Redisson底层原理是怎样的吧:

2Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

只要线程一加锁成功,就会启动一个watch dog看门狗,它是一个后台线程,会每隔10秒检查一下,如果线程1还持有锁,那么就会不断的延长锁key的生存时间。因此,Redisson就是使用Redisson解决了锁过期释放,业务没执行完问题。

12. 什么是Redlock算法

Redis一般都是集群部署的,假设数据在主从同步过程,主节点挂了,Redis分布式锁可能会有哪些问题呢?一起来看些这个流程图:

2Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

如果线程一在Redis的master节点上拿到了锁,但是加锁的key还没同步到slave节点。恰好这时,master节点发生故障,一个slave节点就会升级为master节点。线程二就可以获取同个key的锁啦,但线程一也已经拿到锁了,锁的安全性就没了。

为了解决这个问题,Redis作者 antirez提出一种高级的分布式锁算法:Redlock。Redlock核心思想是这样的:

搞多个Redis master部署,以保证它们不会同时宕掉。并且这些master节点是完全相互独立的,相互之间不存在数据同步。同时,需要确保在这多个master实例上,是与在Redis单实例,使用相同方法来获取和释放锁。

我们假设当前有5个Redis master节点,在5台服务器上面运行这些Redis实例。

2Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

RedLock的实现步骤:如下

  • 1. 現在時刻をミリ秒単位で取得します。
  • 2. 5 つのマスター ノードに順番にロックを要求します。クライアントはネットワーク接続と応答のタイムアウトを設定します。タイムアウトはロックの有効期限よりも短くする必要があります。 (自動ロックの有効期限が 10 秒であると仮定すると、タイムアウト時間は通常 5 ~ 50 ミリ秒の間になります。タイムアウト時間が 50 ミリ秒であると仮定します)。タイムアウトになった場合は、マスター ノードをスキップして、できるだけ早く次のマスター ノードを試してください。
  • 3. クライアントは、現在時刻からロックの取得を開始した時刻 (つまり、手順 1 で記録された時刻) を引いた時刻を使用して、ロックの取得に使用された時間を取得します。 Redis マスター ノードの半分以上 (N/2 1、ここでは 5/2 1 = 3 ノード) がロックを取得し、使用時間がロックの有効期限よりも短い場合に限り、ロックは正常に取得されます。 (上の図に示すように、10 秒 > 30 ミリ秒 40 ミリ秒 50 ミリ秒 4 分 0 秒 50 ミリ秒)
  • ロックが取得されると、キーの実際の有効時間が変化するため、ロックを取得するのに費やした時間を差し引く必要があります。
  • ロックの取得が失敗した場合 (少なくとも N/2 1 マスター インスタンスでロックが取得されなかった場合、またはロックの取得時間が有効時間を超えた場合)、クライアントはすべてのマスター ノードでロックを解除する必要があります (たとえ一部のマスター ノードは正常にロックされていないため、魚がネットをすり抜けるのを防ぐためにロックを解除する必要があります)。

簡略化された手順は次のとおりです:

  • 5 つのマスター ノードに順番にロックを要求します
  • 設定されたタイムアウト時間に基づいて判断します。マスターノードをスキップしたいですか?
  • 3 ノード以上のロックが成功し、使用時間がロックの有効期間未満であれば、ロックは成功したと見なされます。
  • ロックの取得に失敗した場合は、ロックを解除してください。
#13. Redis のジャンプ テーブル

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

    ジャンプ テーブルは、順序付きセット zset
  • # の基礎となる実装の 1 つです。 # #スキップ テーブルは、平均
  • O(logN)
  • 、最悪の場合 O(N) の複雑さのノード検索をサポートし、順次操作を通じてノードをバッチで処理することもできます。 スキップ テーブルの実装は、
  • zskiplist と zskiplistNode
  • の 2 つの構造で構成されます。zskiplist はスキップ テーブル情報 (ヘッダー ノード、テール ノード、長さなど) を保存するために使用され、zskiplistNode は使用されます。 to スキップテーブルノードを表します。 スキップ リストはリンク リストに基づいており、検索効率を向上させるためにマルチレベルのインデックスが追加されています。
  • #14. MySQL と Redis が二重書き込みの一貫性を確保する方法

キャッシュの遅延二重削除

    キャッシュの再試行メカニズムの削除
  • Read biglog はキャッシュを非同期的に削除します
  • 14.1 二重削除が遅延していますか?
遅延二重削除とは何ですか?フローチャートは次のとおりです。

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)#最初にキャッシュを削除します

  • 次にデータベースを更新します

  • しばらく(たとえば 1 秒)スリープして、再度キャッシュを削除します。

  • これは一体どれくらいの時間眠るのでしょうか?全部1秒ですか?

このスリープ時間 = ビジネス ロジック データの読み取りにかかる時間は数百ミリ秒です。読み取りリクエストを確実に終了させるために、書き込みリクエストは、読み取りリクエストによってもたらされる可能性のあるキャッシュされたダーティ データを削除できます。

このソリューションは悪くありません。スリープ期間中 (たとえば、わずか 1 秒) に限り、ダーティ データが存在する可能性がありますが、一般の企業はそれを受け入れます。しかし、

2 番目のキャッシュの削除が失敗した場合はどうなるでしょうか

キャッシュとデータベースのデータがまだ不整合である可能性がありますよね?キーに自然な有効期限を設定して、自動的に期限切れになるようにしてはどうでしょうか?企業は有効期限内にデータの不整合を受け入れる必要がありますか?それとも他にもっと良い解決策があるのでしょうか?

14.2 キャッシュ削除の再試行メカニズム遅延二重削除はキャッシュ削除の 2 番目のステップで失敗し、データの不整合が発生する可能性があるためです。このソリューションを使用して最適化できます。削除が失敗した場合は、さらに数回削除して、キャッシュの削除が確実に成功するようにします。したがって、削除キャッシュの再試行メカニズムを導入できます

#データベース更新リクエストの書き込み3Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

  • 何らかの理由でキャッシュの削除に失敗しました

  • 失敗したキーを入力してくださいメッセージ キューへ

  • メッセージ キューからメッセージを消費し、削除するキーを取得します

  • #削除キャッシュ操作を再試行します
  • 14.3 biglog の読み取りとキャッシュの非同期削除
  • 削除キャッシュ メカニズムの再試行は問題ありませんが、大量の

    ビジネス コード侵入
  • を引き起こすことになります。実際、データベースのバイナリログを通じてキーを非同期的に削除するという方法で最適化することもできます。

mysql を例に挙げます

  • Alibaba の運河を使用して binlog ログを収集し、MQ キューに送信できます。
  • その後、ACK メカニズムを通じてこの更新メッセージを確認して処理し、キャッシュを削除し、データ キャッシュの一貫性を確保します

15. Redis 6.0 以降でマルチスレッドが変更されたのはなぜですか?

  • Redis 6.0 より前は、Redis がソケットの読み取り、解析、実行、ソケットの書き込みなどのクライアント リクエストを処理する場合、それらはすべてシーケンシャルでシリアルなメイン スレッドによって処理されていました。 「シングルスレッド」と呼ばれます。
  • Redis6.0 より前にマルチスレッドが使用されなかったのはなぜですか? Redis を使用する場合、CPU がボトルネックになる状況はほとんどなく、主にメモリとネットワークによって制限されます。たとえば、通常の Linux システムでは、Redis はパイプライン処理を使用して 1 秒あたり 100 万のリクエストを処理できるため、アプリケーションが主に O(N) または O(log(N)) コマンドを使用する場合、CPU をほとんど消費しません。

Redis によるマルチスレッドの使用は、シングル スレッドを完全に放棄するわけではありません。Redis は依然としてシングル スレッド モデルを使用してクライアント要求を処理します。データの読み取りと書き込みを処理するためにのみマルチ スレッドを使用します。コマンドを実行するには、依然としてシングルスレッドが使用されます。

この目的は、Redis のパフォーマンスのボトルネックが CPU ではなくネットワーク IO にあるためです。マルチスレッドを使用すると、IO の読み取りと書き込みの効率が向上し、それによって Redis の全体的なパフォーマンスが向上します。

16. Redis トランザクション メカニズムについて話しましょう

Redis は、MULTI、EXEC、WATCH などの一連のコマンドを通じてトランザクション メカニズムを実装します。トランザクションは一度に複数のコマンドの実行をサポートしており、トランザクション内のすべてのコマンドはシリアル化されます。トランザクション実行処理中、キュー内のコマンドは順番に実行され、他のクライアントから送信されたコマンド要求はトランザクション実行コマンドシーケンスに挿入されません。

つまり、Redis トランザクションは、キュー内の一連のコマンドを 順次、1 回限り、排他的に実行するものです。

Redis トランザクション実行のプロセスは次のとおりです。

    トランザクション開始 (MULTI)
  • コマンドエンキュー
  • トランザクション実行 (EXEC)、トランザクションのキャンセル (DISCARD)
コマンド説明EXEC トランザクション ブロック内のすべてのコマンドを実行します#DISCARDMULTIUNWATCHWATCH

17. Redis でハッシュの競合に対処する方法

K-V インメモリ データベースとして、Redis はグローバル ハッシュを使用してすべてのキーと値のペアを保存します。このハッシュ テーブルは複数のハッシュ バケットで構成されています。ハッシュ バケットのエントリ要素には、key および value ポインタが格納されます。*key は実際のキーを指し、*value は実際の値を指します。

3Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

ハッシュ テーブルの検索速度は非常に速く、Java の HashMap に似ており、O(1) の時間計算量でキーと値のペアをすばやく見つけることができます。まず、キーを通じてハッシュ値を計算し、対応するハッシュ バケットの場所を見つけて、次にエントリを見つけて、エントリ内の対応するデータを見つけます。

ハッシュ衝突とは何ですか?

ハッシュの競合: 同じハッシュ値が異なるキーを通じて計算され、結果として同じハッシュ バケットが生成されます。

ハッシュの競合を解決するために、Redis は チェーン ハッシュ を使用します。連鎖ハッシュとは、同じハッシュ バケット内の複数の要素がリンク リストに格納され、ポインタを使用して順番に接続されることを意味します。

3Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

#読者の中にはまだ疑問を持つ人もいるかもしれません。ハッシュ競合チェーン上の要素は、ポインターを介して 1 つずつ検索して操作することしかできません。大量のデータがハッシュ テーブルに挿入されると、競合が多くなり、競合リンク リストが長くなり、クエリの効率が低下します。

効率を維持するために、Redis は ハッシュ テーブルに対して再ハッシュ 操作を実行します。これは、ハッシュ バケットを追加して競合を減らすことを意味します。再ハッシュをより効率的にするために、Redis はデフォルトで 2 つのグローバル ハッシュ テーブルも使用します。1 つはメイン ハッシュ テーブルと呼ばれる現在使用用で、もう 1 つは拡張用であり、バックアップ ハッシュ テーブル と呼ばれます。

18. RDB の生成中に、Redis は書き込みリクエストを同時に処理できますか?

はい。Redis には、RDB を生成するための 2 つの命令 (save と bgsave) が用意されています。

    保存命令の場合、メインスレッドによって実行されるためブロックされます。
  • これが bgsave 命令の場合、RDB ファイルを書き込むために子プロセスをフォークします。スナップショットの永続化は子プロセスによって完全に処理され、親プロセスはクライアント要求の処理を続行できます。
19. Redis の下部ではどのようなプロトコルが使用されていますか?

RESP、英語の完全名は Redis Serialization Protocol で、Redis 用に特別に設計されたシリアル化プロトコルです。実はredisバージョン1.2からすでに登場していましたが、最終的にredis通信プロトコルの標準となったのはredis2.0になってからです。

RESP には、主に

シンプルな実装、高速な解析速度、優れた可読性 という利点があります。

20. ブルーム フィルター

キャッシュ侵入問題に対処するには、ブルーム フィルターを使用できます。ブルームフィルターとは何ですか?

ブルーム フィルターは、スペースをほとんど占有しないデータ構造です。長いバイナリ ベクトルと一連のハッシュ マッピング関数で構成されます。要素がセット、スペース内にあるかどうかを取得するために使用されます。効率とクエリ時間は一般的なアルゴリズムよりもはるかに優れていますが、一定の誤認識率と削除が難しいという欠点があります。

ブルームフィルターの原理は何ですか? 集合 A があり、A には n 個の要素があるとします。 k ハッシュ ハッシュ 関数を使用して、A の各要素 を配列 B の異なる位置にビット長でマップします。これらの位置の 2 進数は両方とも 1 に設定されます。チェック対象の要素がこれらの k 個のハッシュ関数によってマッピングされ、その k 位置の 2 進数 がすべて 1 であることが判明した場合、この要素は集合 A に属する可能性が高くなります。それ以外の場合、セット A に属してはなりません。 簡単な例を見てみましょう。セット A に 3 つの要素、つまり {

d1,d2,d3

} があるとします。ハッシュ関数は 1 つあり、Hash1 です。次に、A の各要素を長さ 16 ビットの配列 B にマップします。

#Hash1 (d1) = 2 と仮定して、d1 をマップします。次のように、配列 B の添え字 2 を持つグリッドを 1 に変更します。 Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)

Hash1(d2) = 5 と仮定して、3Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)d2

もマップします。次のように、配列 B の添字 5 を持つグリッドも 1 に変更します。

次に、ハッシュ 1 (d3) も 2 に等しいと仮定して、3Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)d3

をマッピングします。これにより、添え字も 2 グリッド マーク 1 に設定されます。

したがって、要素 dn が集合 A に含まれるかどうかを確認する必要があります。Hash1 (dn) で得られるインデックスの添え字を計算するだけで十分です。それが 0 である限り、要素 が集合 A に含まれていないことを意味します。セット A のインデックスの場合、添え字 1 はどうでしょうか?その場合、要素 は A の要素 である可能性があります。ご覧のとおり、d1 と d3 によって取得される添え字の値は両方とも 1 である場合もあれば、他の数値にマッピングされる場合もあります。ブルーム フィルターには 欠点があります: ハッシュ False が存在します。衝突による陽性 、判断に誤りがあります。

このエラーを減らす方法?

    より多くのハッシュ関数マッピングを構築して、ハッシュ衝突の可能性を低減します。
  • 同時に、B 配列のビット長を増やすと、ハッシュによって生成されるデータの範囲が広がる可能性があります。
  • #Hash2(d1)=6、Hash2(d3)=8 と仮定して、別の Hash2
ハッシュ マッピング

関数を追加します。以下のように、競合はありません。

Redis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)エラーがあったとしても、ブルーム フィルターが

完全なデータを保存していないことがわかります

、それは、一連のハッシュ マップ関数を使用して位置が計算され、バイナリ ベクトルが埋められるだけです。 数値が非常に大きいの場合、ブルーム フィルターは非常に低いエラー率で多くのストレージ スペースを節約でき、非常にコスト効率が高くなります。 現在、ブルーム フィルターを適切に実装するオープン ソース クラス ライブラリが存在します。たとえば、

Google の Guava クラス ライブラリ

、Twitter の Algebird クラス ライブラリなど、簡単に入手できるか、Redis 独自のクラス ライブラリに基づいています。ライブラリ ビットマップが独自のデザインを実装することも可能です。 プログラミング関連の知識について詳しくは、

プログラミング ビデオ

をご覧ください。 !

トランザクションをキャンセルし、トランザクション ブロック内のすべてのコマンドの実行を中止します
トランザクション ブロックの開始をマークします
WATCH コマンドによるすべてのキーの監視をキャンセルします。
キーを監視します。トランザクションの実行前に他のコマンドによってキーが変更された場合、トランザクションは中断されます。

以上がRedis に関する 20 の典型的な面接質問の要約と共有 (回答分析付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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