Podsumowanie : Dla około 1 miliona aktywnych użytkowników i 150 milionów zapisanych działań, utrzymuję to w prostocie:
- Użyj relacyjnej bazy danych do przechowywania unikalnych działań (1 rekord na działanie / „rzecz, która się wydarzyła”). Uczyń rekordy tak zwartymi, jak to tylko możliwe. Struktura, dzięki której można szybko pobrać pakiet działań według identyfikatora działania lub przy użyciu zestawu identyfikatorów znajomych z ograniczeniami czasowymi.
- Publikuj identyfikatory działań w Redis za każdym razem, gdy tworzony jest rekord aktywności, dodając identyfikator do listy „strumienia aktywności” dla każdego użytkownika, który jest znajomym / subskrybentem, który powinien zobaczyć działanie.
Zapytaj Redis, aby uzyskać strumień aktywności dla dowolnego użytkownika, a następnie w razie potrzeby pobierz powiązane dane z bazy danych. Wróć do odpytywania bazy danych według czasu, jeśli użytkownik musi przeglądać daleko w czasie (jeśli w ogóle to oferujesz)
Używam zwykłej starej tabeli MySQL do obsługi około 15 milionów działań.
Wygląda mniej więcej tak:
id
user_id (int)
activity_type (tinyint)
source_id (int)
parent_id (int)
parent_type (tinyint)
time (datetime but a smaller type like int would be better)
activity_type
informuje mnie o rodzaju czynności, source_id
informuje o zapisie, z którym jest ona związana. Więc jeśli typ działania oznacza „dodane ulubione”, to wiem, że source_id odnosi się do identyfikatora ulubionego rekordu.
parent_id
/ parent_type
Są użyteczne dla mojej aplikacji - mówią mi, jaka działalność jest związana. Gdyby książka została dodana do ulubionych, wtedy parent_id / parent_type powiedziałby mi, że działanie dotyczy książki (typu) z podanym kluczem podstawowym (id)
Indeksuję (user_id, time)
i wyszukuję działania, które są user_id IN (...friends...) AND time > some-cutoff-point
. Porzucenie identyfikatora i wybranie innego indeksu klastrowego może być dobrym pomysłem - nie eksperymentowałem z tym.
Całkiem podstawowe rzeczy, ale działają, są proste i łatwo się z nimi pracuje, gdy zmieniają się Twoje potrzeby. Ponadto, jeśli nie używasz MySQL, możesz być w stanie zrobić to lepiej pod względem indeksowania.
Aby uzyskać szybszy dostęp do najnowszych działań, eksperymentowałem z Redis . Redis przechowuje wszystkie swoje dane w pamięci, więc nie możesz umieścić tam wszystkich swoich działań, ale możesz przechowywać ich wystarczająco dużo dla większości najczęściej odwiedzanych ekranów w Twojej witrynie. Najnowsze 100 dla każdego użytkownika lub coś w tym rodzaju. Z Redisem w miksie może to wyglądać tak:
- Utwórz swój rekord aktywności MySQL
- Dla każdego znajomego użytkownika, który utworzył działanie, umieść identyfikator na jego liście działań w Redis.
- Przytnij każdą listę do ostatnich X elementów
Usługa Redis jest szybka i oferuje sposób przesyłania poleceń w ramach jednego połączenia - więc przekazanie aktywności 1000 znajomym zajmuje milisekundy.
Bardziej szczegółowe wyjaśnienie tego, o czym mówię, można znaleźć w przykładzie Redis na Twitterze: http://redis.io/topics/twitter-clone
Aktualizacja luty 2011 Mam w tej chwili 50 milionów aktywnych działań i niczego nie zmieniłem. Jedną fajną rzeczą w robieniu czegoś podobnego jest to, że używa kompaktowych, małych rzędów. Planuję wprowadzić pewne zmiany, które obejmowałyby znacznie więcej działań i więcej zapytań związanych z tymi działaniami, i na pewno będę używać Redis, aby przyspieszyć działanie. Używam Redis w innych obszarach i naprawdę dobrze działa w przypadku niektórych problemów.
Aktualizacja, lipiec 2014 r. Mamy około 700 tys. Aktywnych użytkowników miesięcznie. Od kilku lat używam Redis (zgodnie z opisem na liście punktowanej) do przechowywania ostatnich 1000 identyfikatorów aktywności dla każdego użytkownika. W systemie jest zwykle około 100 milionów rekordów aktywności i nadal są one przechowywane w MySQL i nadal mają ten sam układ. Te rekordy pozwalają nam uciec z mniejszą ilością pamięci Redis, służą jako zapis danych o aktywności i używamy ich, jeśli użytkownicy muszą cofnąć się w czasie, aby coś znaleźć.
Nie było to sprytne ani szczególnie interesujące rozwiązanie, ale dobrze mi służyło.