1. Redis を使用する理由
プロジェクトで Redis を使用する場合、著者はパフォーマンスと同時実行性を考慮する必要があると考えています。もちろん、Redis には他にも分散ロックなどを実行できる機能がありますが、分散ロックなど他の機能だけであれば、代わりに使用できる他のミドルウェア (Zookpeer など) があり、 Redis を使用する必要はありません。
したがって、この質問には主にパフォーマンスと同時実行性の 2 つの観点から答えられます:
##1. パフォーマンス
次の図に示すように、特に長時間実行する必要があり、結果が頻繁に変更されない SQL が発生した場合、実行結果をキャッシュに入れるのが特に適しています。 。このようにして、後続のリクエストはキャッシュから読み取られるため、リクエストに迅速に応答できます。 余談: 突然、迅速な応答の基準について話したいと思います。実際、相互作用効果に応じて、この応答時間には固定された基準はありません。かつて誰かが私にこう言いました。「理想的には、ページジャンプは瞬時に完了し、ページ内操作も瞬時に完了する必要があります。」さらに、ユーザーに最高のエクスペリエンスを提供するために、指でスナップするだけでは済まない時間のかかる操作には進行状況を示すプロンプトが表示され、いつでも中断またはキャンセルできる必要があります。 「それでは、一瞬、一瞬、指を鳴らすとどれくらいの時間がかかるのでしょうか? 「マハ サンガ ヴィナヤ」の記録によると、1 つの瞬間は 1 つの思考、20 の思考は 1 つです瞬間と 20 秒は、指を鳴らすのは 1 回、指を 20 回鳴らすのは 1 ストローク、20 回のストロークは 1 瞬間、そして 1 日と 1 晩には 30 回の瞬間があります。 、1 つの瞬間は 0.36 秒、1 つの瞬間は 0.018 秒で、指を鳴らすと最大 7.2 秒になります。 同時実行性が非常に高い場合、図に示すように、データベースへの直接アクセスを要求するとデータベース接続例外が発生します。データベースへの直接アクセスを回避するには、Redis を使用できます。この場合はバッファリングを行い、リクエストが最初に Redis にアクセスできるようにします。 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 は経験から学び、次のビジネス方法を提案しました↓
ビジネス方法 2:
Xiaoqu は配達員を 1 人だけ雇い、顧客が送った速達便に次のようなマークを付けました。目的地まで、一か所にすっきりと収まります。最後に、宅配業者は荷物を 1 つずつ順番に受け取り、荷物を追い出し、次の荷物を取りに戻ります。 上記 2 つのビジネス方法を比較すると、2 番目の方法の方が効率的で優れていると思いますか?上記の例え:
1. 各クーリエ → 各スレッド 2. 各クーリエ → 各ソケット (I/O ストリーム)3. の配信場所速達 → ソケットのさまざまな状態
4. 速達を送信するという顧客のリクエスト → クライアントからのリクエスト
5. Xiaoqu のビジネス メソッド → ソケット上で実行されるコードサーバー
6. 1 台の車 → CPU コアの数
したがって、次の結論が得られます:
1. 最初のビジネス メソッドは、従来の同時実行モデルです。 ○フロー(急行) 管理する新しいスレッド(宅配便)があります。
2. 2 番目の管理方法は I/O 多重化です。宅配業者は、各 I/O フローのステータスを追跡することで複数の I/O フローを管理します。これは、各荷物を配達する担当者が 1 人だけで、各荷物の配送状況を把握する必要がある宅配業者に似ています。
次の図は、実際の Redis スレッド モデルと類似しています。
上の図を参照すると、簡単に言うと、次のようになります。私たちの Redis クライアントは動作中に、さまざまなイベント タイプのソケットが生成されます。サーバー側には、I/O をキューに入れる I/O 多重化プログラムがあります。次に、ファイル イベント ディスパッチャがキューからファイルを順番に取得し、別のイベント プロセッサに転送します。
なお、この I/O 多重化の仕組みについては、Redis からも Select、Epoll、Evport、Kqueue などの多重化関数ライブラリが提供されており、自分で学習することができます。
#4. Redis データ型とそれぞれの使用シナリオ
この質問を見たとき、とても基本的なことだと思いますか?実際、私もそう思います。しかし、面接の経験によれば、少なくとも 80% の人がこの質問に答えることができません。プロジェクトで使用した後は、暗記するのではなく、類推で覚えてより深い経験を積むことをお勧めします。基本的に、資格のあるプログラマは次の 5 つの型を使用します:1、String
これは実際には大したことはありません。最も一般的な Set/Get 操作では、Value は文字列または数値のいずれかになります。一般に、一部の複雑なカウント関数はキャッシュされます。2. ハッシュ
ここでの値は、特定のフィールドを簡単に操作できる構造化オブジェクトを含む変数です。初期化。作成者がシングル サインオンを実行している場合、このデータ構造を使用してユーザー情報を保存し、キーとして CookieId を使用し、キャッシュの有効期限として 30 分を設定します。これにより、セッションのような効果を非常によくシミュレートできます。3. List
List のデータ構造を使用して、簡単なメッセージ キュー関数を実行できます。さらに、Redis の Lrange コマンドを使用してページング機能を実装することもできます。これは優れたパフォーマンスを備え、優れたユーザー エクスペリエンスを提供できます。4. Set
Set は一意の値のコレクションをスタックするため、グローバルに使用できます 重複削除機能。 重複排除用に JVM に付属のセットを使用してみてはいかがでしょうか?通常、システムはクラスタでデプロイされているため、JVM に付属の Set を使用するのは面倒ですが、グローバルな重複排除を目的としたパブリック サービスを作成する必要がありますか?面倒すぎる。 さらに、交差、和集合、差分などの演算を使用して、共通の設定、すべての設定、および独自の設定を計算できます。5. ソート セット
Score パラメーターをセット内の要素に割り当てることで、ソート セットは次のことができます。要素はスコアに基づいて並べ替えられます。ランキングアプリを作成してTOPNを取ることができます。さらに、ソート セットを使用して、遅延タスクを実行することもできます。最後のアプリケーションは範囲検索を行うことです。#5. Redis の有効期限戦略とメモリ削除メカニズム
この質問の重要性は自明であり、Redis が正しく適用されているかどうかを明らかにすることができます。たとえば、Redis が 5G のデータしか保存できないときに 10G を書き込むと、5G のデータが削除されます。どのように削除されましたか?この問題について考えたことがありますか?また、データには有効期限が設定されていますが、期限が切れても、メモリ使用量はまだ比較的高いです。理由について考えたことはありますか?
Redis は、定期的な削除と遅延削除戦略を採用しています。
計画的な削除戦略を使用してみてはいかがでしょうか?定期的な削除、
タイマーを使用してキーを監視すると、有効期限が切れると自動的に削除されます。メモリは時間内に解放されますが、大量の CPU リソースを消費します。大規模な同時リクエストでは、CPU はキーを削除する代わりにリクエストの処理に時間を費やす必要があるため、この戦略は採用されません。
定期的な削除 遅延削除はどのように機能しますか?定期的な削除、
Redis はデフォルトで 100 ミリ秒ごとに期限切れのキーがあるかどうかを確認し、期限切れのキーがある場合は削除します。 Redis は 100 ミリ秒ごとにすべてのキーをチェックするのではなく、ランダムに選択してチェックすることに注意してください (すべてのキーが 100 ミリ秒ごとにチェックされる場合、Redis はスタックしません)。したがって、定期的な削除戦略のみを採用した場合、多くのキーは最後まで削除されません。 そこで、遅延削除が便利です。つまり、キーを取得すると、Redis は、このキーに有効期限が設定されている場合、有効期限が切れているかどうかを確認します。有効期限が切れた場合は、この時点で削除されます。
定期削除と遅延削除で他に問題はありませんか?いいえ、定期的に削除される場合、キーは削除されません。次に、時間内にキーを要求しませんでした。これは、遅延削除が有効にならなかったことを意味します。 Redis のメモリが継続的に増加するのを防ぐには、メモリ削除メカニズムを有効にする必要があります。
Redis.conf には設定の行があります:
# maxmemory-policy volatile-lru この設定にはメモリの削除が装備されています。 Strategy:Noeviction:メモリが新しく書き込まれたデータを収容するのに不十分な場合、新しい書き込み操作はエラーを報告します。誰もそれを使用すべきではありません; Allkeys-lru: 新しく書き込まれたデータを格納するにはメモリが不十分な場合、キー空間で、最も最近使用されていないキーを削除します。推奨、現在プロジェクトはこれを使用しています; Allkeys-random:メモリが新しく書き込まれたデータを収容するのに十分でない場合、キー空間でキーをランダムに削除する必要があります。誰も使用しません; Volatile-lru: メモリが新しく書き込まれたデータを収容するのに不十分な場合、有効期限が設定されたキー空間で、最も最近使用されていない Key を削除します。この状況は通常、Redis がキャッシュと永続ストレージの両方として使用される場合に使用されます。推奨されません; Volatile-random: メモリが新しく書き込まれたデータを収容するのに十分でない場合、キーは有効期限が設定されてキー空間からランダムに削除されます。まだ推奨されません; Volatile-ttl: メモリが新しく書き込まれたデータを収容するのに不十分な場合、有効期限が設定されたキー空間では、有効期限が早いキーが最初に移動されます。 。 取り除く。お勧めしません。 PS: Expire Key が設定されておらず、前提条件が満たされていない場合、Volatile-lru、Volatile-random、および Volatile-ttl 戦略の動作は基本的に Noeviction と同じになります (削除されません)。 #6. Redis とデータベースの二重書き込みの整合性の問題
#7. キャッシュペネトレーションとキャッシュアバランチの問題への対処
一般に、中小規模の従来型ソフトウェア会社は、キャッシュの侵入とキャッシュなだれという 2 つの問題に遭遇することはほとんどありません。数百万のトラフィックを処理したい場合は、次の 2 つの問題を慎重に考慮する必要があります:
#1. キャッシュ侵入への対処
#キャッシュ侵入とは、ハッカーがキャッシュに存在しないデータを意図的に要求し、すべての要求がデータベースに送信され、データベース接続が異常になることを意味します。 解決策: ミューテックス ロックを使用します。キャッシュが失敗した場合は、まずロックを取得します。ロックを取得したら、データベースを要求します。ロックが取得できない場合は、スリープ状態になります。一定期間待ってから再試行します; 1. 非同期更新戦略を採用し、キーに値があるかどうかに関係なく直接戻ります。キャッシュの有効期限は値の値で維持されます。キャッシュの有効期限が切れると、データベースを読み取り、キャッシュを更新するためにスレッドが非同期的に開始されます。キャッシュのウォームアップ操作 (プロジェクトを開始する前にキャッシュをロードする) が必要です。 2. ブルーム フィルターを使用して一連の合法的で有効なキーを内部的に維持し、リクエストに含まれるキーが合法であるかどうかを迅速に判断するなど、リクエストが有効かどうかを迅速に判断できる傍受メカニズムを提供します。有効でない場合は、直接返されます。
#2. キャッシュなだれへの対処
キャッシュなだれ、つまり、次の時点で広い領域でキャッシュが失敗します。このとき、再度リクエストの波が来て、リクエストがすべてデータベースに送信され、データベース接続が異常になりました。 解決策: 1. 集団的な失敗を避けるために、キャッシュの有効期限にランダムな値を追加します; 2. ミューテックス ロックを使用しますが、このソリューションのスループットは大幅に減少しました; 3. ダブルバッファリング。キャッシュ A とキャッシュ B の 2 つのキャッシュがあります。キャッシュ A の有効期限は 20 分で、キャッシュ B には有効期限はありません。キャッシュの予熱操作は単独で実行されます。 次に、次の点を詳しく説明します: a. キャッシュ A からデータベースを読み取り、存在する場合は直接返します;b. A にキャッシュがある場合は、データなし、直接返す B からデータを読み取り、直接返す、更新スレッドを非同期で開始する;
8. Redis 同時実行競争の主要な問題を解決する方法
この問題は、大まかに言うと、複数のサブシステムが同時にキーを設定していることです。この場合、Redis トランザクション メカニズムを使用するように注意する必要があります。事前に百度で検索した結果では、この方法を推奨している人が多かったです。ただし、Redis のトランザクション メカニズムを使用することはお勧めしません。主に本番環境では Redis クラスターを使用し、データシャーディングを実行します。トランザクションに複数のキー操作が含まれる場合、これらのキーは必ずしも同じ Redis サーバーに保存されるとは限りません。したがって、Redis のトランザクション メカニズムは非常に役に立ちません。 解決策は次のとおりです。
このキー操作の順序が必要ない場合は、
この場合、全員に分散ロックを準備します。ロックを取得するには、ロックを取得するときに Set 操作を実行するだけです。これは比較的簡単です。
このキー操作にシーケンスが必要な場合
Key1 があるとします。システム A は Key1 を ValueA に設定する必要があり、システム B は Key1 を ValueB に設定する必要があり、システム C は Key1 を ValueC に設定する必要があります。 Key1の値がValueA→ValueB→ValueCの順に変化することが望まれます。現時点では、データベースにデータを書き込むときにタイムスタンプを保存する必要があります。タイムスタンプが次のとおりであると仮定します:
1. システム A キー 1 {ValueA 3:00}
2. システム B キー 1 {ValueB 3:05}
3. システム C キー 1 {ValueC 3:10}
したがって、システム B が最初にロックを取得し、Key1 を {ValueB 3:05} に設定すると仮定します。システム A がロックを取得し、ValueA のタイムスタンプがキャッシュ内のタイムスタンプよりも古いことが判明した場合、Set 操作は実行されません。等々。
以上がRedisの技術的なポイントは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。