1 Redis を使用する理由
プロジェクトで Redis を使用する場合、パフォーマンスと同時実行性という 2 つの主な考慮事項があります。分散ロックなど他の機能だけであれば、Zookpeerなど他のミドルウェアがあり、Redisを使用する必要はありません。
パフォーマンス:
以下の図に示すように、特に長時間実行する必要がある SQL が発生した場合に特に適しています。結果は頻繁に変更されません。実行結果をキャッシュに入れてください。このようにして、後続のリクエストはキャッシュから読み取られるため、リクエストに迅速に応答できます。
特にフラッシュ セール システムでは、ほぼ全員が同時にクリックして注文を行っています。 。 。同じ操作が実行され、データベースにデータがクエリされます。
インタラクション効果に応じて、応答時間の固定基準はありません。理想的な世界では、ページジャンプは瞬時に解決される必要があり、ページ内操作も瞬時に解決される必要があります。
同時実行数:
次の図に示すように、同時実行数が多い場合、すべてのリクエストがデータベースに直接アクセスし、データベースで接続例外が発生します。 。現時点では、リクエストがデータベースに直接アクセスするのではなく、最初に Redis にアクセスできるように、Redis を使用してバッファリング操作を実行する必要があります。
Redis の使用に関するよくある質問
- キャッシュとデータベースの二重書き込みの整合性の問題
- キャッシュ雪崩の問題
- キャッシュの故障問題
- キャッシュの同時実行性の競合問題
シングルスレッド Redis はなぜ速いのか
#この質問は、Redis の内部メカニズムの調査です。多くの人は、Redis にシングルスレッド動作モデルがあることを知りません。
その理由は主に次の 3 点によるものです。
純粋なメモリ操作- シングルスレッド操作により頻繁なコンテキスト切り替えが回避されます
-
ノンブロッキング I/O 多重化メカニズムの使用-
I/O 多重化メカニズムについて、例え話を使って詳しく説明します。Xiao Ming は A DianDian 市にファーストフードをオープンしました。市内のファーストフードサービスを担当しています。経済的制約のため、シャオミンさんは配達員を雇いましたが、シャオ・クーさんは資金が足りず、速達を届けるために車を買うしかないことに気づきました。
営業方法 1
顧客が注文するたびに、Xiao Ming は配達員に監視させ、その後誰かが運転して配達させます。 Xiaoqu は、この運用モードに関する次の問題をゆっくりと発見しました:
車を捕まえるのに時間がかかり、配達員のほとんどが暇でした。車を使って配達することもできます。
注文数が増加するにつれて、配達員の数も増加しました。Xiao Ming さんは、エクスプレス ストアがますます混雑しており、新しい配達員を雇う方法がないことに気づきました。 - 配達員間の調整に時間がかかります。
- 上記の欠点に基づいて、Xiao Ming は経験から学び、2 番目の管理方法を提案しました。
-
ビジネス メソッド 2
Xiao Ming では配達員を 1 人だけ雇用しています。顧客が注文すると、Xiao Ming は配達場所をマークし、1 か所に置きます。最後に配達員に車を運転して商品を1つずつ届けてもらい、配達後にまた次の商品を取りに来ます。上記 2 つのビジネス方法を比較すると、後者の方が効率的であることは明らかです。
上記の比喩では:
各配達担当者→各スレッド- 各注文→各ソケット (I/O ストリーム)
- 注文の配送場所→ソケットのさまざまな状態
- 顧客への食品配達リクエスト→クライアントからのリクエスト
- Mingqu のビジネス メソッド→サーバー上で実行されるコード
- 車のコアの数→CPU
-
したがって、次の結論が得られます:
最初のビジネス メソッドは、従来の同時実行モデルであり、各 I/O ストリーム ( order) は新しいスレッド (配達員) によって管理されます。 - 2 番目の管理方法は I/O 多重化です。各 I/O ストリームのステータス (各配達員の配達場所) を追跡することで、複数の I/O ストリームを管理するスレッド (1 人の配達員) のみが存在します。
-
次は、図に示すように、実際の Redis スレッド モデルと類似しています。
Redis クライアントは、次の場合に異なる特性を持ちます。イベントタイプのソケットを操作しています。サーバー側には、それをキューに入れる I/O マルチプレクサがあります。次に、ファイル イベント ディスパッチャがキューからファイルを順番に取得し、別のイベント プロセッサに転送します。
3 つの Redis データ型と使用シナリオ
資格のあるプログラマーは、これら 5 つの型を使用します。
String
最も一般的な set/get 操作。値には文字列または数値を指定できます。一般に、一部の複雑なカウント関数はキャッシュされます。
Hash
ここでの Value には構造化オブジェクトが格納されており、その中で特定のフィールドを操作する方が便利です。シングル サインオンを実行していたとき、このデータ構造を使用してユーザー情報を保存し、キーとして CookieId を使用し、キャッシュの有効期限として 30 分を設定しました。これにより、セッションのような効果を非常によくシミュレートできます。
List
List データ構造を使用すると、 単純なメッセージ キュー関数を実行できます。さらに、lrange コマンドを使用して、優れたパフォーマンスと優れたユーザー エクスペリエンスを備えた Redis ベースのページング関数 を実装できます。
Set
Set は一意の値のコレクションをスタックするためです。したがって、グローバル重複排除機能を実現することができる。私たちのシステムは通常クラスタでデプロイされており、JVM に付属の Set を使用するのは面倒です。さらに、 は交差、和集合、差分などの演算を使用して、共通の設定、すべての設定、独自の独自の設定、およびその他の関数を計算します。
Sorted Set
Sorted Set には追加の 重みパラメータ Score があり、セット内の要素は Score に従って配置できます。 ランキング アプリケーション を実行して、TOP N の操作を行うことができます。 Sorted Set は遅延タスクの実行に使用できます。
4 つの Redis 有効期限戦略とメモリ削除メカニズム
これを見れば、家庭で Redis が使用されているかどうかがわかります。たとえば、Redis は 5G データしか保存できませんが、10G を書き込むと 5G のデータが削除されます。どうやって削除しましたか? この問題について考えたことはありますか?
正解: Redis は、定期的な削除と遅延削除戦略を採用しています。
スケジュールされた削除戦略を使用してみてはいかがでしょうか。
定期的に削除し、タイマーを使用してキーを監視し、有効期限が切れたら自動的に削除します。メモリは時間内に解放されますが、大量の CPU リソースを消費します。 大量の同時リクエストでは、CPU はキーを削除する代わりにリクエストの処理に時間を費やす必要があるため、この戦略は採用されません。
定期的な削除 遅延削除の仕組み
定期的な削除では、Redis はデフォルトで 100 ミリ秒ごとにチェックし、期限切れのキーを削除します。 Redis は 100 ミリ秒ごとにすべてのキーをチェックするのではなく、ランダムにキーを選択してチェックすることに注意してください。通常の削除戦略のみを採用した場合、多くのキーはそれまでに削除されません。したがって、遅延削除が便利です。
定期的な削除を使用する場合、遅延削除による他の問題は発生しません。
いいえ、定期的な削除でキーが削除されない場合は。また、時間内にキーを要求しなかったため、遅延削除は有効になりませんでした。このようにして、Redis のメモリはどんどん増えていきます。その場合は、メモリ削除メカニズムを採用する必要があります。
redis.conf には次の設定行があります:
# maxmemory-policy volatile-lru
この設定にはメモリ削除戦略が装備されています:
noeviction: メモリが新しく書き込まれたデータを収容するのに不十分な場合、新しい書き込み操作はエラーを報告します。 - allkeys-lru: 新しく書き込まれたデータを格納するにはメモリが不十分な場合、キー空間で、最も最近使用されていないキーを削除します。 (推奨、これは現在プロジェクトで使用されています) (最近使用されたアルゴリズム)
- allkeys-random: メモリが新しく書き込まれたデータを収容するのに十分でない場合、キーはキー空間からランダムに削除されます。 。 (誰も使用しないでください。削除しない場合は、少なくともキーを使用してランダムに削除してください)
- volatile-lru: メモリが新しく書き込まれたデータを収容するのに十分でない場合、有効期限が設定されたキースペース。最も最近使用されていないキーを削除します。この状況は通常、Redis がキャッシュと永続ストレージの両方として使用される場合に使用されます。 (推奨されません)
- volatile-random: メモリが新しく書き込まれたデータを収容するのに十分でない場合、有効期限が設定されたキー空間内のキーをランダムに削除します。 (それでも推奨されません)
- volatile-ttl: メモリが新しく書き込まれたデータを収容するのに十分でない場合、有効期限が設定されたキー空間では、有効期限が早いキーが最初に削除されます。 (推奨されません)
-
5 つの Redis とデータベースの二重書き込みの整合性の問題
整合性の問題は、
最終整合性と強整合性にもさらに分類できます。 。データベースとキャッシュが二重に書き込まれている場合、必然的に不整合が発生します。前提として、データに強い整合性要件がある場合、データをキャッシュすることはできません。私たちが行うすべてのことは、最終的な整合性を保証することしかできません。
さらに、私たちが作成したソリューションは、不整合の可能性を減らすことしかできません。したがって、
強い一貫性要件を持つデータはキャッシュできません。まず、 正しい更新戦略を採用し、最初にデータベースを更新してから、キャッシュを削除します 。次に、 キャッシュの削除に失敗する問題が発生する可能性があるため、メッセージキューを使用するなどの補償措置を提供するだけです。
6 キャッシュペネトレーションおよびキャッシュアバランシェの問題に対処する方法
これら 2 つの問題は、通常、中小規模の従来のソフトウェア会社が遭遇するのが困難です。数百万のトラフィックを伴う大規模な同時プロジェクトがある場合は、これら 2 つの問題を深く考慮する必要があります。キャッシュ侵入とは、ハッカーがキャッシュに存在しないデータを意図的に要求し、すべての要求がデータベースに送信され、データベース接続が異常になることを意味します。
キャッシュ侵入ソリューション:
- Use mutex lock. キャッシュが失敗した場合、まずロックを取得し、ロックを取得します。次にデータベースをリクエストします。ロックが取得できない場合は、しばらくスリープしてから再試行します。
- 非同期更新戦略を採用すると、キーが値を取得したかどうかに関係なく、値が直接返されます。キャッシュの有効期限は値の値で維持されます。キャッシュの有効期限が切れると、スレッドが非同期で開始され、データベースを読み取り、キャッシュを更新します。キャッシュの予熱(プロジェクト開始前にキャッシュをロードする)操作が必要です。
リクエストが有効かどうかを迅速に判断できる傍受メカニズムを提供します。たとえば、ブルーム フィルターを使用して、一連の合法的で有効なキーを内部的に維持します。リクエストに含まれるキーが合法かつ有効であるかどうかを迅速に判断します。違法な場合は直接返却してください。 -
キャッシュ雪崩、つまり広い範囲で同時にキャッシュに障害が発生し、さらにリクエストの波が押し寄せます。その結果、リクエストはすべてデータベースに送信されるため、データベース接続が異常になります。
キャッシュなだれの解決策:
キャッシュの有効期限にランダムな値を追加して、集団的な障害を回避します。 -
- ミューテックス ロックを使用しますが、このソリューションのスループットは大幅に低下します。
- 二重キャッシュ。キャッシュ A とキャッシュ B の 2 つのキャッシュがあります。キャッシュ A の有効期限は 20 分ですが、キャッシュ B の有効期限はありません。キャッシュのウォームアップ操作は自分で行ってください。
次に、次の点を詳しく説明します: キャッシュ A からデータベースを読み取り、存在する場合は直接戻ります。A にはデータがありません。B からデータを直接読み取り、直接戻り、更新スレッドを非同期で開始します。更新スレッドはキャッシュ A とキャッシュ B を同時に更新します。 -
8 同時実行性の競合を解決する方法 Redis の主要な問題
この問題は大まかに言うと、
キーを設定するサブシステムが複数あります。同時。このとき私たちは何に注意すべきでしょうか? 基本的には誰もが Redis トランザクション メカニズム を使用することを推奨します。
ただし、Redis トランザクション メカニズムを使用することはお勧めできません。というのは、本番環境は基本的に Redis クラスター環境であり、データシャーディング操作が実行されるためです。トランザクションに複数のキー操作が含まれる場合、これらの複数のキーは必ずしも同じ redis サーバーに保存されるとは限りません。したがって、Redis のトランザクション メカニズムは非常に役に立ちません。
このキーを操作する場合、 の順序は必要ありません。
この場合、## を準備します。 # distribution 「lock
」と入力すると、全員がロックを取得しに行き、ロックを取得した後に set 操作を実行するだけです。これは比較的簡単です。
このキーを操作する場合、
注文が必要ですキーがあると仮定すると、1、システム A は次のことを行う必要があります。 key1 を valueA に設定し、システム B は key1 を valueB に設定する必要があり、システム C は key1 を valueC に設定する必要があります。
key1 の値は、valueA > valueB > valueC の順に変化することが予想されます。現時点では、
データがデータベースに書き込まれるときに、
タイムスタンプ を保存する必要があります。
タイムスタンプは次のとおりであると仮定します
:システム A キー 1 {valueA 3:00}
システム B キー1 { valueB 3:05}
System C key 1 {valueC 3:10}
したがって、システム B が最初にロックを取得すると仮定して、key1 を {値B 3:05}。次に、システム A がロックを取得し、自身の valueA のタイムスタンプがキャッシュ内のタイムスタンプよりも古いことが判明したため、セット操作は実行されません。以下同様です。
キューを使用したり、set メソッドをシリアル アクセスに変換したりするなど、他の方法も
実行できます。 #Redis 関連の技術記事の詳細については、
Redis チュートリアル## 列にアクセスして学習してください。
以上がRedisを分散させる方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。