Raportowanie ponad 15 mln zdarzeń dziennie
Zastąpiliśmy przestarzały system raportowania kolejką, która przechowuje każde zdarzenie do momentu potwierdzenia odbioru przez grupę kapitałową, wysyła je dokładnie raz i w kilka minut skaluje się z popołudniowego strumienia do całodniowego zaległego wolumenu.
Kontekst
Krajowy operator raportuje każde zdarzenie operacyjne do grupy kapitałowej, do której należy. Każdej nocy grupa mierzy odsetek zdarzeń dostarczonych na czas, a wynik zasila korporacyjne wskaźniki KPI, od których zależą premie pracowników. Stary system zapisywał pliki w formacie z innej epoki, nie prowadził rejestru losów poszczególnych zdarzeń i nie był w stanie obsłużyć nowego schematu JSON, nowego API ani nowych typów zdarzeń wprowadzanych przez grupę. Zastąpiliśmy go nowym rozwiązaniem.
Ograniczenia
- Każde zdarzenie musi zostać wysłane dokładnie raz. Zdarzenie czeka w kolejce, dopóki grupa nie potwierdzi jego odbioru - nic nie ginie i nic nie jest wysyłane podwójnie.
- Obciążenie napływa falami: większość dziennych zdarzeń pojawia się przed południem, a po południu ruch jest niewielki. Po awarii wolumen z całego dnia trafia do systemu w ciągu kilku minut i nadal musi zostać przetworzony przed nocnym oknem rozliczeniowym.
- Punkt końcowy grupy potrafi zwrócić błąd 500. W takiej sytuacji ciężar dowodu spoczywa na nadawcy, dlatego każda próba wysyłki musiała być rejestrowana.
- Systemów źródłowych nie można było przepisać. Jedyną dopuszczalną zmianą po ich stronie było miejsce zapisu plików.
Co zbudowaliśmy
Stary system nadal generował swoje pliki - jedyną zmianą było kierowanie ich do zasobnika Cloud Storage. Funkcja Cloud Function odczytuje każdy plik partiami, mapuje rekordy na nowy schemat i zapisuje je w bazie Spanner, porównując liczbę wierszy z nagłówka pliku z liczbą zapisanych rekordów. Dzięki temu ewentualna utrata danych jest wychwytywana już na etapie przyjęcia, a nie dopiero w przyszłomiesięcznym raporcie KPI.
Kolejka jest utrzymywana w bazie Spanner. Podczas porannej fali obciążenia pojawiały się w niej tzw. hotspoty, dlatego kolejkę podzielono na szardy (partycje), a każdy worker wysyłający obsługuje własny szard. Workery to funkcje Cloud Functions uruchamiane równolegle przez Pub/Sub, a ich liczba dostosowuje się do głębokości kolejki: od kilku po południu do kilkuset po awarii. Każda operacja na zdarzeniu jest zapisywana bezpośrednio przy nim - każda próba, każda odpowiedź od grupy, każde ponowienie - dzięki czemu pełną historię dowolnego zdarzenia można odczytać jednym zapytaniem. Po potwierdzeniu odbioru zdarzenie trafia do archiwum w BigQuery i jest usuwane ze Spannera.
Kluczową metryką jest stosunek głębokości kolejki do tempa wysyłki, bezpośrednio połączony z systemem alertowania: gdy kolejka rośnie szybciej, niż workery są w stanie ją opróżniać, dyżurny inżynier otrzymuje automatyczne połączenie telefoniczne na długo przed tym, zanim zagrożona będzie godzina graniczna.
Rezultat
Ponad 15 mln zdarzeń wychodzących i do 3 mln przychodzących dziennie - każde w pełni rozliczone. Po raz pierwszy biznes zobaczył, gdzie i dlaczego giną zdarzenia. Okazało się, że większość problemów leży u źródła: klienci nie dostarczali danych wymaganych przez grupę, przez co zdarzenia były odrzucane już na wejściu. Twarde dowody przeniosły dyskusję o KPI z samego potoku przetwarzania na jakość danych źródłowych. System został zaprojektowany i poprowadzony przez Jakuba, zbudowany w zespole trzech osób w ciągu dwóch, trzech miesięcy i nadal jest używany każdego dnia.
Technologia
Google Cloud: Spanner, Cloud Functions, Pub/Sub, Cloud Storage, BigQuery, Cloud Logging oraz Cloud Monitoring.