8

各ページの「ビュー カウント」を mySQL データベースに保存しようとしている非常にスループットの高いサイトがあります (従来の理由により、最終的には mySQL に格納する必要があります)。

ビューの数が非常に多いため、SQL の「UPDATE ITEM SET VIEW_COUNT=VIEW_COUNT+1」タイプのステートメントを実行するのは現実的ではありません。何百万ものアイテムがありますが、ほとんどのアイテムは数回しか表示されず、他のアイテムは何度も表示されます。

そのため、Redis を使用してビュー カウントを収集し、カウントを mySQL に書き込むバックグラウンド スレッドを使用することを検討しています。これを行うための推奨される方法は何ですか? このアプローチにはいくつかの問題があります。

  • バックグラウンド スレッドはどのくらいの頻度で実行されますか?
  • mySQL に何を書き戻すかをどのように決定しますか?
  • ヒットするすべての ITEM に対して Redis KEY を保存する必要がありますか?
  • どの TTL を使用すればよいですか?
  • すでに途中まで作成されたソリューションやパワーポイント プレゼンテーションが既に存在するかなど。

私は StackOverflow で非常によく似た質問を見てきましたが、素晴らしい答えはありません...まだ! この時点でより多くの Redis の知識があることを願っています。

4

3 に答える 3

7

答えにたどり着くには、一歩下がって、別の角度からいくつかの質問を見る必要があると思います。

「バックグラウンド スレッドはどのくらいの頻度で実行されますか?」これに答えるには、次の質問に答える必要があります: どのくらいのデータを失う可能性がありますか? データが MySQL にある理由は何ですか? また、そのデータはどのくらいの頻度でアクセスされますか? たとえば、レポートのために 1 日に 1 回だけデータベースを参照する必要がある場合は、1 日に 1 回だけ更新する必要があるかもしれません。一方、Redis インスタンスが停止した場合はどうなるでしょうか? 何回インクリメントを失っても「OK」でいられるでしょうか? これらは、MySQL インスタンスを更新する頻度に関する質問に対する回答を提供するものであり、私たちが回答できるものではありません。

これを redis に格納するには、非常に異なる戦略を使用します。議論のために、1 時間ごとに「db にフラッシュ」する必要があると判断したと仮定します。

各ヒットを、次の行に沿ったキー名構造を持つハッシュに保存します。

interval_counter:DD:HH
interval_counter:total

ページ ID (URI の MD5 サム、URI 自体、または現在使用している ID など) をハッシュ キーとして使用し、ページ ビューで 2 つのインクリメントを行います。ハッシュごとに 1 つ。これにより、各ページの現在の合計と、更新されるページのサブセットが提供されます。

次に、時間の開始から 1 分ほど後に cron ジョブを実行し、前の 1 時間のハッシュを取得して、ビュー数が更新されたすべてのページをプルダウンします。これにより、MySQL DB を更新するためのデータを取得するための非常に高速な手段が提供されますが、数学を実行したり、タイムスタンプなどを使用してトリックを実行したりする必要はありません。bing がインクリメントされていないキーからデータをプルすることにより、競合状態を回避できます。クロックスキューに。

日次キーに有効期限を設定することもできますが、DB が正常に更新されたら、cron ジョブを使用して削除することをお勧めします。これは、cron ジョブが失敗した場合や実行に失敗した場合でも、データが残っていることを意味します。また、変更されないキーを介して既知のヒット カウンター データの完全なセットをフロントエンドに提供します。必要に応じて、毎日のデータを保持して、ページの人気度をウィンドウ ビューで表示することもできます。たとえば、削除の代わりに cron ジョブを介して有効期限を設定することにより、毎日のハッシュを 7 日間維持した場合、先週の各ページの 1 日あたりのトラフィック量を表示できます。

2 つの hincr 操作の実行は、単独で実行することも、パイプライン化することもできますが、コードで計算を行ったりデータを変更したりするよりも効率的であり、パフォーマンスも優れています。

次に、トラフィックの少ないページとメモリ使用量の期限切れの問題について説明します。まず、あなたのデータセットは、大量のメモリを必要とするものとは思えません。もちろん、その多くは各ページをどのように識別するかによって異なります。数値 ID を使用している場合、必要なメモリはかなり少なくなります。それでもメモリが多すぎる場合は、構成を介して調整できます。必要に応じて、メモリ使用量を大幅に削減するために、redis の 32 ビット コンパイルを使用することもできます。たとえば、この回答で説明したデータは、インターネット上で最も忙しい 10 のフォーラムの 1 つを管理するために使用し、3 GB 未満のデータしか消費しませんでした。また、ここで説明しているよりもはるかに多くの「一時的なウィンドウ」キーにカウンターを保存しました。

とはいえ、このユース ケースでは Redis がキャッシュです。上記のオプションを使用してもまだメモリを使いすぎている場合は、キーに有効期限を設定し、各 ht に expire コマンドを追加できます。より具体的には、上記のパターンに従う場合、ヒットごとに次のことを行います。

hincr -> total
hincr -> daily
expire -> total

これにより、アクセスされるたびに有効期限を延長することで、積極的に使用されているものを新鮮に保つことができます。もちろん、これを行うには、表示呼び出しをラップして、合計ハッシュで hget の null 回答をキャッチし、MySQL DB から入力してからインクリメントする必要があります。増分として両方を行うこともできます。これにより、上記の構造が保持され、Redis ノードに再設定が必要な場合に、MySQL Db から Redis サーバーを更新するために必要なコードベースと同じになる可能性があります。そのためには、信頼できると見なされるデータ ソースを検討して決定する必要があります。

前の質問から決定したデータ整合性のパラメーターに従って間隔を変更することにより、cron ジョブのパフォーマンスを調整できます。より高速に実行される cron nob を取得するには、ウィンドウを減らします。この方法でウィンドウを縮小すると、更新するページのコレクションが少なくなるはずです。ここでの大きな利点は、どのキーを更新する必要があるかを把握してから取得する必要がないことです。hgetall を実行し、ハッシュのキーを繰り返し処理して更新を行うことができます。また、すべてのデータを一度に取得することで、多くの往復を節約できます。どちらの場合でも、最初の Redis インスタンスにスレーブ化された 2 番目の Redis インスタンスを検討して、読み取りを行うことを検討する必要がある場合。マスターに対して引き続き削除を行いますが、これらの操作ははるかに高速であり、書き込みの多いインスタンスで遅延が発生する可能性は低くなります。

Redis DB のディスク永続性が必要な場合は、必ずそれをスレーブ インスタンスに配置してください。そうしないと、多くのデータが頻繁に変更される場合、RDB ダンプが常に実行されます。

それが役立つことを願っています。Redis を適切に使用するには、データにアクセスする方法を最初に考える必要があり、それはユーザーごと、プロジェクトごとに大きく異なるため、「既定の」答えはありません。ここでは、この説明に基づいて、2 つのコンシューマーがデータにアクセスし、1 つは表示のみ、もう 1 つは別のデータソースの更新を決定するというルートに基づいています。

于 2013-05-27T19:39:55.807 に答える