web-dev-qa-db-ja.com

Facebookのように通知カウンターを処理する良い方法

Facebookが処理する同様の通知メカニズムを構築したいと考えています。

enter image description here

私は実際にユーザーの通知をSQLテーブルに保存します(実際にはグラフデータベースですが、みんなRDBMS用語をマスターしています)。

ユーザーがアイコンをクリックした場合に興味があります。カウンターは内部的に0の値を取得し、視覚的に消えます。

このカウンターをクリアするにはどうすればよいですか?

  • クリックすると、各通知にread(テーブルの列READ)のフラグを付けるRest APIを呼び出しますか?
    欠点は、カウンタを0にして非表示にするためにフラグを立てる通知が大量にある場合、時間がかかることです。
  • アイコンがクリックされるたびにfalseと評価されるHAS_NEW_NOTIFICATIONと呼ばれる各ユーザーの種類の列がある(REST API呼び出しを通じて)、カウンターがいた。
    したがって、カウンタは、フラグ値がtrueの場合にのみ存在します。

良い習慣は何でしょうか?

7
Mik378

ベストプラクティスは、ブラウザが通知を最後にプルしたことを示す日時スタンプをユーザーのテーブルに保存することです。この日時スタンプの後に作成された通知は、新規および未読としてカウントされます。

データベースは、作成された日時スタンプによって通知に効率的にインデックスを付け、読み取りがパフォーマンスに影響しない場合はフラグを追加できます。与えられた日時以降は常に通知を検索しているので、パフォーマンスは大丈夫です。

最も古い未読の日時スタンプが何であるかのユーザーのテーブルを更新する必要があるだけです。これにより、新しいアイテムや未読アイテムの通知をクエリする場所が提供されます。

未読のアイテムがない場合、ユーザーのタイムスタンプは、ブラウザが最後にチェックのためにプルした時間に更新されます。

8
Reactgular

主な考え方は同じですが、以前の回答に完全に同意することはできません。

最終読み取りタイムスタンプ

最初に、個人的なメッセージのみがある場合はすべてのユーザーの最後のプルタイムスタンプを保存するか、未読を追跡するためにすべてのユーザーチャネル(チャット、ストリーム、ルーム、トピックなど)ペアの最後のプルタイムスタンプを保存する必要があります。メッセージを個別に。

すべてのユーザーと通知のペアにフラグを保存することも解決策になる可能性がありますが、UIで通知ごとに「読み取り」のイベントをキャッチすることが難しくなり(これがメールボックスでない場合)、通常はユーザーエクスペリエンスが低下します。

一定期間のクエリ

すべての未読通知の総数を取得するたびに(違いではありません)

人々がそのようなカウンターを見て、それを一定の間隔、たとえば30秒で更新するWebサイトがあるとすると、10_000人の訪問者がいくつかの記事を同時に読んでいることになります。次に、カウンターのみで20k rmpまたは333 rpsを取得します。 10秒の更新では、それぞれ60k rmp 1k rpsを取得します。

問題がないのは、あなたがWebサイトの管理者であり、そのすべてのユーザーに宛てられた「通知」または「ニュース」と呼ばれる唯一のテーブルを持っている場合です。ここには多くの行があるはずはありません。

キャッシング数

各ユーザーと部屋のペアの未読メッセージ数を保持

したがって、最後のプルタイムスタンプを保持することに加えて、未読メッセージの数をどこかにキャッシュする必要があることがよくあります。そうしないと、インデックスは役に立ちません。カウントは非常に負荷の高い操作です(例:postgres)。メッセージ/投稿/通知テーブルのサイズによっては、すぐに問題になります。

カウンタをメモリまたはデータベースにキャッシュすることもできます。

一般に、メッセージの宛先が誰であるかを言うことができます(ユーザーが認証されている場合)。したがって、メッセージを作成するときに、ユーザーのカウンターを(たとえば、チャットアプリケーションで)増やすことができます。

ユーザーがメッセージを読み取るたびに、キャッシュを無効にする(またはゼロに設定する)必要があります。

メッセージのキャッシング(上限付きリスト)

各部屋の最後のN個のメッセージと最後に読み取られたタイムスタンプをキャッシュ

未読として表示するメッセージの最大数はいくつですか?カウンターに制限がある場合、メモリ内の各部屋(Aerospike、Redis、Memcached)の最後のN(例:10)メッセージを追跡でき、最後に読み取られたタイムスタンプより後に作成されたメッセージを見つける複雑さはCONST(O( N)実際には、Nはconst)であり、データベースのサイズやインデックスにはまったく依存しません。キャッシュに十分なメモリを割り当てたことを確認してください。 Nを超えるものはすべてフラッシュされます。

定期購入

最初に合計を取得し、次に更新時に差分を取得します

WebSocketまたは別のプロトコルを介したpub/subメカニズムを使用してクライアントをサブスクライブできます。次に、ページを開くときにユーザーが未読の通知の数を取得し、これらの通知をクライアントにプッシュし、カウンターをインクリメントし、クライアントの実装でページのカウンターを増やす必要があります。

Kafkaなどのメッセージブローカーを使用すると、すべての未読メッセージを自動的に接続して取得することもできます(もちろん、いくつかの制限があります)。

  • WebアプリがSPAでない限り機能しません。クラシックなページナビゲーションの場合は、キャッシュカウントとほぼ同じです。*

UIトリック

表示ラベルだけを非表示にする

ラベルに書かれていることを過小評価しないでください。未読が1か500の場合がありますが、特に問題はありません。最初に、空白のラベル(または1のみ)、ラベル10、またはラベル100が違いを生むかどうかを考えます。それらをカウントする代わりに、PostgresでEXISTS句を使用して、いくつかのメッセージがあることを示すことができます。したがって、優れたUIを開発することで、データベースの負荷を大幅に削減できます。

3
Nick Roz