Architecture of the WhatsApp System and Ways to Handle Huge Scale (film, 14m)
In his latest video, Coding Chef discusses the architecture and technology behind the WhatsApp application. He begins by mentioning that he has reopened the presale of his coffee course on the kawkasz.fpl website. He then delves into the client-server architecture, which is a core component of the application’s operation. WhatsApp maintains a constant connection to a remote server, allowing for quick reception of messages in push mode. This architecture, while appearing classic, reveals many innovative elements that facilitate the management of an enormous user base with minimal resources. Notably, in 2014, the application supported 400 million users with just 550 servers, which is a remarkable achievement in the programming industry.
Another significant point addressed by Coding Chef is the use of the Erlang programming language, which was designed with telecommunications systems in mind from the beginning. Erlang, known for its high performance and ability to handle multiple users simultaneously, introduces an actor model and allows for code hotswapping, significantly improving system reliability. The author emphasizes that this technology enables WhatsApp to effectively manage billions of connections while ensuring minimal delays in communication. Furthermore, its built-in error tolerance allows the system to automatically rectify issues without impacting overall functionality.
The video also discusses the message storage approach used by WhatsApp. The app employs a transient offline storage method, meaning that messages are temporarily stored on the servers only for the time the recipient is offline. If a user sends a message to a group chat, the server efficiently distributes the message to all participants. Those online receive the message in real-time, while those offline only need to wait until they can connect to the server to retrieve their messages. This data management model effectively meets privacy demands, a critical aspect in today’s internet landscape.
The also highlights the multi-device architecture, which allows users to operate the app on multiple devices simultaneously. This functionality required a transformation of the previous model, enabling each device to operate independently of the phone serving as the main server. Each device connects separately to WhatsApp servers, maintaining end-to-end encryption principles. The author notes that synchronization between devices has also improved, enhancing user experience.
In conclusion, Coding Chef emphasizes the importance of the application's architectural efficiency and WhatsApp's responsible approach to data privacy. Looking at the statistics, the video currently has 5955 views and 239 likes at the time of writing this article. This type of content is not only valuable for programmers but also for anyone interested in technological innovations and the workings of popular applications. Coding Chef effectively sheds light on the complexity of system architectures, making his videos highly educational.
Toggle timeline summary
-
Introduction about the presale of the coffee course.
-
Information about WhatsApp's client-server architecture.
-
WhatsApp connects to remote servers to maintain a constant connection.
-
Use of TCP connection and modified XMPP protocol.
-
Continuous connection allows instant message delivery.
-
WhatsApp's scalability with a small development team.
-
In 2014, WhatsApp had over 400 million users managed by around 550 servers.
-
WhatsApp's use of fewer but powerful servers for efficiency.
-
Geographically distributed architecture to reduce latency.
-
One List mechanism connecting clusters worldwide.
-
Erlang as a technological choice for WhatsApp.
-
Erlang's design for telecommunication systems and reliability.
-
Erlang processes handling user connections.
-
Built-in error tolerance within Erlang.
-
Database management and memory use in WhatsApp.
-
Mnesia as a distributed database solution.
-
Performance issues as WhatsApp scaled.
-
Sending messages from client to WhatsApp server.
-
Presence functionality in WhatsApp infrastructure.
-
Transient offline storage for messages.
-
Similar logic for group chats in message distribution.
-
Message delivery confirmation mechanics.
-
Decoupling components for scalability.
-
Introduction of multi-device support in 2021.
-
New architecture allowing independent device connections.
-
Ensuring privacy with no message storage on servers.
-
Design of multimedia servers for image sharing.
-
End-to-end encryption protocols used by WhatsApp.
-
Group messaging and secure sharing of keys.
Transcription
Na wstępie tylko dodam, że ponownie otworzyłem drugą przedsprzedaż mojego kursu z kawki. Tym razem jest trochę drożej niż poprzednio, ale wciąż jest to promocyjna cena. Wszystkie informacje znajdziesz na stronie kawkasz.fpl Na pierwszy rzut oka WhatsApp ma klasyczną architekturę klient-serwer. Każda aplikacja WhatsAppa na telefonie łączy się ze zdalnym serwerem należącym do WhatsAppa przez internet, utrzymując tym samym stałe i długotrwałe połączenie. W praktyce jest to zazwyczaj połączenie TCP, historycznie wykorzystujące protokół XMPP, który WhatsApp zmodyfikował pod swoje potrzeby. Dzięki utrzymywaniu ciągłego połączenia aplikacja może natychmiast otrzymać nowe wiadomości w trybie push, bez konieczności ciągłego odpłytywania serwera. WhatsApp zasłynął z tego, że osiągnął ogromną skalę przy bardzo małym zespole programistów i relatywnie niewielkiej liczbie maszyn. W 2014 roku obsługiwano ponad 400 mln użytkowników miesięcznie za pomocą około 550 serwerów, co przekładało się na około 2 mln jednoczesnych połączeń na każdym z nich. WhatsApp osiągnął to m.in. dzięki stosowaniu mniejszej ilości, ale mocniejszych serwerów, co zmniejsza złożoność operacyjną, bo mniej serwerów do zarządzania, to mniej awarii. Każdy serwer, to tzw. chat-serwer, zdolny obsłużyć ogromną liczbę klientów jednocześnie. Architektura jest rozproszona geograficznie, aby użytkownicy łączyli się do najbliższego regionu, co zmniejsza opóźnienia oraz rozkładał obciążenie globalnie. Komunikację między klastrami w różnych częściach świata rozwiązano m.in. mechanizmem One List, który łączy klastry w różnych datacenter i zapewnia, że wiadomość znajdzie właściwą drogę. Jednym z najważniejszych wyborów technologicznych WhatsAppa był język Erlang, bo to w nim zapisane są główne serwery obsługujące chat. Erlang został zaprojektowany do systemów telekomunikacyjnych, od początku stawiając na współbieżność i niezawodność. Ma on wbudowany model aktorów i lekki wątek dla każdej niezależnej jednostki, a w przypadku WhatsAppa można sobie wyobrazić, że każde połączenie użytkownika z serwerem jest obsługiwane przez osobny proces Erlanga. Te procesy są ultralekkie i mogą być ich imelnione na jednym serwerze bez problemu z przełączeniem kontekstu, co właśnie pozwalało utrzymać milion jednoczesnych użytkowników. Po drugie Erlang ma wbudowaną tolerancję błędów, pozwalając procesowi się wykrzaczyć, a inny proces nadzorujący to wychwyci i zrestartuje go w czysty sposób. Dzięki temu system może jakby samoistnie leczyć się z drobnych błędów bez wpływu na całość. No i po trzecie, czyli hotswap code, czyli Erlang pozwala wgrać nową wersję kodu na działający serwer bez zatrzymywania procesu, co pozwala aktualizować serwery bez przerw. Wspomnijmy też o bazach danych. Whatsapp starał się unikać nadmiarowej złożoności, więc wiele rzeczy przechowywał w pamięci, korzystając choćby z Mnezji, czyli wbudowanej rozproszonej bazy danych Erlanga. Mnezja pozwalała trzymać dane w RAM z opcją zapisu na dysk i łatwo replikować je między Erlangowymi noadami. Wczesna architektura Whatsappa używała Mnezji na przykład do tymczasowego przechowywania wiadomości i metadanych multimediów, o czym za chwilę. Jednak przy ogromnej skali zaczęły się pojawiać problemy z wydajnością. Oficjalnie Whatsapp nie zraza wielu szczegółów na temat swoich baz danych, ale możemy założyć, że np. informacje o użytkownikach, profilach czy grupach oraz niektóre lodi są trzymane w skalowalnych bazach zdolnych obsłużyć miliardy wpisów. Natomiast sama treść wiadomości nie jest trwale przechowywana na serwerach, co wynika z podejścia do prywatności i szyfrowania danych. Gdy piszesz wiadomość i klikasz wyślij, to aplikacja klienta na Twoim telefonie natychmiast pakuje tę wiadomość i wysyła ją przez wcześniej ustanowione stałe połączenie do serwera Whatsapp. Ten serwer to wspomniany chat serwer, czyli węzeł w klastrze, który obsługuje Twoje połączenie. Zwykle będzie to serwer w najbliższym Tobie datacenter. No i ta wiadomość jest opatrzona m.in. Twoim ID, ID czatu i odbiorcy, no i oczywiście treścią zaszyfrowaną end-to-end, ale o tym później. Serwer otrzymujący wiadomość sprawdza do kogo jest ona skierowana. Jeśli jest to chat indywidualny, to musi znaleźć gdzie znajduje się urządzenie odbiorcy i czy jest online, a jeśli tak, to na którym serwerze ma otwarte połączenie. Whatsapp utrzymuje w swojej infrastrukturze informację, który użytkownik jest podłączony do którego serwera. Jest to część funkcji presence. Jeśli odbiorca jest online, to serwer nadawcy może przekazać wiadomość bezpośrednio do serwera obsługującego odbiorcę. Oba serwery, czyli nadawcy i odbiorcy, mogą komunikować się w ramach klastra lub między klastrami wykorzystując mechanizm rozproszony Erlanga, jak wspomniany Wendlist. Dzięki temu wiadomość trafia do właściwego procesu obsługującego dany telefon odbiorcy. Jeśli odbiorca jest aktualnie offline, czyli nie ma ustalonego połączenia ze serwerem, tutaj wchodzi rola tymczasowego przechowania i Whatsapp stosuje tzw. transient offline storage. Oznacza to, że wiadomość jest przechowywana na serwerach tylko tak długo, aż urządzenie odbiorcy ją odbierze. W praktyce więc wiadomość może trafić do bazy w pamięci, np. do domencji lub innej kolejki przypisanej do odbiorcy, no i tam sobie będzie czekać. Gdy odbiorca znów się połączy, to serwer znajdzie wszystkie zaległe wiadomości, przekaże mu i następnie usunie je z serwera, czyli nie ma żadnej trwałej chmury z historią czatów po stronie serwera, co wpływa właśnie na prywatność. A co jeśli wiadomość jest wysłana do czatu grupowego? Tutaj logika jest podobna, tylko że serwer musi powielić wiadomość do wielu odbiorców. Jeden użytkownik może być w grupie z powiedzmy 50 osobami, nie wysyła więc 50 osobnych kopii z telefonu, tylko jedną do serwera. Następnie serwer dokonuje fanout, czyli dystrybuuje tę wiadomość do wszystkich uczestników grupy. Każdy uczestnik, który jest online dostaje ją w czasie rzeczywistym, a jeśli ktoś jest offline, to jego kopia czeka offline tak jak opisałem wcześniej. Gdy serwer przekazuje wiadomość do procesu obsługującego urządzenie odbiorcy, ta zostaje wysłana przez utrzymywany kanał TCP do aplikacji klienckiej. Telefon odbiorcy natychmiast ją deszyfruje i wyświetla w aplikacji. Mój telefon, czyli nadawca, otrzyma natomiast od serwera potwierdzenie. Jeden ptaszek pojawia się, gdy wiadomość dotrze do serwera, a dwa ptaszki, gdy została dostarczona do telefonu odbiorcy. Te statusy to nic innego jak mechanizm ACK, czyli potwierdzeń na poziomie aplikacji. Telefon odbiorcy po odebraniu wiadomości wysyła do serwera komunikat potwierdzający, który serwer przekazuje z powrotem do ciebie. Dzięki temu wiesz, że odbiorca na pewno dostał wiadomość, nawet jeśli jeszcze jej nie przeczytał. Gdy otworzy i przeczyta, to jego aplikacja wyśle kolejny komunikat, tzw. read-received, który skutkuje zmianą tych ptaszków na niebieskie u ciebie. W systemach tej skali zawsze istnieje ryzyko, że jakiś komponent stanie się wąskim gardłem i spowoduje efekt domina, np. zapchana kolejka opóźni inne wiadomości. Stosuje się więc zasady decoupling, czyli rozluźniania powiązań między komponentami. Wszystko jest partycjonowane i asynchroniczone jak tylko się da. Przykładowo, jeśli jedna grupa użytkowników powoduje ogromny ruch, to ich komunikacja jest odseparowana na oddzielnych procesach albo partycjach, tak by reszta systemu nie odczuła spowolnienia. Wykorzystuje się kolejki i różne priorytety, np. osobne kolejki dla operacji odczytu i zapisu w bazie, żeby wolniejszy zapis nie blokował szybkich odczytów. Whatsapp zyskał również stabilność dzięki temu, że trzyma rzeczy w pamięci. Dyski i operacje IO są dużo wolniejsze niż RAM, więc dzięki trzymaniu np. oczekujących wiadomości w rozproszonej bazie w pamięci mogli zachować wysoką przepustowość, czyli to co nie musi być zapisane jest po prostu trzymane tyle ile trzeba, a potem znika. Kolejną techniką jest monitorowanie pików i zapewnienie odpowiedniego headroomu, czyli zapasu mocy np. na życzenia noworoczne wysyłane o północy przez setki milionów ludzi jednocześnie. Przez wiele lat Whatsapp miał jedno z ograniczeń, czyli konto Whatsapp było ściśle powiązane z jednym telefonem. Owszem, istniała opcja Whatsapp Web czy Desktop, ale one działały tylko jako odbicie lustrzane telefonu, czyli wymagałyby telefonu być w pobliżu i online, bo to on pełnił rolę głównego węzła szyfrującego i wysyłającego wiadomości. Jednak w 2021 roku wprowadzono multi-device, czyli możliwość korzystania z Whatsappu na wielu urządzeniach na raz bez ciągłego połączenia z telefonem. Wymagało to poważnej zmiany architektury, bo trzeba było usunąć smartfon z roli serwera i umożliwić bezpośrednią komunikację innych urządzeń z chmurą Whatsapp. Jak więc to rozwiązano? Nowa architektura multi-device opiera się na idei, że użytkownik może mieć do pięciu urządzeń, czyli jeden telefon i cztery inne, a każdy z nich łączy się niezależnie do serwerów Whatsapp. Wszystkie urządzenia nadal utrzymują szyfrowanie end-to-end, ale skoro nie komunikują się przez telefon, to Whatsapp musiał zapewnić synchronizację danych między nimi poprzez swoją infrastrukturę, jednocześnie nie mając wglądu w te dane. Rozwiązano to następująco. Każde urządzenie, czyli telefon, laptop i tablet ma własną parę kluczy i ustanawia zaszyfrowany kanał z każdym innym urządzeniem w ramach tego samego konta oraz z urządzeniami kontaktów. Gdy wysyłasz wiadomość, a jesteś np. zalogowany na telefonie i laptopie, to twój telefon albo urządzenie z którego piszesz wykona tzw. client fanout, czyli wielokrotne zaszyfrowanie i wysłanie wiadomości do wielu odbiorców. W przypadku czatu 1-1 z inną osobą, która ma np. dwa urządzenia, twoja wiadomość zostanie osobno zaszyfrowana kluczem dla urządzenia A i urządzenia B odbiorcy oraz jeśli masz więcej niż jedno urządzenie, to dodatkowo wyślesz kopię na swoje pozostałe urządzenia. Brzmi to mało efektywnie, ale gwarantuje, że każde urządzenie otrzyma wiadomość w formie, którą potrafi odszyfrować, no i że serwer nie musi nic odszyfrowywać ani doklejać kluczy, on tylko przekazuje pakiety wiadomości dalej. Whatsapp sam potwierdza, że wiadomości nie są przechowywane na serwerze po dostarczeniu nawet w trybie multi-device, dzięki temu utrzymaną obietnicę prywatności. No ale co z historią czatów na nowo podłączonym urządzeniu? Kiedy podłączysz np. nowy komputer do swojego konta, to twój telefon jako urządzenie pierwotne tworzy paczkę zawierającą ostatnie wiadomości z każdej rozmowy, szyfruje jej asymetrycznie dla nowego urządzenia i wysyła przez serwer. Nowe urządzenie pobiera ten zaszyfrowany plik, odszyfruje go u siebie i ma bazę startową wiadomości. Ten transfer jest jednorazowy i zaszyfrowany end-to-end. Nowe urządzenie klucz do odszyfrowania dostaje również w bezpieczny sposób. Po tym wstępnym zrzucie każde urządzenie prowadzi już swoją lokalną bazę danych czatów. Pozostaje też kwestia ciągłej synchronizacji pewnych rzeczy, np. stanów aplikacji, czyli oznaczenie wiadomości gwiazdką, wyciszenie jakiegoś czatu, zmiana nazwy grupy itd. Takie rzeczy mogą być wymieniane z różnych urządzeń i powinny się zsynchronizować. WhatsApp rozwiązał to przechowując zaszyfrowaną kopię stanu na swoich serwerach. Każdy element stanu, nazwijmy je dane aplikacyjne typu lista zarchiwizowanych czatów, kontakty itd. jest szyfrowany end-to-end kluczem znanym tylko urządzeniem użytkownika, a serwer trzyma tę zaszyfrowaną informację i pośredniczy w jej aktualizacji. Co ciekawe zaszyfrowane są nie tylko same dane, ale także meta informacji o tym co to są za dane, czyli serwer nie wie czy ta paczka to np. lista ulubionych wiadomości, czy ustawienia powiadomień. Wszystko widzi jako ciąg zaszyfrowany. Gdy zmienisz np. zdjęcie profilowe na jednym urządzeniu, to zostanie to zaszyfrowane i zaktualizowane na serwerze, a inne twoje urządzenia odbiorą te zmiany i odszyfrują u siebie, dzięki czemu zachowają spójność. Oprócz wiadomości tekstowych, Whatsapp obsługuje również multimedia. Jak więc zaprojektować system, który dostarczy np. 2 mld zdjęć w ciągu doby? Oprócz czat serwerów do obsługi tekstu, o którym mówiłem wcześniej, są też MMS Servers, czyli Multimedia Servers, przeznaczone do obsługi uploadu i downloadu załączników. Proces wysłania zdjęcia przebiega mniej więcej tak. Telefon nadawcy szyfruje zdjęcia lokalnie. Zaszyfrowany plik trafia do serwera multimedialnego jako zwykły blob. Równolegle wysyłana jest mała wiadomość z kluczem i innymi linkami do plików. Telefon odbiorcy odszyfruje metawiadomość, pobiera plik, po czym sprawdza hasz i odszyfrowuje zdjęcie. Powyższy proces gwarantuje pełne szyfrowanie end-to-end załączników, czyli serwery przechowują plik, ale nie mają klucza by go odszyfrować. Klucze przekazano w bezpiecznej wiadomości tylko docelowemu użytkownikowi. Od 2016 roku każda wiadomość, załącznik i rozmowa w Whatsappie są domyślnie szyfrowane end-to-end. Treść opuszcza telefon nadawcy już zaszyfrowana i może ją odszyfrować wyłącznie urządzenie odbiorcy, więc serwery metanie widzą zawartości. Whatsapp używa sprawdzonego protokołu Signal z mechanizmem Double Ratchet i Perfect Forward Secrecy, czyli nawet jeśli jakimś cudem ktoś przechwyci Twój klucz za jakiś czas, to nie będzie w stanie odszyfrować starych wiadomości, bo klucze ciągle się zmieniają dla kolejnych wiadomości. Każda rozmowa w Whatsappie ma swój zestaw kluczy. Stały klucz tożsamości każdej strony, klucze sesyjne negocjowane przy rozpoczęciu czatu i potem dynamicznie zmienione klucze dla każdej kolejnej wiadomości. Warto dodać, że szyfrowanie obejmuje też grupy, gdzie rozwiązano to przez mechanizm klucza grupowego zwanego Sender Key. Działa to tak, że w grupie ustanawia się jeden wspólny klucz symetryczny dla wszystkich członków, czyli właśnie Sender Key. Jest on udostępniany każdemu członkowi przez nadawcę za pomocą ich indywidualnych sesji szyfrowanych. Dzięki temu, gdy piszesz w grupie do 30 osób, to nie musisz szyfrować wiadomości 30 razy różnymi kluczami. Szyfrujesz raz kluczem grupowym, a serwer robi fanout tej zaszyfrowanej wiadomości do wszystkich. Bezpieczne udostępnianie klucza grupowego następuje przy dołączeniu do grupy i jest aktualizowane, gdy ktoś opuszcza grupę. Wtedy ustanawia się nowy klucz. Jeśli wytrwałeś do tego momentu i coś pożytecznego wyniosłeś z tego filmu, to zostaw łapkę w górę i suba. Yo!