Membangun sistem notifikasi [ditutup]

170

Saya pada awalnya membangun sistem pemberitahuan gaya Facebook untuk halaman kami (tipe game sosial) dan saya sekarang sedang meneliti apa yang akan menjadi cara terbaik untuk merancang sistem seperti itu. Saya tidak tertarik tentang cara mendorong pemberitahuan ke pengguna atau hal-hal seperti itu (untuk saat ini bahkan). Saya sedang meneliti bagaimana membangun sistem di server (cara menyimpan notifikasi, tempat menyimpannya, cara mengambilnya, dll ...).

Jadi ... beberapa persyaratan yang kami miliki:

  • pada waktu puncak, kami memiliki sekitar 1 r pengguna yang masuk secara bersamaan (dan lebih banyak tamu, tetapi mereka tidak penting di sini karena mereka tidak akan memiliki pemberitahuan) yang akan menghasilkan banyak acara
  • akan ada berbagai jenis notifikasi (pengguna A telah menambahkan Anda sebagai teman, pengguna B telah mengomentari profil Anda, pengguna C menyukai gambar Anda, pengguna D telah mengalahkan Anda di game X, ...)
  • sebagian besar acara akan menghasilkan 1 pemberitahuan untuk 1 pengguna (pengguna X menyukai gambar Anda), tetapi akan ada kasus di mana satu acara akan menghasilkan banyak pemberitahuan (misalnya, ulang tahun pengguna Y)
  • pemberitahuan harus dikelompokkan bersama; jika misalnya empat pengguna berbeda menyukai beberapa gambar, pemilik gambar tersebut harus mendapatkan satu pemberitahuan yang menyatakan bahwa empat pengguna menyukai gambar dan bukan empat pemberitahuan terpisah (seperti halnya FB)

OK jadi yang saya pikirkan adalah saya harus membuat semacam antrian di mana saya akan menyimpan acara ketika itu terjadi. Lalu saya akan memiliki pekerjaan latar belakang ( tukang gigi ?) Yang akan melihat antrian itu dan menghasilkan pemberitahuan berdasarkan peristiwa-peristiwa itu. Pekerjaan ini kemudian akan menyimpan notifikasi dalam database untuk setiap pengguna (jadi jika suatu peristiwa memengaruhi 10 pengguna, akan ada 10 notifikasi terpisah). Kemudian ketika pengguna akan membuka halaman dengan daftar notifikasi saya akan membaca semua notifikasi untuknya (kami berpikir untuk membatasi ini hingga 100 notifikasi terbaru) dan mengelompokkannya bersama dan akhirnya menampilkannya.

Hal yang saya khawatirkan dengan pendekatan ini:

  • kompleks sekali :)
  • adalah basis data penyimpanan terbaik di sini (kami menggunakan MySQL) atau haruskah saya menggunakan sesuatu yang lain (redis sepertinya cocok juga)
  • apa yang harus saya simpan sebagai pemberitahuan? ID pengguna, ID pengguna yang memprakarsai acara, jenis acara (sehingga saya dapat mengelompokkannya dan menampilkan teks yang sesuai) tetapi kemudian saya agak tidak tahu cara menyimpan data notifikasi yang sebenarnya (misalnya URL & judul gambar yang disukai). Haruskah saya "memanggang" info itu ketika saya menghasilkan pemberitahuan, atau haruskah saya menyimpan ID catatan (gambar, profil, ...) yang terpengaruh dan menarik info keluar dari DB saat menampilkan pemberitahuan.
  • kinerja harusnya OK di sini, bahkan jika saya harus memproses 100 notifikasi secara langsung saat menampilkan halaman notifikasi
  • kemungkinan masalah kinerja pada setiap permintaan karena saya harus menampilkan jumlah pemberitahuan yang belum dibaca kepada pengguna (yang bisa menjadi masalah tersendiri karena saya akan mengelompokkan pemberitahuan bersama). Ini bisa dihindari meskipun jika saya membuat tampilan pemberitahuan (di mana mereka dikelompokkan) di latar belakang dan tidak on-the-fly

Jadi apa yang Anda pikirkan tentang solusi yang saya usulkan dan kekhawatiran saya? Berikan komentar jika Anda pikir saya harus menyebutkan hal lain yang relevan di sini.

Oh, kami menggunakan PHP untuk halaman kami, tapi itu seharusnya tidak menjadi faktor besar di sini.

Jan Hančič
sumber
Berapa lama waktu yang Anda perlukan untuk membangun sistem pemberitahuan ini sebagai upaya satu orang. Saya hanya ingin memiliki perkiraan untuk membuat garis waktu yang sesuai.
Shaharyar
@ Shaharyar Saya pikir itu tergantung pada kompleksitas sistem notifikasi.
tyan
Saya menggunakan sistem yang sama dengan MySQL untuk membangun sistem notifikasi berbasis prioritas. Hal yang baik adalah ia menskala hingga beberapa ribu pengguna, jika lebih dari itu, akan meledak, khususnya dengan Android dan GCM. Saya ingin tahu alternatif untuk MySQL seperti redis, rabbitMQ, Kafka yang secara alami menunjukkan antrian pesan, jenis fungsionalitas.
Ankit Marothi

Jawaban:

168

Pemberitahuan adalah sesuatu (objek = acara, pertemanan ..) sedang diubah (kata kerja = ditambahkan, diminta ..) oleh seseorang (aktor) dan dilaporkan kepada pengguna (subjek). Berikut adalah struktur data yang dinormalisasi (meskipun saya telah menggunakan MongoDB). Anda perlu memberi tahu pengguna tertentu tentang perubahan. Jadi itu adalah pemberitahuan per pengguna .. artinya jika ada 100 pengguna yang terlibat, Anda menghasilkan 100 pemberitahuan.

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

(Tambahkan bidang waktu yang Anda inginkan)

Ini pada dasarnya untuk mengelompokkan perubahan per objek, sehingga Anda dapat mengatakan "Anda memiliki 3 permintaan teman". Dan pengelompokan per aktor berguna, sehingga Anda bisa mengatakan "Pengguna James Bond membuat perubahan di tempat tidur Anda". Ini juga memberikan kemampuan untuk menerjemahkan dan menghitung notifikasi sesuka Anda.

Tapi, karena objek hanyalah ID, Anda perlu mendapatkan semua info tambahan tentang objek yang Anda inginkan dengan panggilan terpisah, kecuali objek benar-benar berubah dan Anda ingin menunjukkan riwayat itu (jadi misalnya "pengguna mengubah judul acara menjadi ... ")

Karena notifikasi dekat dengan realtime untuk pengguna di situs, saya akan mengikat mereka dengan klien nodejs + websockets dengan php mendorong pembaruan ke nodejs untuk semua pendengar saat perubahan ditambahkan.

Artjom Kurapov
sumber
1
notification_object.object mengidentifikasi tipe perubahan, seperti string "persahabatan" Referensi aktual untuk objek berubah dengan data tambahan yang saya bicarakan adalah di notification_change.notificationObjectID
Artjom Kurapov
2
Ini mungkin pertanyaan bodoh, tetapi dengan pengaturan ini, apa yang Anda lakukan setelah pengguna melihat atau bertindak atas notifikasi? Apakah Anda hanya menghapusnya dari database atau hanya menggunakan tanggal untuk melihat apakah pengguna telah masuk sejak pemberitahuan itu dibuat?
Jeffery Mills
4
Saya tahu topik ini sudah cukup lama, namun saya agak bingung tentang tabel pertama, apa sebenarnya tujuan tabel ini? apa keuntungan memiliki ini sebagai tabel terpisah dibandingkan menempatkan userID di tabel notification_object? Dengan kata lain kapan Anda akan membuat entri baru dalam pemberitahuan dan kapan Anda hanya akan menambahkan objek dan mengubah pemberitahuan yang ada dengan struktur ini?
Bas Goossen
3
@ JefferyMills Anda bisa memiliki bidang status seperti is_notification_readdi notificationtabel dan menandainya dengan tepat jika ya unread, readatau deleted.
Kevin
2
Saya juga telah berjuang untuk memahami beberapa aspek dari solusi ini, dan membuat pertanyaan terpisah tentang hal itu: dba.stackexchange.com/questions/99401/…
user45623
27

Ini benar-benar sebuah pertanyaan abstrak, jadi saya kira kita hanya perlu membahasnya daripada menunjukkan apa yang harus atau tidak seharusnya Anda lakukan.

Inilah yang saya pikirkan tentang kekhawatiran Anda:

  • Ya, sistem notifikasi itu rumit, tetapi tidak terlalu besar. Anda dapat memiliki banyak pendekatan berbeda dalam pemodelan dan penerapan sistem seperti itu, dan mereka dapat memiliki dari tingkat kompleksitas menengah hingga tinggi;

  • Biasanya, saya selalu mencoba membuat hal-hal yang didorong oleh basis data. Mengapa? Karena saya dapat menjamin memiliki kendali penuh atas semua yang terjadi - tetapi itu hanya saya, Anda dapat memiliki kontrol tanpa pendekatan berbasis database; percayalah, Anda akan ingin mengendalikan kasus itu;

  • Biarkan saya memberi contoh kasus nyata untuk Anda, sehingga Anda dapat mulai dari suatu tempat. Pada tahun lalu saya telah membuat model dan menerapkan sistem notifikasi di beberapa jenis jejaring sosial (tidak seperti facebook, tentu saja). Cara saya dulu menyimpan notifikasi di sana? Saya memiliki notificationstabel, tempat saya menyimpan generator_user_id(ID pengguna yang menghasilkan notifikasi), target_user_id(agak jelas, bukan?), notification_type_id(Yang merujuk ke tabel berbeda dengan tipe notifikasi), dan semua hal-hal yang perlu kita isi dengan tabel kita (cap waktu, bendera, dll). notification_typesTabel saya dulunya memiliki hubungan dengannotification_templates tabel, yang menyimpan template spesifik untuk setiap jenis notifikasi. Sebagai contoh, saya memiliki POST_REPLYtipe, yang memiliki jenis template seperti {USER} HAS REPLIED ONE OF YOUR #POSTS. Dari sana, saya baru saja merawat{}sebagai variabel dan #sebagai tautan referensi;

  • Ya, kinerja harus dan harus baik-baik saja. Ketika Anda memikirkan pemberitahuan, Anda berpikir tentang server mendorong dari ujung ke ujung. Entah jika Anda akan melakukannya dengan permintaan ajax atau apa pun, Anda harus khawatir tentang kinerja. Tapi saya pikir itu adalah keprihatinan kedua kalinya;

Model yang saya rancang, tentu saja, bukan satu-satunya yang dapat Anda ikuti, bukan yang terbaik juga. Saya harap jawaban saya, setidaknya, mengikuti Anda ke arah yang benar.

Daniel Ribeiro
sumber
Mengapa saya tidak memiliki kendali dengan beberapa penyimpanan data lainnya?
Jan Hančič
Yah, aku tidak mengatakan itu. Apa yang saya katakan adalah bahwa saya hanya dapat menjamin kontrol data dengan pendekatan berbasis database; tapi itu hanya aku. Saya akan ulangi itu.
Daniel Ribeiro
@DanielRibeiro placeholder ({...}) dalam templat pemberitahuan harus mengganti data placeholder dari set tabel yang berbeda dalam database untuk berbagai jenis notifikasi. Misalnya, satu templat "{user} menyukai foto Anda.", Templat lainnya adalah "{Pagename} Anda memiliki yang baru." Dll {PageName} dan {user} dan placeholder lainnya akan memetakan dari tabel database yang berbeda, jadi apa yang seharusnya menjadi skema untuk mendapatkan nilai placeholder secara dinamis.
Ashish Shukla
DanielRibeiro bagaimana Anda mengganti placeholder seperti yang diminta oleh @Ashish Shukla,
Shantaram Tupe
@AshishShukla sudahkah Anda menggunakan atau mengganti placeholder, dan bagaimana?
Shantaram Tupe
8
╔════════════════════╗
║notification        ║
╟────────────────────╢
║Username            ║
║Object              ║
║verb                ║
║actor               ║
║isRead              ║
╚════════════════════╝

Ini terlihat jawaban yang bagus daripada memiliki 2 koleksi. Anda dapat meminta nama pengguna, objek, dan isRead untuk mendapatkan acara baru (seperti 3 permintaan pertemanan yang tertunda, 4 pertanyaan diajukan, dll ...)

Beri tahu saya jika ada masalah dengan skema ini.

Kaphy
sumber
3
Jawaban teratas menggunakan struktur data yang dinormalisasi, yang berarti tidak ada redudansi dalam tabel. Apakah jawaban Anda melakukan itu?
Aaron Hall
4

Saya pribadi tidak mengerti dengan baik diagram untuk jawaban yang diterima, Jadi saya akan melampirkan basis data diagram berdasarkan apa yang bisa saya pelajari dari jawaban yang diterima dan halaman lain.

masukkan deskripsi gambar di sini

Perbaikan diterima dengan baik.

Jason Glez
sumber
Sepertinya message_template akan ada di tabel NotificationType. Sepertinya main_url juga ada di tabel notifikasi, maka Anda bisa menghilangkan tabel Notification_Message. Bisakah Anda menjelaskan alasan Anda memiliki tabel NotificationMessage sendiri?
Jeff Ryan