ファイルをクリアする必要性からRedisセカンダリインデックスの使用について話します



Talking About Use Redis Secondary Index From Needs Clearing Files



ファイルをクリアする必要性からRedisセカンダリインデックスの使用について話します

オリジナルのシャンハンチャン 網易ゲームの運用および保守プラットフォーム 2019-07-27



シャンハンチャン

網易のシニアオペレーションおよびメンテナンスエンジニア、ゲーム部門のRedisサービスプラットフォームの責任者。



このホワイトペーパーでマスタースレーブビジネスによって提案されたFLUSHDB要件によって引き起こされた考え方は、削除するキーを見つけるための追加のデータ構造を導入することによって実現されます。最後に、より一般的なRedisの使用状況、つまりRedisでのセカンダリインデックスの使用を要約し、他の例を使用して、セカンダリインデックスを使用してRedisを最大限に活用する方法を説明します。

バックグラウンド

あるカジュアルな週末の午後、私はコンピューターの電源を入れ、突然ビジネス開発のクラスメートから次のようなメッセージを受け取りました。

'そこにいますか? FLUSHDBコマンドをアクティブ化するのを手伝ってください。私のプログラムはそれを必要としています。



Redisサービスを使用したことのある学生は、オンラインビジネスの安定性を確保するために、KEYSコマンドなどのオンラインRedisの危険な操作をブロックしていることを知っておく必要があります。これには、指定したDBデータをクリーンアップするコマンドも含まれます。 FLUSHDB

これは、Redisがシングルスレッドサービスであるためです。コマンドは1つずつ実行されます。時間がかかるコマンドの中には、Redisがスタックし、通常のリクエストに応答できない場合があります。スタックしているだけでなく、可用性の高い環境では、サバイバルステータスの監視要求に応答できず、最終的には障害との誤判断につながり、切り替えがトリガーされます。

Redisの内部動作を理解したい学生は、この記事を参照できます。

Redisのコア原則:イベントベースの処理フロー

「いいえ、これはオンラインサービスの安定性に影響します。」私はビジネスクラスメートに返信しました。

'私に何ができる?'ビジネスの同級生が尋ねた。

一般的に使用されるいくつかの方法

スキャン

これは通常、最も直接的で失礼な代替手段です。 DBを選択した後、pass SCANコマンドはすべてのキーをスキャンして、1つずつまたはバッチで削除します。

問題がある

  1. SCANこのメソッドは、段階的な反復法を使用してキーを取得します。オンラインで読み書き中のデータについては、削除したくないデータが誤って削除される場合があります。ビジネスでは、ファイルをクリアするためにノンストップの操作が必要です。

  2. ビジネス処理ロジックが必要です。毎回スキャンおよび削除されるキーが多すぎると、ブロッキングの問題が発生する可能性もあります。少なすぎると効率に影響し、データのクリーンアップに長い時間がかかります。

非同期削除

Redis 4.0以降、非同期削除をサポートする関数FLUSHDB ASYNCは、メインのRedisスレッドFLUSHDB機能をブロックせずに実行できます。

問題がある

コマンドをブロックする場合、個別にブロックする方法はありませんFLUSHDBそして開くFLUSHDB ASYNCしたがって、学生のオンライン操作を操作および維持するか、管理プラットフォームが提供するクリア機能を使用する必要があります。

ビジネス要件は、このコマンドをプログラムに統合し、頻繁に実行することです。したがって、理論は実行可能ですが、実際の操作にはより大きなリスクが伴います。

定期的に削除するには有効期限機能を使用してください

個人的な経験に基づいて、通常、ビジネスはファイルをクリアする必要があり、通常は特定の条件をトリガーし、通常は特定の時点で、または特定のイベントが発生します。

期限切れの削除が時間に関連している場合は、RedisのEXPIREまたはEXPIREATコマンドを使用できます。前者は削除後の期間を指定でき、後者は特定の時点で削除するように指定できます。時間は、通常、時間に関連する期限切れの削除のニーズのほとんどを解決できます。

問題がある

基本的に、イベントによってトリガーされた削除に対して実行できることは何もありません。

シーンの復元

数文で解決できる問題ではないようですので、ビジネスの学生に具体的な使用シナリオを説明してもらい、理解と合わせて次の要件に絞り込みました。

  1. このシーンはオンラインモールとして機能し、ユーザーが購入できるさまざまな商品を提供します。商品には、商品タイプ、ゲームタイプ、価格、販売量、オンライン時間など、さまざまな属性があります。

  2. ビジネスでは、価格、販売量、更新時間などの指定された要件に従って製品を並べ替え、結果をフロントエンドに返して、シーケンシャルリストの形式でユーザーに表示できます。

  3. 製品データはリレーショナルデータベース(MySQLなど)に保存され、新しいクエリはすべてデータベースにクエリを送信して結果を取得します。クエリの種類は常に制限されており、通常は一定期間にわたってあまり変化しないため、ビジネスはこのクエリの結果をRedisにキャッシュして、クエリの効率を向上させます。

    キー名はクエリ条件で構成され、クエリの結果はリストデータ構造に格納されます。

    低価格から高価格へのクエリを想定しています。

ビジネスが結果を直接取得した後、データベースへのクエリと並べ替えの操作を回避し、データベースの負荷を軽減し、同時にページの対応する速度を向上させます。

  1. 価格や販売量などの商品の属性が変更されると、Redisに保存されているキャッシュレコードは無効になり、削除する必要があります。次回ユーザーがクエリを実行すると、キャッシュレコードが再生成され、Redisに配置されます。

おそらくシーンはこれを聞いており、それでも比較的一般的なキャッシュ要件であると感じていますが、なぜそれを使用するのですかFLUSHDBこのような危険な順序ですか?特定の製品に関連するキャッシュを削除するだけで十分ではないでしょうか?

ビジネスクラスメートのアイデアはまだ比較的簡単です。製品の属性が変更された場合は、ファイルをクリアするだけです。まだ有効なデータが削除されているかどうかは関係ありません。とにかく、データベースに移動して再生成するだけです。

これはおそらく非科学的です。データ量が比較的多い場合、ファイルがクリアされるたびに、リレーショナルデータベースに送信される新しいリクエストの大きな波に相当します。同時実行性が比較的高い場合、リレーショナルデータベースはそれをサポートできません。一定期間のキャッシュアクセラレーションの欠如も、ユーザーエクスペリエンスに大きく影響します。

ソリューション

ビジネス学生は、この方法が実際にはあまり科学的ではないことに同意しているため、ビジネスロジックで削除するキーを決定することにしました。

しかし、実際の操作は簡単ではありません。ビジネスロジックは、製品の属性と情報に従って関連するキーの名前を組み立て、一致するすべてのキーをスキャンして削除する必要があります。クエリごとに異なる条件で構成されるキー名の組み合わせが異なるため、完全に削除できるようにするには、複数の全表スキャンが必要になる場合があります。

一方、キャッシュされた製品のクエリ結果が最初のNレコードのみを記録する場合、これらのNレコードには更新された製品が含まれない可能性があります。これは、不要な削除を行うことと同じです。

Redisは、そのような問題を解決するのにとても不器用なだけでしょうか?

問題の本質について考えてください。実際、製品に対応するクエリステートメントのキーを見つける必要があります。製品とクエリの関係を直接維持できますか?

製品(製品)とクエリステートメント(クエリ)の間には多対多の関係があります。 Redisでは、データはKey-Value方式で保存されます。値には、リスト、セット、ソートされたセットなど、さまざまなタイプがあります。 product:$idなど、製品の特定の情報をキー名として使用するだけです。関連するクエリのキー名を要素としてセットコレクションに格納することで、このマッピングを作成できます。

特定の商品の属性が変更されるたびに、このセットの要素をトラバースしたり、要素を1つずつまたはバッチで削除または変更したりできます。 DB全体のデータをクリーンアップすることは言うまでもなく、DB全体をトラバースする必要はありません。

ただし、同時に、元のリストの作成に加えて、クエリキャッシュを作成するたびに、対応する製品のセットも更新する必要があります。

LPUSH query:xxxxx:xxxxx SADD product1 query:xxxxx:xxxxx SADD product2 query:xxxxx:xxxxx SADD product3 query:xxxxx:xxxxx ... SADD productN query:xxxxx:xxxxx

上記の操作は、Redisのパイプライン関数を使用してバッチ操作を実行することにより、バッチコマンドにパッケージ化できます。

ここには多くの更新された操作がありますが、ビジネスがより多くを読み取り、より少なく書き込むシナリオでは、それでも許容できるはずです。

このとき、ビジネスクラスメートは親指を立ててクリックし、コードの入力を開始しました。

必須要件-Redisセカンダリインデックス

このアプリケーションのシナリオを要約すると、Redisのセカンダリインデックスである使用状況を抽出できます。

別のシナリオで説明しましょう。

特定の年齢層のユーザーを選択します

3人のユーザーがいて、各ユーザーの情報がハッシュデータ構造に格納されているとします。

HMSET user:1 id 1 username antirez ctime 1444809424 age 38 HMSET user:2 id 2 username maria ctime 1444808132 age 42 HMSET user:3 id 3 username jballard ctime 1443246218 age 33

現時点では、他のデータ構造のサポートなしで30〜39歳のユーザーを検索する場合は、すべてのDBにパスHSCANコマンドを実行して、各ユーザーの年齢フィールドをスキャンして検索することしかできません。

sorted set各ユーザーの年齢情報を記録するには、スコアは年齢、値はユーザーIDです。

ZADD user.age.index 38 1 ZADD user.age.index 42 2 ZADD user.age.index 33 3

このように、30〜39歳のユーザーを検索する場合は、次の操作を行うだけで済みます。

127.0.0.1:6379> ZRANGEBYSCORE user.age.index 30 39 1) '3' 2) '1'

ここで、ID 1および3のユーザーは、探しているユーザーのIDであり、HGETコマンドを渡して特定のユーザー情報を照会します。

実際、これは公式Webサイトでのセカンダリインデックスの使用に関するトピックの例です。興味のある学生は、https://redis.io/topics/indexesにアクセスして詳細を確認できます。

セカンダリインデックスは、Redisの比較的高度な使用法であると言えます。これは、この使用法が通常、リスト、セット、ソートされたセットなどの複数のデータ構造と組み合わされているためです。同時に、セカンダリインデックスは、Redisに、より複雑なクエリと操作の要件を実現するためのより豊富な技術的手段を提供します。

公式ウェブサイトでは、辞書式インデックス、複合インデックス、多次元インデックスなどの使用方法など、インデックスでのRedisのその他のより高度な使用法についても言及していますが、ここでは拡張しません。

この記事のモールシーンに戻る

この記事の元のオンラインショッピングシーンでは、各製品マッピング関係へのクエリキャッシュがあります(ここでは、リスト構造が使用されています)。ただし、逆に、商品からクエリキャッシュを検索する場合、追加のデータ構造を使用しない場合は、トラバースすることしかできません。

したがって、関連するクエリのキー名を取得するためのキーとして製品を使用することにより、注文要件のないセカンダリインデックスを構築するため、セットタイプが使用されます。ここでの特別な点は、各製品にはこのようなインデックスが必要なため、複数のセットを使用することです。

最後に、セカンダリインデックスは、すべての問題を解決する特効薬ではありません。実際、このシナリオのデータ量が比較的少なく(増加しない)、製品情報の変更頻度が非常に低い場合は、偶然に発生する可能性がありますFLUSHDBもう少し楽しくしてください。すべては特定のビジネスニーズに依存します。

過去に素晴らしい

IPv6環境でのIPv6サポートレポートとDNS関連のテスト

NetEaseGames海外AWSダイナミックスケーリングプラクティス

スワップとスワップネス

MongoDB変更ストリームとデータサブスクリプションの同期

MySQLフラッシュバックは握手パーティーを保存します