ホームページ  >  記事  >  データベース  >  Redis の 8 つの古典的な問題とは何ですか?

Redis の 8 つの古典的な問題とは何ですか?

王林
王林転載
2023-06-03 14:44:481210ブラウズ

1. Redis を使用する理由

ブロガーは、プロジェクトで Redis を使用する際の主な考慮事項はパフォーマンスと同時実行性であると考えています。もちろん、redisには分散ロックなど他の機能もありますが、分散ロックなど他の機能だけなら他のミドルウェア(zookpeerなど)があり、必ずしもredisを使う必要はありません。したがって、この質問には主にパフォーマンスと同時実行性という 2 つの観点から答えられます。

回答: 以下の 2 点に分かれます。

(1) 性能

実行時間がかかる場合SQL が非常に長く、結果が頻繁に変更されない場合は、結果をキャッシュに保存することをお勧めします。このようにして、後続のリクエストはキャッシュから読み取られるため、リクエストに迅速に応答できます。

Redis の 8 つの古典的な問題とは何ですか?

余談: 突然ですが、この迅速な対応の基準について話したいと思います。実際、相互作用の影響にもよりますが、この応答時間には一定の基準はありません。しかし、ある人は私にこう言いました。「理想的な世界では、ページジャンプは瞬時に解決される必要があり、ページ内操作も瞬時に解決される必要があります。最高のユーザーエクスペリエンスを提供するには、 1 秒を指定する必要があります。進行状況のプロンプトが表示され、いつでも中断またはキャンセルできます。」

それでは、一瞬、瞬間、または指を鳴らすのはどれくらいの時間ですか?

「マハ サンガ ヴィナヤ」の記録によると、

一瞬間は一念、二十念は一瞬間、二十瞬間は一指鳴らし、二十指鳴らしは一羅玉、二十羅 事前の予測は一瞬間、一日と一夜は三十瞬間です。

したがって、慎重に計算すると、1 つの瞬間は 0.36 秒、1 つの瞬間は 0.018 秒、指のフリックの長さは 7.2 秒になります。

(2) 同時実行数

下図に示すように、同時実行数が多い場合、すべてのリクエストがデータベースに直接アクセスすることになり、接続例外が発生します。データベース。この場合、リクエストがデータベースに直接アクセスするのではなく、最初に Redis にアクセスできるように、Redis バッファリング操作を使用する必要があります。

Redis の 8 つの古典的な問題とは何ですか?

2. Redis を使用するデメリットは何ですか

分析: 誰もが長い間 Redis を使用してきました。基本的に、redis を使用するといくつかの問題が発生しますが、一般的な問題はほんのわずかです。

回答: 主に 4 つの質問

(1) キャッシュとデータベースの二重書き込みの整合性の問題

(2) キャッシュ雪崩の問題

#(3) キャッシュの内訳の問題

(4) キャッシュの同時実行性の競合問題

これは個人的に感じていることです。これら 4 つの問題はプロジェクトで比較的よく見られますが、具体的な解決策は以下のとおりです。

「キャッシュ雪崩、キャッシュペネトレーション、キャッシュウォームアップ、キャッシュ更新、キャッシュダウングレード、その他の問題!」を参照してください。 》

3. シングルスレッド Redis はなぜ速いのですか?

分析: この質問は、実際には Redis の内部メカニズムの調査です。ブロガーのインタビュー経験によると、実際には多くの人が Redis のシングルスレッド作業モデルを理解していません。したがって、この問題は引き続き検討される必要があります。

回答:主に以下の 3 点です。

(1) 純粋なメモリ動作

(2) シングルスレッド動作、頻繁なコンテキスト切り替えを回避

(3) ノンブロッキング I/O 多重化メカニズムの使用

余談: このステートメントのため、I/O 多重化メカニズムについて詳しく説明する必要があります。これは非常に人気があるため、ほとんどのユーザーが人々はそれが何を意味するのか理解していません。ブロガーは、次のように例えました。Xiaoqu は、市内の速達サービスを担当する速達ストアを S 市にオープンしました。資金が限られていたため、Xiaoqu さんは当初、宅配業者のグループを雇いましたが、後に資金が不足しており、速達用の車しか購入できないことがわかりました。

ビジネス メソッド 1

顧客が宅配便を届けるたびに、Xiaoqu は宅配便を監視するように宅配便を割り当て、その後、宅配便が運転して宅配便を配達します。 。 Xiaoqu は、このビジネス手法に関する次の問題をゆっくりと発見しました。

  • 数十人の配達員が基本的に車の強盗に時間を費やしており、ほとんどの配達員がトラブルに見舞われていました。速達便を配達できます

  • 速達便の数が増えるにつれて、配達員もますます増えています。Xiaoqu さんは、速達便の店舗がますます混雑していることに気付きました。新しい配達員を雇うには

  • 配達員間の調整には非常に時間がかかります

上記の欠点に基づいて、Xiaoqu は経験から学び、次のことを提案しました。次のビジネス方法が採用されています

ビジネス方法 2

Xiaoqu は配達員を 1 人だけ雇います。 Xiaoquは、顧客が送った速達便に配達場所に応じてマークを付け、同じ場所に置きます。結局、宅配業者は荷物を一つずつ受け取り、車で配達に行き、配達後に次の荷物を取りに戻ってきました。

比較

上記 2 つのビジネス方法を比較すると、2 番目の方法の方が効率的で優れていることは明らかですか?上記の比喩では:

  • すべての配達員 ------------------> すべてのスレッド

  • 各エクスプレス-------------------->各ソケット (I/O ストリーム)

  • の配信場所速達-------------->ソケットのステータスが異なります

  • お客様納品依頼-------------->お客様からの依頼

  • Xiaoqu の営業方法 ---- ---------->サーバー上で実行されているコード

  • 車-------------- ---- --->CPU コアの数

したがって、次の結論が得られます

1. 最初のビジネス メソッドは、従来の同時実行モデルです。 (Express) は新しいスレッド (Expressor) によって管理されます。

2. 2 番目の管理方法は I/O 多重化です。各 I/O ストリームのステータス (各クーリエの配信場所) を追跡することによって複数の I/O ストリームを管理するスレッド (クーリエ) は 1 つだけです。

以下は、図に示す実際の Redis スレッド モデルとの類似です。

Redis の 8 つの古典的な問題とは何ですか?

上の図を参照してください。簡単に言うと、は。動作中に、Redis クライアントはさまざまなイベント タイプのソケットを作成します。サーバー側には、それをキューに入れる I/O 多重化プログラムがあります。次に、ファイル イベント ディスパッチャがキューからファイルを順番に取得し、別のイベント プロセッサに転送します。

この I/O 多重化メカニズムについて、redis は select、epoll、evport、kqueue などの多重化関数ライブラリも提供していることに注意してください。これについては自分で学ぶことができます。

4. Redis データ型と各データ型の使用シナリオ

分析: この質問は非常に基本的だと思いますか? 実際、私もそう思います。しかし、面接の経験によれば、少なくとも 80% の人がこの質問に答えることができません。プロジェクトで使用した後は、丸暗記するのではなく、類推して覚えるとより理解が深まるのでおすすめです。基本的に、資格のあるプログラマーは 5 つのタイプすべてを使用します。

答え: 合計 5 つのタイプがあります

(1) String

これは実際には非常に一般的で、最も基本的な get/set 操作が含まれます。 、値は文字列または数値です。一般に、一部の複雑なカウント関数はキャッシュされます。

(2)hash

ここの値には構造化オブジェクトが格納されており、その中の特定のフィールドを操作する方が便利です。ブロガーがシングル サインオンを行う場合、このデータ構造を使用してユーザー情報を保存し、cookieId をキーとして使用し、キャッシュの有効期限を 30 分に設定します。これにより、セッションのような効果を非常によくシミュレートできます。

(3)list

List のデータ構造を使用して、簡単なメッセージ キュー関数を実行できます。さらに、lrange コマンドを使用して Redis ベースのページング機能を実装することもでき、この方法はパフォーマンスとユーザー エクスペリエンスに優れています。

(4)set

set は非反復値のコレクションであるためです。したがって、グローバル重複排除機能を実現することができる。重複排除のために JVM に付属するセットを使用してみてはいかがでしょうか?システムは通常クラスタでデプロイされるため、JVM に付属の Set を使用するのは面倒ですが、グローバル重複排除を行うためだけにパブリック サービスをセットアップするのは面倒ですか?

さらに、交差、和集合、差分などの演算を使用して、共通の設定、すべての設定、および独自の設定を計算できます。

(5) ソート セット

ソート セットには追加の重みパラメータ スコアがあり、セット内の要素をスコアに従って配置できます。ランキングアプリを作成してTOPNを取ることができます。さらに、「分散遅延タスク スキームの分析」というタイトルの記事では、ソート セットを使用して遅延タスクを実装できることが述べられています。最後のアプリケーションは範囲検索を行うことです。

5. Redis の有効期限戦略とメモリ削除メカニズム

この問題の重要性は自明であり、Redis が使用されているかどうかでわかります。たとえば、Redis に 5 GB のデータしか保存できない場合、10 GB のデータを書き込むと、5 GB のデータが削除されます。どうやって削除しましたか? この問題について考えたことはありますか?また、データには有効期限が設定されていますが、期限が切れてもメモリ使用量はまだ比較的多くなっています。その理由について考えたことはありますか?

回答:

redis は定期的な削除を使用します。慣性削除ポリシー。

スケジュールされた削除戦略を使用してみてはいかがでしょうか?

スケジュールされた削除では、タイマーを使用してキーを監視し、期限が切れると自動的に削除されます。メモリは時間内に解放されますが、大量の CPU リソースを消費します。同時リクエストが多い場合、CPU はキー値の削除操作ではなくリクエストの処理に集中する必要があるため、この戦略の採用を断念しました。

定期的な削除と遅延削除はどのように機能しますか?

定期的に削除します。Redis はデフォルトで 100 ミリ秒ごとに期限切れのキーがあるかどうかを確認します。期限切れのキーがある場合は削除します。 redis は 100 ミリ秒ごとにすべてのキーをチェックするのではなく、ランダムにそれらを選択して検査することに注意してください (すべてのキーが 100 ミリ秒ごとにチェックされる場合、redis はスタックしないでしょうか)。定期的な削除戦略のみを使用する場合、多くのキーは有効期限が過ぎても削除されません。

そこで、遅延削除が便利です。つまり、有効期限が設定されている場合、キーを取得すると、Redis はキーの有効期限が切れているかどうかを確認します。有効期限が切れた場合は、この時点で削除されます。

定期削除と遅延削除には他に問題はありませんか?

いいえ、通常の削除中にキーが削除されなかった場合は。この場合、キーをすぐに要求しませんでした。つまり、遅延削除は有効になりませんでした。このようにして、redis のメモリはどんどん増えていきます。その場合は、メモリ削除メカニズムを採用する必要があります。

redis.conf には構成の行があります

# maxmemory-policy volatile-lru

この構成はメモリ削除戦略で構成されています (何、まだ設定しましたか? OK 反省してください)

1) noeviction: メモリが新しく書き込まれたデータを収容するのに十分でない場合、新しい書き込み操作はエラーを報告します。誰もそれを使用すべきではありません。

メモリ スペースが新しいデータを保存するのに不十分な場合、allkeys-lru アルゴリズムは、最も最近使用されていないキーをキー スペースから削除します。推奨されており、現在プロジェクトで使用されています。

3) allkeys-random: メモリが新しく書き込まれたデータを収容するのに不十分な場合、キーはキー空間からランダムに削除されます。誰も使用してはいけません。削除したくない場合は、少なくとも Key を使用してランダムに削除してください。

4) volatile-lru: メモリが新しく書き込まれたデータを収容するのに不十分な場合、有効期限が設定されたキー空間では、最も最近使用されていないキーが削除されます。通常、この方法は、redis がキャッシュと永続ストレージの両方として使用される場合にのみ使用されます。推奨されません

5) volatile-random: メモリが新しく書き込まれたデータを収容するのに不十分な場合、有効期限が設定されたキー空間からキーがランダムに削除されます。まだ推奨されません

6) volatile-ttl: メモリが新しく書き込まれたデータを収容するのに十分ではない場合、有効期限が設定されたキー空間では、有効期限が早いキーが最初に削除されます。推奨されません

ps: 有効期限キーが設定されておらず、前提条件が満たされていない場合、volatile-lru、volatile-random、および volatile-ttl 戦略の動作は基本的に noeviction と同じになります (削除されません)。 。

6. Redis とデータベースの二重書き込みの整合性の問題

分散システムでは、整合性の問題は一般的な問題です。この問題はさらに、結果整合性と強整合性に分類できます。データベースとキャッシュが二重に書き込まれている場合、必然的に不整合が発生します。この質問に答えるには、まず前提を理解する必要があります。つまり、データに強い整合性要件がある場合、そのデータをキャッシュすることはできません。私たちが行うすべてのことは、最終的な整合性を保証することしかできません。私たちが提案したソリューションは、実際には矛盾したイベントの確率を減らすだけで、完全に排除することはできません。したがって、強い整合性要件を持つデータはキャッシュできません。

ここでは、記事「分散データベースとキャッシュの二重書き込み一貫性スキームの分析」の詳細な分析を簡単に紹介します。まず、正しい更新戦略を採用し、最初にデータベースを更新してからキャッシュを削除します。キャッシュの削除に失敗した場合に備えて、メッセージキューを使用するなどのバックアップ措置を講じてください。

7. キャッシュペネトレーションとキャッシュアバランシェの問題に対処する方法

中小規模の従来型ソフトウェア会社が、正直に言うと、これら 2 つの問題に遭遇することはほとんどありません。大規模な同時プロジェクトがある場合、トラフィックは約数百万になります。この 2 つの問題を深く考慮する必要があります。

回答: 以下に示すように、

キャッシュ侵入、つまり、ハッカーはキャッシュに存在しないデータを意図的に要求し、すべての要求がデータベースであるため、データベース接続例外が発生します。

解決策:

キャッシュが失敗した場合は、まずミューテックス ロックを使用してロックを取得し、ロックを取得したらデータベースを要求します。ロックが取得できない場合は、一定期間スリープして再試行します。

(2) 非同期更新戦略を使用し、キーに値があるかどうかに関係なく直接戻ります。キャッシュの有効期限を値 value に保存します。キャッシュの有効期限が切れると、スレッドが非同期で開始され、データベースを読み取り、キャッシュを更新します。キャッシュの予熱(プロジェクト開始前にキャッシュをロードする)操作が必要です。

リクエストが有効かどうかを迅速に判断できるインターセプト メカニズムを提供します。たとえば、ブルーム フィルターを使用して、一連の合法的で有効なキーを内部的に維持します。リクエストに含まれるキーが合法かつ有効であるかどうかを迅速に判断します。違法な場合は直接返却してください。

キャッシュ雪崩、つまり広い範囲で同時にキャッシュに障害が発生し、その際にまたリクエストの波が押し寄せ、その結果、リクエストがすべてデータベースに送信され、異常なデータベース接続。

解決策:

(1) 集団的な失敗を避けるために、キャッシュの有効期限にランダムな値を追加します。

(2) ミューテックス ロックを使用しますが、このソリューションのスループットは大幅に低下します。

(3) ダブルバッファリング。キャッシュ A とキャッシュ B の 2 つのキャッシュがあります。キャッシュ A の有効期限は 20 分ですが、キャッシュ B の有効期限はありません。キャッシュのウォームアップ操作は自分で行ってください。次に、次の点を詳しく説明します。

  • I キャッシュ A からデータベースを読み取り、データがあれば直接返します。

  • II A にはデータがなく、キャッシュ A から直接返されます。 B はデータを読み取り、直接返し、更新スレッドを非同期で開始します。

  • III 更新スレッドは、キャッシュ A とキャッシュ B を同時に更新します。

8. Redis でのキーの同時競合の問題を解決する方法

分析: この問題は、大まかに言うと、複数のサブシステムが同時にキーを設定していることです。このとき私たちは何に注意すべきでしょうか?考えたことはありますか?事前に Baidu の検索結果を確認したところ、ブロガーはほぼすべての回答で Redis トランザクション メカニズムの使用を推奨していることがわかりました。ブロガーは、redis トランザクション メカニズムの使用を推奨していません。本番環境は基本的に Redis クラスター環境であるため、データのシャーディング操作が実行されます。 1 つのタスクに複数のキー操作が含まれる場合、これらのキーは必ずしも同じ Redis サーバーに保存されるとは限りません。したがって、redis のトランザクション機構は非常に役に立ちません。

答え: 以下のようになります。

(1) このキーを操作する場合、順序は必要ありません。

この場合、分散ロックの場合は全員でロックを掴み、ロックを掴んだらset操作を行うだけで比較的簡単です。

(2) このキーを操作すると、必要なシーケンスが実行されます。

key1 があり、システム A は key1 を valueA に設定する必要があり、システム B は key1 を valueB に設定する必要があり、システムC は key1 を valueB に設定する必要があります。key1 は valueC に設定されます。

key1 の値は、valueA->valueB->valueC の順序で変化することが予想されます。現時点では、データベースにデータを書き込むときにタイムスタンプを保存する必要があります。タイムスタンプが次のとおりであると仮定します。

システム A キー 1 {値A 3:00}

システム B キー 1 {値B 3:05}

システム C キー 1 { valueC 3: 10}

システム B が最初にロックを取得すると、key1 の値が {valueB 3:05} に設定されると想像してください。システム A がロックを取得したときに、システム A が格納している valueA のタイムスタンプがキャッシュに格納されているタイムスタンプよりも古いことが判明した場合、システム A は設定操作を実行しません。等々。

キューを使用したり、set メソッドをシリアル アクセスに変換したりするなど、他の方法も使用できます。要するに、柔軟になるということです。

以上がRedis の 8 つの古典的な問題とは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

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