通知システムの構築[終了]


170

私はFacebookスタイルの通知システム(ソーシャルゲームタイプ)の構築を始めており、そのようなシステムを設計するための最良の方法を調査しています。通知をユーザーにプッシュする方法やそのようなものには(今のところは)興味はありません。サーバー上でシステムを構築する方法(通知の保存方法、保存場所、フェッチ方法など)を調査しています。

だから...私たちが持っているいくつかの要件:

  • ピーク時には、約1,000人の同時ログインユーザー(およびさらに多くのゲストがいますが、通知はないためここでは重要ではありません)で、多くのイベントが生成されます
  • 通知にはさまざまなタイプがあります(ユーザーAがあなたを友達として追加し、ユーザーBがあなたのプロフィールにコメントし、ユーザーCがあなたの画像を気に入った、ユーザーDがゲームXであなたを打ち負かした、など)
  • ほとんどのイベントは1人のユーザーに対して1つの通知を生成します(ユーザーXは画像を気に入っています)。ただし、1つのイベントが多くの通知を生成する場合があります(たとえば、ユーザーYの誕生日です)。
  • 通知はグループ化する必要があります。たとえば、4人の異なるユーザーが何らかの画像を好む場合、その画像の所有者は、4人のユーザーが4つの個別の通知ではなく(FBのように)画像を気に入っていることを示す1つの通知を受け取る必要があります

わかりましたので、私が考えていたのは、イベントが発生したときにイベントを格納するキューのようなものを作成することです。次に、そのキューを確認し、それらのイベントに基づいて通知を生成するバックグラウンドジョブ(gearman?)があります。このジョブは、ユーザーごとに通知をデータベースに保存します(したがって、イベントが10人のユーザーに影響する場合は、10個の個別の通知があります)。次に、ユーザーが通知のリストを含むページを開くと、私は彼のためにそれらすべての通知を読み取り(これを100件の最新の通知に制限することを考えています)、それらをグループ化して、最後に表示します。

私がこのアプローチで心配していること:

  • 地獄のように複雑:)
  • データベースはここで最高のストレージです(私たちはMySQLを使用しています)、または他のものを使用する必要があります(redisも適しているようです)
  • 通知として何を保存すればよいですか?ユーザーID、イベントを開始したユーザーID、イベントのタイプ(グループ化して適切なテキストを表示できるようにするため)ですが、通知の実際のデータ(たとえば、URLと画像のタイトル)を保存する方法がわかりません好きだった)。通知を生成するときにその情報を「ベイク」するか、影響を受けるレコードのID(画像、プロファイルなど)を保存し、通知を表示するときにその情報をDBからプルする必要があります。
  • 通知ページを表示するときに100の通知をオンザフライで処理する必要がある場合でも、ここではパフォーマンスは問題ありません。
  • 未読の通知の数をユーザーに表示する必要があるため、すべての要求でパフォーマンスの問題が発生する可能性があります(通知をグループ化するため、それ自体が問題になる可能性があります)。オンザフライではなく、バックグラウンドで通知のグループ化された場所で通知のビューを生成した場合、これは回避できます。

では、私の提案するソリューションと私の懸念についてどう思いますか?ここで関連する他のことについて言及する必要があると思われる場合は、コメントしてください。

ああ、私たちはページにPHPを使用していますが、ここでそれが大きな要因になることはないと思います。


この通知システムを1人の作業として構築するのにかかった時間。それに応じてタイムラインを作成するための見積もりが欲しいだけです。
Shaharyar 2015年

@Shaharyar通知システムの複雑さに依存すると思います。
tyan

MySQLで同じシステムを使用して、優先度ベースの通知システムを構築しました。特に、AndroidとGCMを使用すると、数千ユーザーにまで拡張でき、それ以上になると、爆発的に増加します。MySQLに代わって、メッセージキューや機能の一種を自然に示すredis、rabbitMQ、Kafkaなどを知りたいのですが。
Ankit Marothi 2017

回答:


168

通知は、何か(オブジェクト=イベント、友情..)が誰か(俳優)によって変更(動詞=追加、要求..)され、ユーザー(サブジェクト)に報告されることに関するものです。これは正規化されたデータ構造です(私はMongoDBを使用しましたが)。特定のユーザーに変更について通知する必要があります。つまり、ユーザーごとの通知です。つまり、100人のユーザーが関与した場合、100の通知が生成されます。

╔═════════════╗      ╔═══════════════════╗      ╔════════════════════╗
║notification ║      ║notification_object║      ║notification_change ║
╟─────────────╢      ╟───────────────────╢      ╟────────────────────╢
║ID           ║—1:n—→║ID                 ║—1:n—→║ID                  ║
║userID       ║      ║notificationID     ║      ║notificationObjectID║
╚═════════════╝      ║object             ║      ║verb                ║
                     ╚═══════════════════╝      ║actor               ║
                                                ╚════════════════════╝

(適切と思われる時間フィールドを追加します)

これは基本的にオブジェクトごとに変更をグループ化するためのものなので、「3つの友達リクエストがあります」と言うことができます。また、俳優ごとにグループ化すると便利です。つまり、「ユーザーJames Bondがベッドを変更した」と言うことができます。これにより、通知を必要に応じて翻訳およびカウントすることもできます。

ただし、オブジェクトは単なるIDであるため、オブジェクトが実際に変更されてその履歴を表示したくない場合(たとえば、「ユーザーがイベントのタイトルを...に変更した場合」を除き、個別の呼び出しで必要なオブジェクトに関するすべての追加情報を取得する必要があります。 ")

通知はサイトのユーザーにとってリアルタイムに近いので、変更が追加されると、すべてのリスナーのphp push updateを使用してnodejs + websocketsクライアントで通知を結び付けます。


1
私が話ということにその余分なデータと変更されたオブジェクトへの実際の参照がnotification_change.notificationObjectIDにある文字列のような識別変化型、「友情」notification_object.object
Artjom Kurapov

2
これは馬鹿げた質問かもしれませんが、この設定では、ユーザーが通知を見たり操作したりしたらどうしますか?通知をデータベースから削除するだけですか、それとも日付を使用して、通知が作成されてからユーザーがログインしているかどうかを確認しますか?
Jeffery Mills

4
私はこのトピックがすでに古いことを知っていますが、最初のテーブルについて少し困惑しています。このテーブルの目的は何ですか?これを別のテーブルとして持つことと、userIDをnotification_objectテーブルに置くことの利点は何ですか 言い換えれば、いつ通知に新しいエントリを作成し、いつオブジェクトを追加して、この構造を持つ既存の通知に変更するのですか?
Bas Goossen、2014

3
あなたが好きなステータス・フィールドを持つことができ@JefferyMills is_notification_readnotificationテーブル、それがある場合は、適切にそれをマークしunreadreadまたはdeleted
Kevin

2
私はまた、このソリューションのいくつかの側面を理解するのに苦労し、それについての個別のご質問なされていますdba.stackexchange.com/questions/99401/...
user45623

27

これは本当に抽象的な質問なので、何をすべきか、すべきでないかを指摘するのではなく、議論する必要があるだけだと思います。

これがあなたの懸念について私が思うことです:

  • はい、通知システムは複雑ですが、地獄ではありません。このようなシステムのモデル化と実装には多くの異なるアプローチがあり、それらは中程度から高度の複雑さを持つことができます。

  • 個人的には、私は常にデータベース駆動のものを作るようにしています。どうして?進行中のすべてを完全に制御できることを保証できるので、それは私だけです。データベース主導のアプローチがなくても制御できます。私を信じてください、あなたはそのケースをコントロールしたいと思うでしょう。

  • どこからでも始められるように、実際のケースを例に挙げましょう。昨年、私は何らかのソーシャルネットワーク(もちろんFacebookとは異なります)に通知システムをモデル化して実装しました。そこに通知を保存する方法は?私が持っていたnotifications私が保たれ、テーブル、generator_user_id(通知を生成しているユーザーのID)を、target_user_id(明白なの種類が、それはないですか?)、 notification_type_id(通知タイプを別のテーブルに参照していること)、およびすべてのテーブルに入力するために必要なもの(タイムスタンプ、フラグなど)。私のnotification_typesテーブルnotification_templatesは、通知のタイプごとに特定のテンプレートを格納するテーブルとの関係を持っていました。たとえば、私にはPOST_REPLYタイプがあり、テンプレートのようなもの{USER} HAS REPLIED ONE OF YOUR #POSTSでした。そこから、私はちょうど扱った{}変数#として、参照リンクとして;

  • はい、パフォーマンスは問題ありません。通知について考えるとき、サーバーが頭からつま先まで押すことを考えます。ajaxリクエストなどでそれを行う場合は、パフォーマンスを気にする必要があります。しかし、これは2回目の懸念だと思います。

もちろん、私が設計したそのモデルは、あなたがたどることができる唯一のものではありませんし、最高のものでもありません。私の答えが少なくとも、あなたを正しい方向に導いてくれることを願っています。


他のデータストアを制御できないのはなぜですか?
JanHančič12年

まあ、私はそれを言わなかった。私が言ったことは、データベース制御のアプローチでのみデータ制御を保証できるということです。しかし、それは私だけです。私はそれを言い換えます。
ダニエルリベイロ

@DanielRibeiro通知テンプレートのプレースホルダー({...})は、データベース内のさまざまな種類の通知のさまざまなテーブルセットのプレースホルダーのデータを置き換える必要があります。たとえば、1つのテンプレートは「{user}はあなたの写真を高く評価しました。」、もう1つのテンプレートは「あなたの{Pagename}は新しい高評価を付けました」です。{PageName}や{user}などのプレースホルダーは別のデータベーステーブルからマッピングされるため、プレースホルダーの値を動的に取得するためのスキーマは何である必要があります。
Ashish Shukla 2017年

DanielRibeiro @Ashish Shuklaの質問に応じてプレースホルダーをどのように置き換えたか
Shantaram

@AshishShuklaプレースホルダーを使用または置換しましたか?
Shantaram Tupe

8
╔════════════════════╗
║notification        ║
╟────────────────────╢
║Username            ║
║Object              ║
║verb                ║
║actor               ║
║isRead              ║
╚════════════════════╝

これは2つのコレクションを持つよりも良い答えに見えます。ユーザー名、オブジェクト、isReadでクエリして、新しいイベントを取得できます(3つの保留中の友達リクエスト、4つの質問など...)

このスキーマに問題がある場合はお知らせください。


3
一番上の答えは、正規化されたデータ構造を使用していたため、テーブルに冗長性がありません。あなたの答えはそれをしますか?
アーロンホール

4

個人的には、受け入れられた回答の図をよく理解していないので、受け入れられた回答や他のページから学べることを基にデータベースダイアグラムを添付します。

ここに画像の説明を入力してください

改善は好評です。


message_templateはNotificationTypeテーブルにあるようです。また、main_urlが通知テーブルにあるようで、Notification_Messageテーブルを削除できます。独自にNotificationMessageテーブルがある理由を説明できますか?
ジェフライアン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.