Revolut's infrastructure in numbers

Revolut – architektura

Boiling Frogs 2023 już za nami, nie wiem czy znajdę czas aby podsumować całą konferencję…

Ale przynajmniej chciałbym Wam opisać jedną z ważniejszych prezentacji. Prezentacja Wojtka Ptaka z Revoluta pt. „Hypergrowth scaling made simple”.

Wojtek wziął nas pod włos zaczynając wystąpienie robiąc widowni szybkie „System Design Interview„. Jak to działa? Przychodzimy na rekrutację i dostajemy problem do rozwiązania. Przy każdej iteracji, gdy przedstawimy rozwiązanie rekruter podkręca skalę problemu dodając kolejne wymogi wyimaginowanego Klienta (rekruter nic nie podpowiada, ale może odpowiadać na nasze pytania).
Na tej podstawie przyszła firma jest w stanie określić nasze rzeczywiste doświadczenie i umiejętności zawodowe.

Całość wyglądała jakbyśmy mieli za zadanie zrobić architekturę Revoluta. Zadaniem było zaprojektowanie architektury dla banku, w którym możemy płacić za dany przedmiot/usługę w ecommerce za pomocą karty płatniczej.

Revolut - Let's start
Na wirtualnej rekrutacji poszliśmy w mikroserwisy i Wojtek przedstawił pierwszą iterację, która wyglądała bardzo prawdziwie (Payments Service, Payments Gateway połączony z PSP, a do tego Ledger i Wallet DB).

Następnie okazało się, że odnosimy sukces, bank rośnie, Klientów i operacji przybywa, wchodzimy na kolejne rynki, pojawiają się operacje walutowe.
Dlatego na kolejnych ekranach widzieliśmy jak pojawia się Load Balancer, Kafka, MongoDB (jako cache dla kursów walut), serwis do wysyłki SMS-ów z powiadomieniami o płatnościach, FDS (Fraud Detecton Service). Do tego doszły modele Machine-Learningowe (ML, Spark).
Aby nie powodować opóźnień dla Klientów otwieramy Data Center (DC) na każdym kontynencie, to powoduje, że musimy synchronizować w locie dane. Pojawiają się transakcje rozproszone. Aby to robić musimy mieć zegary atomowe (Spanner, TrueTime & The CAP Theorem)…

W ostateczności wyszła ogromna kobyła, która wydawała się bardzo realna.

Revolut - Nuclear option - ledger .999 availability
Ale to był wkręt 🙂 Zabieg ten miał pokazać, że bardzo skomplikowaną domenę rozwiązaliśmy w bardzo skomplikowany sposób.

Obecnie Revolut ma już ponad 30 mln Klientów na całym globie. A architektura jest o wiele prostsza niż przedstawiona wcześniej.
Musimy pamiętać, że im większego skomplikowanie tym trudniej dane rozwiązanie utrzymywać.

Revolut tak naprawdę posiada prostą architekturę, a na zapleczu korzysta z rozwiązań sieciowych Google Cloud Platform.
Chciano jak najbardziej uniknąć losowości systemu (randomness z książki Waldmana), bo im większe skomplikowanie tym większa losowość w działaniu.

Jak ograniczyć losowość aplikacji/architektury?

  • ograniczyć tooling – wspólna baza dla wszystkich zespołów/projektu (języki programowania, frameworki, biblioteki)
  • ograniczyć procesy – ich ilość i różnorodność, wspólne dla zespołów/projektu
  • umiejętności zespołu – umiejętności, doświadczenie w ramach osób w zespole powinno być podobne

Praca zespołu powinna polegać na zmniejszaniu randomness (losowości). Za wszelką cenę powinniśmy zmniejszać złożonośc systemu poprzez zmniejszanie jego losowości.

Revolut - cloud native by design

Jak do tego aspektu podchodzi Revolut?

  • prosta architektura – skupiamy się na tym co ważne dla firmy – Core, reszta oddelegowana do Google Cloud Platform
  • simplicity standard – ograniczenie ilości narzędzi, standaryzowanie procesów, np. playbook do tworzenia serwisu
  • bardzo skrócona ścieżka feedbacku – TDD na poziomie firmy, testy automatyczne, monitoring, wyśrubowane SLA i MTTR (Mean Time To Recovery)

Prosta architektura to nie tylko slogan, Revolut wprowadził to w życie. Rdzeń systemu opiera się na czystej Javie (Vanilla Java) z użyciem wewnętrznego frameworku do DDD.
Do tego dochodzi uczenie maszynowe (ML Models) oparte o serwisy w Pythonie, które wykorzystują do wszelkich danych.
Całość opakowana jest w klaster Kubernetes i to wszystko.

Natomiast persitence layer (przechowywanie danych) oparte jest na PostgresSQL, który wykorzystany jest zarówno jako baza danych i Event Store.

Revolut - Architecture components of a global bank

A wszelkie usługi sieciowe zostały wyniesione na zewnątrz do GPC (Google Platform Cloud).

Przede wszystkim szybkość

Wprowadzenie wszystkich wspomnianych standardów spowodowało skupienie się na szybkości – działania, wdrożenia, oddania nowych funkcjonalności.
Większość serwisów (API) odpowiada poniżej 50ms, niektóre w granicach 1ms. Górną granicą ustaloną w Revolut jest 150ms, ale kiedy się do niej zbliżamy musimy się tłumaczyć.

Infrastruktura to ponad 40 klastrów Kubernetes, 1500+ maszyn, 200+ serwisów, 350+ baz danych, gdzie największa to 20+TB danych. I to wszystko obsługuje 12 osób.

Aby osiągnąć wysoką responsywność zespołu są tylko 2 środowiska: dev i prod, ze względu na nastawienie na TDD (testy architektury ewolucyjnej) i nie tylko, w Revolut nie ma stanowiska dla QA Engineer (Quality Assurance).

Zespół

Moim zdaniem sukcesem takiej wydajności i jakości jest odpowiednie podejście do tworzenia zespołu. w Revolut są zespoły produktowe (np. Konta, Karty itd).
Zespół odpowiada za swoje serwisy, pokrycie testami, aktualność testów, optymalizację wydajności.
A do tego dochodzą standardy i wykorzystanie istniejących wzorców architektury, które są z nami od dekad.

Pod tym względem warto obejrzeć prezentację Barry O’Reilly z konferencji DDD Europe 2022, na której opowiada jak trudna jest architektura oprogramowania:

Legacy

Jeśli optymalizujemy na prędkość (hypergrowth) powinniśmy ustalić plan wydawniczy i dowozić go jak najszybciej. Firma powinna zmieniać się szybciej niż aspekty wokół niej (rynkowe, biznesowe).
W takim wypadku zawsze pojawi nam się legacy w projekcie i to jest dobrze. Ponieważ głównym naszym wrogiem jest over-engineering, a nie legacy (YOW! 2011: Eric Evans – Domain Driven Design Strategies for Dealing With Legacy Systems).

To co powinniśmy zrobić to wyeliminować nieodwracalność naszych decyzji w systemie. Bardzo często robimy ogromną ilość przypuszczeń, jak coś powinno funkcjonować. Lepiej w takich wypadkach odwlekać nasze decyzje.

Sposób na sukces wg Revoluta

Stwórz najprostszy produkt, który ma sens, a następnie upewnij się, że jest używany (nie każdy produkt, który ma sens jest używany).
Jeśli to zadziała stwórz odpowiednie metryki biznesowe, podążaj za swoim użytkownikiem, analizuj jego potrzeby.
I w kolejnej iteracji dodaj te funkcjonalności z dużym naciskiem na optymalizację szybkości działania.

Jeśli odnosisz sukces skaluj się za pomocą tych narzędzi, które już posiadasz. A kiedy już Tobie to nie starcza to: refactor, rewrite lub… stwórz nowy produkt.

I na koniec. Większość naszych problemów jest wtórnych, zostały już dawno rozwiązane i wystarczy umieć szukać odpowiedzi. Książki, które takie odpowiedzi przynoszą to:

  • Thinking systems need systems thinking – J. D. Waldman
  • The Software Architect Elevator – Gregor Hohpe
  • Analysis Patterns – Martin Flower
  • Data Model Patterns – David C. Hay
  • The Data Model Resource Book – Len Silverston