𝗞𝗼𝗺𝗽𝗮𝗸𝘁𝗼𝘄𝗲 𝗠𝗲𝘁𝗮𝗱𝗮𝗻𝗲 𝗪𝗶𝗱𝗲𝗼 𝘇 𝗣𝗿𝗼𝘁𝗼𝗯𝘂𝗳
Nasz worker ingestujący pobiera tysiące trendujących filmów co dwie godziny. Przesyłamy te dane do trzech usług: usługi rankingowej, cache warmera oraz zadania analitycznego.
Przez długi czas używaliśmy JSON do przesyłania tych danych. Działało to, dopóki nie zawiodło.
Pojedynczy rekord wideo w formacie JSON zajmował 2,4 KB. Przesyłanie 40 000 rekordów do trzech różnych usług oznaczało przesyłanie 280 MB zbędnego tekstu co dwie godziny. Marnowało to przepustowość i spowalniało nasze workery PHP.
Przeszliśmy na Protocol Buffers (Protobuf). Oto dlaczego i jak zmieniło to nasz system.
Trzy główne problemy z JSON:
- Rozmiar: JSON powtarza nazwy pól w każdym rekordzie. Nazwa pola taka jak "viral_score_24h" zajmuje 15 bajtów tylko po to, aby przekazać 8-bajtową liczbę.
- Koszt parsowania: PHP musi sparsować cały obiekt JSON, nawet jeśli usługa potrzebuje tylko dwóch pól.
- Schema Drift: JSON nie posiada kontraktu. Jeśli jedna usługa zmieni pole, inne ulegną cichej awarii w czasie wykonywania (runtime).
Jak Protobuf rozwiązał ten problem:
Protobuf używa numerów pól zamiast nazw. Wykorzystuje plik .proto jako pojedyncze źródło prawdy (single source of truth). Plik ten generuje kod dla PHP, Pythona i Go. Jeśli zmienisz schemat, kod nie skompiluje się. Dzięki temu błędy czasu wykonywania (runtime) zamieniają się w błędy kompilacji.
Wyniki:
Mierzyliśmy te zmiany przez tydzień:
- Rozmiar payloadu: Spadek z 2,4 KB do 720 bajtów (redukcja o 70%).
- Czas kodowania w PHP: Spadek z 310 ms do 95 ms.
- Czas dekodowania w Go: Spadek z 140 ms do 38 ms.
- Przepustowość: Spadek z 280 MB do 84 MB na cykl.
Kiedy używać Protobuf:
Nie używaj go do wszystkiego. Jeśli Twoje payloade są małe lub potrzebujesz, aby były łatwe do odczytu przez ludzi, pozostań przy JSON. Używaj Protobuf dla dużego natężenia ruchu wewnętrznego, gdzie liczy się przede wszystkim szybkość i ścisłe kontrakty.
Nasze publiczne API wciąż używają JSON. Nasze wewnętrzne usługi używają Protobuf.