|
ビジネス ロジックを記述するほとんどのプログラマーは、実際の開発で Redis を使用するときに Set Value 操作と Get Value 操作しか知らないため、Redis に関する包括的な理解が欠けています。 したがって、皆さんの知識のギャップを埋めるために、Redis の一般的な問題を要約することにしました。 この記事では、以下の点について詳しく説明します。
Redis を使用する理由 プロジェクトで Redis を使用する際の主な考慮事項は、パフォーマンスと同時実行性だと思います。 もちろん、Redisには分散ロックなどの他の機能もありますが、これらの機能だけが必要な場合は、Zookeeperなどの代替ミドルウェアオプションがあり、Redisは必須ではありません。したがって、この質問には、主にパフォーマンスと同時実行性の観点から答えるべきです。 パフォーマンス 下の図に示すように、実行に非常に時間がかかり、結果が頻繁に変更されないSQLクエリに遭遇した場合、結果をキャッシュすることが特に適しています。これにより、後続のリクエストはキャッシュから読み込まれるため、応答時間が短縮されます。 余談ですが、突然ですが、迅速な対応の基準についてお話ししたくなりました。交互作用効果にもよりますが、対応時間には決まった基準はありません。 しかし、かつて誰かが私にこう言いました。「理想的には、ページジャンプは瞬時に解決される必要があり、ページ内操作も瞬時に解決される必要があります。」 さらに、指をスナップするよりも長い時間がかかる操作には進行状況インジケーターが必要であり、ユーザーに最高のエクスペリエンスを提供するためにいつでも停止またはキャンセルできるようにする必要があります。 では、一瞬、瞬間、あるいは指を鳴らす動作には、実際どれくらいの時間がかかるのでしょうか? *マハサンギカ ヴィナヤ* によれば、次のようになります。 一つの瞬間は一つの考え、二十の考えは一つの瞬間、二十の瞬間は一つの指鳴らし、二十の指鳴らしは一つの莖玉、二十莖は一つの徐玉、そして一昼夜には三十の徐玉がある。 したがって、慎重に計算すると、瞬間は 0.36 秒、瞬間は 0.018 秒、指を鳴らす時間は 7.2 秒になります。 同時 下の図に示すように、同時実行性が高い場合、すべてのリクエストがデータベースに直接アクセスするため、接続エラーが発生する可能性があります。 この時点で、データベースに直接アクセスするのではなく、最初に Redis にアクセスするリクエストを許可するために、Redis をバッファとして使用する必要があります。 Redis を使用することの欠点は何ですか? Redisを長年使用してきた方なら、これは必ず理解しておくべき問題です。基本的に、Redisを使用する際には誰もが何らかの問題に遭遇しますが、よくある問題はごくわずかです。 答えは主に次の 4 つの質問から構成されます。 キャッシュとデータベース書き込み間の一貫性の問題
シングルスレッドの Redis がなぜこんなに高速なのでしょうか? この質問は、Redisの内部メカニズムに関する理解度を測るものです。私の面接経験からすると、Redisがシングルスレッドモデルで動作することを知らない人が多いようです。そのため、この質問は確認する価値があります。 その答えは主に以下の3点になります。
余談ですが、ここでは I/O 多重化について詳しく説明します。この用語は非常に一般的なので、ほとんどの人はその意味を理解していないからです。 例:シャオ・クはS市に宅配便店を開き、市内の速達サービスを提供しています。資金が限られていたため、シャオ・クは宅配便業者を数人雇いましたが、資金が不足していることが判明し、配達用の車両を1台しか購入できませんでした。 ビジネスモデル1 顧客が荷物を配達するたびに、Xiao Qu は宅配業者に荷物を監視させ、その後宅配業者が車で荷物を配達しに行きます。 徐々に、Xiao Qu はこのビジネス モデルに次のような問題があることを発見しました。
上記の欠点を慎重に検討した後、Xiao Qu は次のビジネス モデルを提案しました。 ビジネスモデル2 Xiao Quは配達員を1人だけ雇っています。顧客が荷物を送ると、Xiao Quは配達先住所に応じて荷物に印を付け、一箇所にまとめて保管します。 配達員は荷物を一つずつ取りに行き、配達のために車で出発し、配達が終わると次の荷物を取りに戻りました。 上記の 2 つの操作方法を比較すると、2 番目の方法の方が明らかに効率的で優れているのではないでしょうか。 上記の例えでは、
したがって、次のように結論付けることができます。
実際の Redis スレッド モデルとの類似性は、図に示すように次のようになります。 簡単に言うと、redis クライアントが動作すると、さまざまなイベント タイプのソケットが生成されます。 サーバー側には、イベントをキューに格納するI/O多重化プログラムがあります。その後、ファイルイベントディスパッチャがキューからイベントを1つずつ取得し、異なるイベントハンドラーに転送します。 なお、Redis は、この I/O 多重化メカニズム用に select、epoll、evport、kqueue などの多重化関数ライブラリも提供しており、これらを独自に調べることができます。 Redis のデータ型とその使用例。 この質問は初歩的な質問に思えますか?私もそう思いました。しかし、私の面接経験から言うと、少なくとも80%の人は答えられません。 私の提案は、まずプロジェクトで実際に使ってみて、それから類似点を見出しながら記憶し、より深く理解することです。丸暗記しようとしないでください。基本的に、有能なプログラマーであれば、5つのタイプすべてを使えるはずです。 弦 これについては特に説明することはありません。最も基本的なset/get操作です。値は文字列または数値です。通常は複雑なカウント関数のキャッシュに使用されます。 ハッシュ ここで、Value は構造化されたオブジェクトを格納し、その中の特定のフィールドを操作するのに便利になります。 シングル サインオンを実装したとき、CookieId をキーとして使用し、30 分のキャッシュ有効期限を設定して、このデータ構造を使用してユーザー情報を保存し、セッションのような効果を効果的にシミュレートしました。 リスト Listデータ構造を使用することで、シンプルなメッセージキュー機能を実装できます。また、`lrange`コマンドを使用してRedisベースのページネーションを実装できるという利点もあり、優れたパフォーマンスと優れたユーザーエクスペリエンスを実現します。 セット Set は一意の値のコレクションを格納するため、グローバルな重複排除に使用できます。重複排除には、JVM 組み込みの Set を使用するのがよいでしょう。 当社のシステムは一般的にクラスタ構成になっているため、JVM 組み込みの Set を使用するのは非常に面倒です。グローバル重複排除を実行するためだけに、新たにパブリックサービスを起動するのは非常に面倒です。 さらに、積、和、差などの演算を使用することで、共通の好み、すべての好み、固有の好みを計算することができます。 ソートされたセット ソート セットには追加の重みパラメータ「スコア」があり、これによりセット内の要素をスコアに従ってソートすることができます。 リーダーボードアプリケーションで上位N件の結果を取得するために使用できます。ソートセットは遅延タスクに使用できます。*** 例として、範囲検索が挙げられます。 Redisの有効期限ポリシーとメモリ削除メカニズム これは非常に重要な質問です。Redis が効果的に使用されているかどうかがわかります。 例えば、Redisインスタンスが5GBのデータしか保存できないのに、10GBを書き込むと5GBのデータが削除されます。この削除がどのように行われるか考えたことがありますか? また、データの有効期限を設定しているにもかかわらず、有効期限を過ぎてもメモリ使用量がかなり高いままです。その理由についてご検討いただけましたか? 回答: Redis は、定期的な削除と遅延削除の戦略を組み合わせて使用します。 時間制限付き削除戦略を使用しないのはなぜですか? スケジュール削除では、タイマーを使用してキーを監視し、有効期限が切れると自動的に削除します。これによりメモリは速やかに解放されますが、CPUリソースを大量に消費します。 同時実行性が高い場合、CPU はキーを削除するのではなく、リクエストの処理に時間を費やす必要があるため、この戦略は採用されませんでした。 スケジュールされた削除と遅延削除はどのように機能しますか? 定期的な削除: Redis は、デフォルトで 100 ミリ秒ごとに期限切れのキーをチェックし、必要に応じて期限切れのキーを削除します。 Redis は 100 ミリ秒ごとにすべてのキーをチェックするのではなく、チェックするキーをランダムに選択することに注意してください (すべてのキーを 100 ミリ秒ごとにチェックすると、Redis がフリーズします)。 したがって、定期的な削除戦略のみを使用すると、多くのキーが期限までに削除されない可能性があります。ここで遅延削除が役立ちます。 つまり、キーを取得する際に、Redis はキーに有効期限が設定されている場合、そのキーが期限切れかどうかを確認します。期限切れの場合は、キーは削除されます。 定期削除と遅延削除を組み合わせて使用すると、他のすべての問題が解消されますか? いいえ、スケジュールされた削除時にキーが削除されず、すぐにキーの返却を要求しない場合、つまり遅延削除が効果を発揮しない場合、Redis のメモリ使用量は急激に増加します。その場合は、メモリエビクションメカニズムを実装する必要があります。 redis.conf には次の設定行があります:
この構成は、メモリ削除ポリシーを設定するためのものです (まだ構成していないのですか? アプローチを真剣に検討する必要があります)。
PS: 有効期限が切れるキーが設定されていない場合、前提条件は満たされません。したがって、volatile-lru、volatile-random、および volatile-ttl 戦略の動作は、基本的に noeviction (削除なし) と同じです。 Redis とデータベースの二重書き込みの一貫性の問題 一貫性の問題は分散システムにおいて一般的な問題であり、さらに結果整合性と強い一貫性に分類できます。データベースとキャッシュへの二重書き込みは、必然的に不整合の問題を引き起こします。 この質問に答えるには、まず一つの前提を理解する必要があります。データに強い一貫性が必要な場合、キャッシュは選択肢ではありません。私たちが行うすべてのことは、結果的一貫性しか保証できないということです。 さらに、当社のソリューションは不整合の可能性を低減するだけで、完全に排除することはできません。そのため、強い整合性が求められるデータはキャッシュできません。 回答:まず、正しい更新戦略を採用してください。まずデータベースを更新し、次にキャッシュを削除します。次に、キャッシュの削除に失敗する可能性があるため、メッセージキューなどの補償策を用意してください。 キャッシュ侵入とキャッシュアバランシェ問題への対処方法 率直に言って、これらは中小規模の従来型ソフトウェア企業ではほとんど遭遇しない2つの問題です。しかし、トラフィックが数百万に達するような高同時実行プロジェクトの場合は、これら2つの問題を慎重に検討する必要があります。 キャッシュ侵入は、ハッカーがキャッシュに存在しないデータを意図的に要求し、すべての要求がデータベースにアクセスしてデータベース接続エラーが発生する場合に発生します。 キャッシュ侵入ソリューション:
キャッシュアバランシェは、多数のキャッシュが同時に期限切れになったときに発生します。次のリクエストの波が到来すると、それらすべてがデータベースに送信され、データベース接続障害につながります。 キャッシュアバランシェソリューション:
次に、以下の点に分解します。データベースからキャッシュAからデータを読み取り、存在する場合はそのデータを直接返します。Aにデータが存在しない場合は、キャッシュBから直接データを読み取り、それを直接返します。そして、非同期で更新スレッドを開始します。更新スレッドは、キャッシュAとキャッシュBの両方を同時に更新します。 Redis での同時キー競合の問題を解決するにはどうすればよいですか? 問題は大まかに言うと、複数のサブシステムが同時に単一のキーを設定していることです。このような状況では、どのような予防策を講じるべきでしょうか? 事前に Baidu で簡単に検索してみたところ、ほとんどの回答で Redis のトランザクション メカニズムの使用が推奨されていることが分かりました。 Redisのトランザクションメカニズムの使用は推奨しません。当社の本番環境は、主にデータシャーディングを備えたRedisクラスタ環境です。 トランザクションが複数のキーの操作を伴う場合、これらのキーは必ずしも同じRedisサーバーに保存されるとは限りません。そのため、Redisのトランザクションメカニズムは実用的ではありません。 このキーに対して操作を実行する場合、順序は必要ありません。 このシナリオでは、分散ロックを準備し、参加者がロックをめぐって競争することができます。ロックが取得されると、比較的単純なセット操作を実行できます。 このキーに対する操作を次の順序で実行する必要がある場合... key1 があるとします。システム A は key1 を valueA に設定する必要があり、システム B は key1 を valueB に設定する必要があり、システム C は key1 を valueC に設定する必要があります。 key1の値は、valueA > valueB > valueCの順に変化することが期待されます。この場合、データベースにデータを書き込む際にタイムスタンプを保存する必要があります。 タイムスタンプが次のとおりであると仮定します。
例えば、システムBが最初にロックを取得し、key1を{valueB 3:05}に設定するとします。次にシステムAがロックを取得し、valueAのタイムスタンプがキャッシュ内のタイムスタンプよりも古いため、設定操作を実行しません。以下、同様の処理が繰り返されます。 キューを使って`set`メソッドを逐次アクセスするといった他の方法も可能です。つまり、柔軟性と適応性を持つことが重要です。 要約 この記事では、Redis に関するよくある質問をまとめています。そのほとんどは、私が仕事で遭遇した質問や、面接でよく聞く質問です。 また、直前に詰め込むのはお勧めしません。経験豊富なエンジニアの質問は、あなたを簡単に困惑させる可能性があります。お役に立てれば幸いです! |