Jestem na początku budowania systemu powiadomień w stylu Facebooka dla naszej strony (typ gier społecznościowych) i teraz badam, jak najlepiej zaprojektować taki system. Nie interesuje mnie, jak wysyłać powiadomienia do użytkownika ani nic w tym rodzaju (na razie nawet). Badam, jak zbudować system na serwerze (jak przechowywać powiadomienia, gdzie je przechowywać, jak je pobrać itp.).
A więc ... niektóre wymagania, które mamy:
- w godzinach szczytu mamy około 1 tys. jednocześnie zalogowanych użytkowników (i znacznie więcej gości, ale nie mają oni tutaj znaczenia, ponieważ nie będą mieli powiadomień), które wygenerują wiele zdarzeń
- będą różne rodzaje powiadomień (użytkownik A dodał Cię jako znajomego, użytkownik B skomentował Twój profil, użytkownik C polubił Twój obraz, użytkownik D pokonał Cię w grze X, ...)
- większość wydarzeń wygeneruje 1 powiadomienie dla 1 użytkownika (użytkownik X polubił Twój obraz), ale zdarzają się przypadki, gdy jedno zdarzenie wygeneruje wiele powiadomień (na przykład urodziny użytkownika Y)
- powiadomienia powinny być zgrupowane razem; jeśli na przykład czterech różnych użytkowników lubi jakiś obraz, właściciel tego obrazu powinien otrzymać jedno powiadomienie informujące, że obraz podobał się czterem użytkownikom, a nie cztery oddzielne powiadomienia (tak jak robi to FB)
OK, więc pomyślałem, że powinienem stworzyć coś w rodzaju kolejki, w której będę przechowywać zdarzenia, gdy się pojawią. Wtedy miałbym zadanie w tle ( biegacz ?), Które przeglądałoby tę kolejkę i generowało powiadomienia na podstawie tych zdarzeń. To zadanie przechowuje następnie powiadomienia w bazie danych dla każdego użytkownika (więc jeśli zdarzenie dotyczy 10 użytkowników, byłoby 10 oddzielnych powiadomień). Następnie, gdy użytkownik otwierał stronę z listą powiadomień, czytałem mu wszystkie te powiadomienia (myśleliśmy o tym, żeby ograniczyć to do 100 najnowszych) i grupowałem je razem, a na koniec wyświetlałem.
Rzeczy, które mnie interesują w przypadku tego podejścia:
- skomplikowane jak diabli :)
- czy baza danych to najlepsza pamięć masowa tutaj (używamy MySQL), czy powinienem użyć czegoś innego (redis też wydaje się pasować)
- co mam przechowywać jako powiadomienie? identyfikator użytkownika, identyfikator użytkownika, który zainicjował zdarzenie, typ zdarzenia (żebym mógł je pogrupować i wyświetlić odpowiedni tekst), ale wtedy trochę nie wiem, jak przechowywać rzeczywiste dane powiadomienia (na przykład adres URL i tytuł obrazu, który był lubiany). Czy powinienem po prostu „upiec” te informacje podczas generowania powiadomienia, czy też powinienem zapisać identyfikator rekordu (obraz, profil, ...), na który ma to wpływ, i wyciągnąć informacje z bazy danych podczas wyświetlania powiadomienia.
- wydajność powinna być tutaj OK, nawet jeśli muszę przetwarzać 100 powiadomień w locie podczas wyświetlania strony powiadomień
- możliwy problem z wydajnością przy każdym żądaniu, ponieważ musiałbym wyświetlać użytkownikowi liczbę nieprzeczytanych powiadomień (co mogłoby być problemem samo w sobie, ponieważ grupowałbym powiadomienia razem). Można by tego jednak uniknąć, gdybym wygenerował widok powiadomień (gdzie są one zgrupowane) w tle, a nie w locie
Co myślisz o zaproponowanym przeze mnie rozwiązaniu i moich obawach? Proszę o komentarz, jeśli sądzisz, że powinienem wspomnieć o czymś innym, co byłoby tutaj istotne.
Och, używamy PHP dla naszej strony, ale myślę, że nie powinno to być dużym czynnikiem.
źródło
Odpowiedzi:
Powiadomienie dotyczy czegoś (obiekt = wydarzenie, przyjaźń ...), które zostało zmienione (czasownik = dodane, zażądane ..) przez kogoś (aktora) i zgłoszone użytkownikowi (podmiotowi). Oto znormalizowana struktura danych (chociaż korzystałem z MongoDB). Musisz powiadomić niektórych użytkowników o zmianach. Więc są to powiadomienia dla każdego użytkownika… co oznacza, że jeśli było zaangażowanych 100 użytkowników, generujesz 100 powiadomień.
(Dodaj pola czasu tam, gdzie uważasz za stosowne)
Zasadniczo służy to do grupowania zmian według obiektu, aby można było powiedzieć „Masz 3 zaproszenia do znajomych”. Przydatne jest grupowanie według aktorów, dzięki czemu można powiedzieć „Użytkownik James Bond dokonał zmian w Twoim łóżku”. Daje to również możliwość tłumaczenia i liczenia powiadomień według własnego uznania.
Ale ponieważ obiekt jest tylko identyfikatorem, musiałbyś uzyskać wszystkie dodatkowe informacje o obiekcie za pomocą oddzielnych wywołań, chyba że obiekt faktycznie się zmienia i chcesz pokazać tę historię (na przykład „użytkownik zmienił tytuł zdarzenia na ... ")
Ponieważ powiadomienia są zbliżone do czasu rzeczywistego dla użytkowników witryny, powiązałbym je z klientem nodejs + websockets z aktualizacją php push do nodejs dla wszystkich słuchaczy w miarę dodawania zmian.
źródło
is_notification_read
wnotification
tabeli i odpowiednio je oznaczyć, jeśli tak jestunread
,read
lubdeleted
.To naprawdę abstrakcyjne pytanie, więc myślę, że będziemy musieli je po prostu przedyskutować, zamiast wskazywać, co należy, a czego nie.
Oto, co myślę o Twoich obawach:
Tak, system powiadomień jest złożony, ale nie tak diabli. Możesz mieć wiele różnych podejść do modelowania i wdrażania takich systemów, od średniego do wysokiego poziomu złożoności;
Osobiście zawsze staram się, aby rzeczy były oparte na bazie danych. Czemu? Ponieważ mogę zagwarantować pełną kontrolę nad wszystkim, co się dzieje - ale to tylko ja, możesz mieć kontrolę bez podejścia opartego na bazie danych; zaufaj mi, będziesz chciał mieć kontrolę nad tą sprawą;
Pozwólcie, że zilustruję prawdziwy przypadek dla Ciebie, abyś mógł zacząć od czegoś. W zeszłym roku wymodelowałem i wdrożyłem system powiadomień w jakiejś sieci społecznościowej (oczywiście nie takiej jak facebook). W jaki sposób przechowywałem tam powiadomienia? Miałem
notifications
tabelę, w której zachowałemgenerator_user_id
(identyfikator użytkownika, który generuje powiadomienie),target_user_id
(rodzaj oczywiste, prawda?),notification_type_id
(Który odwołuje się do innej tabeli z typami powiadomień) i wszystko potrzebne rzeczy, które musimy wypełnić w naszych tabelach (znaczniki czasu, flagi itp.). Mojanotification_types
tabela była powiązana znotification_templates
tabelą, która zawierała określone szablony dla każdego typu powiadomienia. Na przykład miałemPOST_REPLY
typ, który miał podobny szablon{USER} HAS REPLIED ONE OF YOUR #POSTS
. Stamtąd właśnie potraktowałem plik{}
jako zmienna i#
jako odsyłacz;Tak, wydajność powinna i musi być w porządku. Kiedy myślisz o powiadomieniach, myślisz o przepychaniu się serwera od stóp do głów. Albo jeśli zamierzasz to zrobić z żądaniami Ajaxa lub czymkolwiek, będziesz musiał martwić się o wydajność. Ale myślę, że to drugi problem;
Model, który zaprojektowałem, nie jest oczywiście jedynym, który możesz naśladować, ani też najlepszy. Mam nadzieję, że przynajmniej moja odpowiedź podąży za tobą we właściwym kierunku.
źródło
Wygląda na to, że jest to dobra odpowiedź, a nie dwie kolekcje. Możesz zapytać o nazwę użytkownika, obiekt i isRead, aby uzyskać nowe zdarzenia (takie jak 3 oczekujące zaproszenia do znajomych, 4 zadawane pytania itp.)
Daj mi znać, jeśli jest problem z tym schematem.
źródło
Osobiście nie rozumiem zbyt dobrze diagramu zaakceptowanej odpowiedzi, więc dołączę diagram bazy danych w oparciu o to, czego mogłem się nauczyć z zaakceptowanej odpowiedzi i innych stron.
Ulepszenia są dobrze odbierane.
źródło