Historia architektury Dodo IS: droga back-office’u

Habr zmienia świat. Od ponad roku prowadzimy naszego bloga. Po około sześciu miesiącach otrzymaliśmy całkiem logiczną informację zwrotną od użytkowników Habr: „Dodo, mówicie wszędzie, że macie swój system. Co to za system? I po co jest potrzebny sieci pizzerii?”.

Usiedliśmy, pomyśleliśmy i zrozumieliśmy, że macie rację. Staramy się wszystko wyjaśnić w prosty sposób, ale wychodzi to w urwanych fragmentach i nigdzie nie ma pełnego opisu systemu. Tak rozpoczął się długi proces zbierania informacji, poszukiwania autorów i pisania serii artykułów o Dodo IS. Startujemy!

Podziękowania: dziękujemy, że dzielicie się swoją informacją zwrotną. Dzięki niej w końcu opisaliśmy system, stworzyliśmy technoradar i wkrótce opublikujemy duży opis naszych procesów. Bez was wciąż siedzielibyśmy jeszcze 5 lat.

Historia architektury Dodo IS: droga back-office’u

Seria artykułów „Czym jest Dodo IS?” opowie o:

  1. Wczesny monolit w Dodo IS (2011-2015). (W trakcie…)
  2. Droga back-office: osobne bazy i szyna. (Jesteś tutaj)
  3. Droga części klienckiej: fasada nad bazą (2016-2017). (W trakcie…)
  4. Historia prawdziwych mikroserwisów. (2018-2019). (W trakcie…)
  5. Zakończony podział monolitu i stabilizacja architektury. (W trakcie…)

Jeśli chcesz dowiedzieć się czegoś więcej — pisz w komentarzach.

Opinia o chronologicznym opisie od autora
Regularnie organizuję spotkanie dla nowych pracowników na temat „Architektura systemu”. Nazywa się to „Wprowadzenie do architektury Dodo IS” i jest częścią procesu onboardingu nowych programistów. Opowiadając o naszej architekturze, o jej cechach, opracowałem pewne podejście historyczne do opisu.

Tradycyjnie postrzegamy system jako zbiór komponentów (technicznych lub bardziej ogólnych), modułów biznesowych, które współdziałają ze sobą w celu osiągnięcia określonego celu. I jeśli w projektowaniu taki punkt widzenia jest uzasadniony, to do opisu i zrozumienia nie do końca pasuje. Powody są różne:

  • Rzeczywistość różni się od tego, co na papierze. Nie wszystko, co zostało zaplanowane, udaje się zrealizować. A nas interesuje, jak naprawdę wszystko wygląda i działa.
  • Sekwencyjne przedstawienie informacji. W zasadzie można przejść chronologicznie od początku do obecnego stanu.
  • Od prostego do złożonego. Nie jest uniwersalne, ale w naszym przypadku tak właśnie było. Od prostszych podejść architektura przechodziła do bardziej skomplikowanych. Często poprzez komplikację rozwiązywano problemy z szybkością realizacji i stabilnością, a także dziesiątki innych właściwości z listy wymagań niefunkcjonalnych (tutaj dobrze opisano przeciwstawienie złożoności innym wymaganiom).

W 2011 roku architektura Dodo IS wyglądała tak:

Historia architektury Dodo IS: droga back-office’u

Do 2020 roku nieco się skomplikowała i wyglądała tak:

Historia architektury Dodo IS: droga back-office’u

Jak nastąpiła ta ewolucja? Po co potrzebne są różne części systemu? Jakie decyzje architektoniczne podjęto i dlaczego? Rozwiążemy to w tej serii artykułów.

Pierwsze problemy z 2016 roku: po co usługi musiały opuścić monolit

Pierwsze artykuły z cyklu będą dotyczyć usług, które jako pierwsze oddzieliły się od monolitu. Żeby wprowadzić was w kontekst, opowiem, jakie problemy mieliśmy w systemie na początku 2016 roku, co musieliśmy zrobić, aby zrealizować podział usług.

Jedna baza MySql, do której wszystkie aplikacje, istniejące wówczas w Dodo IS, zapisywały swoje dane. Skutki były następujące:

  • Duże obciążenie (przy czym 85% zapytań dotyczyło odczytu).
  • Baza się powiększała. Z tego powodu jej koszt i wsparcie stały się problemem.
  • Jedyny punkt awarii. Jeśli jedna aplikacja, pisząca do bazy, nagle zaczynała działać aktywniej, inne aplikacje odczuwały to na sobie.
  • Nieefektywność w przechowywaniu i zapytaniach. Często dane były przechowywane w pewnej strukturze, która była wygodna dla jednych scenariuszy, ale nie nadawała się do innych. Indeksy przyspieszały jedne operacje, ale mogły spowalniać inne.
  • Część problemów rozwiązali pośpiesznie zrobione cache i repliki read dla baz (o tym będzie osobny artykuł), ale one jedynie pozwoliły zyskać czas i zasadniczo problemu nie rozwiązały.

Problemem było samo istnienie monolitu. Skutki były następujące:

  • Jednolite i rzadkie wydania.
  • Trudności we wspólnej pracy dużej liczby ludzi.
  • Niemożność wprowadzania nowych technologii, nowych frameworków i bibliotek.

Problemy z bazą i monolitem były wielokrotnie opisywane, na przykład w kontekście awarii na początku 2018 roku (Bądź jak Munk, czyli kilka słów o długu technicznym, Dzień, w którym Dodo IS się zatrzymała. Asynchroniczny scenariusz i Historia o ptaku Dodo z rodziny Feniksów. Wielki upadek Dodo IS), więc nie będę się zbytnio zatrzymywał. Powiem tylko, że chcieliśmy zapewnić większą elastyczność w opracowywaniu usług. W pierwszej kolejności dotyczyło to tych, które były najbardziej obciążone i kluczowe w całym systemie — Auth i Tracker.

Droga zaplecza: oddzielne bazy i magistrala

Nawigacja po rozdziale

  1. Schemat monolitu z 2016 roku
  2. Zaczynamy odciążanie monolitu: wydzielenie Auth i Trackera
  3. Czym zajmuje się Auth
  4. Skąd pochodzą obciążenia?
  5. Odciążamy Auth
  6. Czym zajmuje się Tracker
  7. Skąd pochodzą obciążenia?
  8. Odciążamy Tracker

Schemat monolitu z 2016 roku

Przed Państwem główne bloki monolitu Dodo IS z 2016 roku, a nieco niżej objaśnienie ich głównych zadań.
Historia architektury Dodo IS: droga back-office’u
Kasa Dostaw. Zarządzanie kurierami, wydawanie zamówień kurierom.
Centrum Kontaktowe. Przyjmowanie zamówień przez operatora.
Strona. Nasze strony (dodopizza.ru, dodopizza.co.uk, dodopizza.by itd.).
Auth. Usługa autoryzacji i uwierzytelniania dla zaplecza.
Tracker. Tracker zamówień w kuchni. Usługa oznaczania statusów gotowości podczas przygotowywania zamówień.
Kasa Restauracji. Przyjmowanie zamówień w restauracji, interfejsy kasjera.
Eksport. Eksport raportów do 1C dla księgowości.
Powiadomienia i dokumenty. Komendy głosowe w kuchni (na przykład, „Przyszła nowa pizza”) + drukowanie dokumentów dla kurierów.
Menadżer Zmiany. Interfejsy dla menedżera zmiany: lista zamówień, grafiki wydajności, wyświetlanie pracowników na zmianie.
Menadżer Biura. Interfejsy dla franczyzobiorcy i menedżera: przyjęcie pracowników, raporty z pracy pizzerii.
Tablica Restauracji. Wyświetlanie menu na telewizorach w pizzeriach.
Panel Administracyjny. Ustawienia w konkretnej pizzerii: menu, ceny, zarządzanie, kody promocyjne, akcje, banery na stronie itd.
Panel Klienta Pracownika. Harmonogramy pracy pracowników, informacje o pracownikach.
Tablica Motywacji Kuchni. Oddzielny ekran, który wisi w kuchni i wyświetla prędkość pracy pizzaiolo.
Komunikacja. Wysyłanie sms i email.
FileStorage. Własna usługa do przyjmowania i wydawania statycznych plików.

Pierwsze próby rozwiązania problemów pomogły nam, ale były tylko tymczasową ulgą. Nie stały się systemowymi rozwiązaniami, więc stało się jasne, że z bazami trzeba coś zrobić. Na przykład, podzielić ogólną bazę na kilka bardziej wyspecjalizowanych.

Zaczynamy odciążanie monolitu: wydzielenie Auth i Trackera

Główne usługi, które wtedy najbardziej intensywnie zapisywały i odczytywały z bazy:

  1. Auth. Usługa autoryzacji i uwierzytelniania dla zaplecza.
  2. Tracker. Tracker zamówień w kuchni. Usługa oznaczania statusów gotowości podczas przygotowywania zamówienia.

Czym zajmuje się Auth

Auth — to usługa, przez którą użytkownicy logują się do back-office (na stronie klienta jest niezależne logowanie). Odwołują się do niej również w zapytaniach, aby upewnić się, że mają odpowiednie prawa dostępu, i że te prawa nie zmieniły się od ostatniego logowania. Dzięki niej następuje logowanie urządzeń w pizzerii.

Na przykład chcemy otworzyć na telewizorze wiszącym w sali tablicę ze statusami gotowych zamówień. Wtedy otwieramy auth.dodopizza.ru, wybieramy „Logowanie jako urządzenie”, pojawia się kod, który można wprowadzić na specjalnej stronie na komputerze menedżera zmiany, wskazując typ urządzenia. Telewizor sam przejdzie na odpowiedni interfejs swojej pizzerii i zacznie wyświetlać imiona klientów, których zamówienia są gotowe.

Historia architektury Dodo IS: droga back-office’u

Skąd pochodzą obciążenia?

Każdy zalogowany użytkownik back-office dla każdego zapytania odwołuje się do bazy, do tabeli użytkowników, wyciąga stamtąd użytkownika za pomocą zapytania SQL i sprawdza, czy ma potrzebne uprawnienia i dostęp do tej strony.

Każde z urządzeń robi to samo, tylko z tabelą urządzeń, sprawdzając swoją rolę i swoje uprawnienia. Duża liczba zapytań do głównej bazy powoduje jej obciążenie i zużycie zasobów wspólnej bazy na te operacje.

Odciążamy Auth

Auth ma oddzielną domenę, to znaczy, że dane o użytkownikach, logowaniach lub urządzeniach trafiają do usługi (jeszcze przyszłej) i tam pozostają. Jeśli ktoś ich potrzebuje, idzie do tej usługi po dane.

BYŁO. Schemat działania był początkowo taki:

Historia architektury Dodo IS: droga back-office’u

Chciałbym trochę wyjaśnić, jak to działało:

  1. Zapytanie z zewnątrz przychodzi na backend (tam Asp.Net MVC), przynosi ze sobą cookie sesji, które jest używane do uzyskania danych sesyjnych z Redis(1). W niej może być informacja o uprawnieniach i wtedy dostęp do kontrolera jest otwarty (3,4), lub nie.
  2. Jeśli dostępu nie ma, należy przejść przez procedurę autoryzacji. Dla uproszczenia została ona przedstawiona jako część ścieżki w tym samym atrybucie, chociaż to jest przejście na stronę logowania. W pozytywnym scenariuszu uzyskujemy poprawnie wypełnioną sesję i przechodzimy do Kontrolera Backoffice.
  3. Jeśli dane są dostępne, należy je sprawdzić pod kątem aktualności w bazie użytkownika. Czy nie zmieniła się jego rola, czy nadal powinien mieć dostęp do strony. W takim przypadku, po uzyskaniu sesji (1), należy bezpośrednio sprawdzić w bazie dostęp użytkownika za pomocą warstwy logiki uwierzytelniania (2). Następnie przenieść na stronę logowania lub przejść do kontrolera. Taki prosty system, ale nie do końca standardowy.
  4. Jeśli wszystkie procedury są zakończone, przechodzimy dalej w logice w kontrolerach i metodach.

Dane użytkowników są oddzielone od wszystkich innych danych, przechowywane są w osobnej tabeli membership, a funkcje z warstwy logiki AuthService mogą być w pełni metodami API. Granice domeny są dość wyraźnie określone: użytkownicy, ich role, dane o dostępach, przyznawanie i odbieranie dostępów. Wszystko wygląda tak, że można by to wydzielić do osobnej usługi.

STAŁO SIĘ. Tak zrobiliśmy:

Historia architektury Dodo IS: droga back-office’u

Taki sposób ma kilka problemów. Na przykład, wywołanie metody wewnątrz procesu — to nie to samo, co wywołanie zewnętrznej usługi przez http. Opóźnienia, niezawodność, utrzymanie, przejrzystość operacji są zupełnie inne. Więcej o takich problemach opowiadał Andriej Morewski w swoim wystąpieniu „50 odcieni mikrousług”.

Usługa uwierzytelniania i z nią usługa urządzeń są wykorzystywane dla back-office, tj. dla usług i interfejsów stosowanych w produkcji. Uwierzytelnianie dla usług klienckich (takich jak strona internetowa lub aplikacja mobilna) odbywa się oddzielnie bez użycia Auth. Wydzielenie zajęło około roku, a teraz znów zajmujemy się tym tematem, przenosząc system na nowe usługi uwierzytelniania (ze standardowymi protokołami).

Dlaczego wydzielenie trwało tak długo?
Po drodze napotkaliśmy wiele problemów, które spowolniły proces:

  1. Chcieliśmy przenieść dane o użytkownikach, urządzeniach i uwierzytelnieniu z baz w danym kraju do jednej. W tym celu należało przenieść wszystkie tabele i zmienić identyfikator int na globalny identyfikator UUID (niedawno przerabialiśmy ten kod Roman Bukin „Uuid — wielka historia małej struktury” i projekt open-source Primitives). Przechowywanie danych o użytkownikach (jako że są to informacje osobiste) ma swoje ograniczenia i w niektórych krajach należy je przechowywać oddzielnie. Jednak globalny identyfikator użytkownika powinien być.
  2. Wiele tabel w bazie danych zawiera informacje o użytkowniku, który wykonał daną operację. Wymagało to dodatkowego mechanizmu, aby zapewnić spójność.
  3. Po stworzeniu usług API nastąpił długi i stopniowy okres przenoszenia na inny system. Przełączenia musiały odbywać się bezproblemowo dla użytkowników i wymagały pracy ręcznej.

Schemat rejestracji urządzenia w pizzerii:

Historia architektury Dodo IS: droga back-office’u

Ogólna architektura po wydzieleniu usługi Auth i Devices:

Historia architektury Dodo IS: droga back-office’u

Uwaga. Na rok 2020 pracujemy nad nową wersją Auth, która opiera się na standardzie autoryzacji OAuth 2.0. Ten standard jest dość skomplikowany, ale przyda się do opracowania usługi jednolitej autoryzacji. W artykule „Zawiłości autoryzacji: przegląd technologii OAuth 2.0” Aleksiej Czerniajew postarał się przedstawić standard w możliwie najprostszy i najjaśniejszy sposób, abyście zaoszczędzili czas na jego naukę.

Czym zajmuje się Tracker

Teraz o drugim z obciążonych serwisów. Tracker pełni podwójną rolę:

  • Z jednej strony jego zadaniem jest pokazywanie pracownikom w kuchni, które zamówienia są aktualnie w realizacji, jakie produkty należy teraz przygotować.
  • Z drugiej strony — cyfryzować wszystkie procesy w kuchni.

Historia architektury Dodo IS: droga back-office’u

Gdy w zamówieniu pojawia się nowy produkt (na przykład pizza), trafia on na stację trackera „Wałkowanie”. Na tej stacji znajduje się pizzaiolo, który bierze odpowiedni kawałek ciasta i wałkuje go, po czym zaznacza na tablecie trackera, że wykonał swoje zadanie i przekazuje wałkowane ciasto do następnej stacji — „Nadzienie”.

Tam kolejny pizzaiolo nadziewa pizzę, następnie zaznacza na tablecie, że wykonał swoje zadanie i wkłada pizzę do pieca (to również oddzielna stacja, którą należy zaznaczyć na tablecie). Taki system istniał od samego początku w Dodo i od początku istnienia Dodo IS. Pozwala to na pełne śledzenie i cyfryzowanie wszystkich operacji. Ponadto tracker podpowiada, jak przygotowywać dany produkt, prowadzi każdy rodzaj produktu przez jego schematy produkcji, przechowuje optymalny czas przygotowania produktu i śledzi wszystkie operacje związane z produktem.

Historia architektury Dodo IS: droga back-office’uTak wygląda ekran tabletu na stacji trackera „Wałkowanie”

Skąd pochodzą obciążenia?

W każdej pizzerii znajduje się około pięciu tabletów z trackerem. W 2016 roku mieliśmy ponad 100 pizzerii (a teraz ponad 600). Każdy tablet co 10 sekund wysyła zapytanie do backendu i pobiera dane z tabeli zamówień (połączenie z klientem i adresem), składu zamówienia (połączenie z produktem i określenie ilości), tabeli motywacyjnej (w której śledzone jest czas naciśnięcia). Kiedy pizzaiolo naciska na produkt na trackerze, następuje aktualizacja wpisów we wszystkich tych tabelach. Tabela zamówień jest wspólna, do niej jednocześnie trafiają wstawienia przy przyjęciu zamówienia, aktualizacje z innych części systemu oraz liczne odczyty, na przykład na telewizorze, który wisi w pizzerii i pokazuje gotowe zamówienia dla klientów.

W okresie walki z obciążeniami, kiedy wszystko było buforowane i przenoszone na asynchroniczną replikę bazy, te operacje z trackerem nadal trafiały do bazy głównej. Nie powinno być tu żadnych opóźnień, dane muszą być aktualne, a desynchronizacja jest niedopuszczalna.

Brak własnych tabel i indeksów na nich nie pozwalał na pisanie bardziej specyficznych zapytań, dopasowanych do własnych potrzeb. Na przykład, tracker może efektywnie mieć indeks na pizzerię w tabeli zamówień. Zawsze pobieramy z bazy trackera zamówienia według pizzerii. Przy tym przyjęcie zamówienia nie jest tak ważne, do której pizzerii ono trafia, ważniejsze jest, który klient złożył to zamówienie. A to oznacza, że potrzebny jest indeks według klienta. Dodatkowo dla trackera w tabeli zamówień nie jest konieczne przechowywanie ID wydrukowanego paragonu lub powiązanych z zamówieniem promocji. Ta informacja nie interesuje naszego serwisu trackera. W ogólnej monolitycznej bazie tabele mogły być tylko kompromisowym rozwiązaniem pomiędzy wszystkimi użytkownikami. Był to jeden z pierwotnych problemów.

BYŁO. Początkowo architektura była taka:

Historia architektury Dodo IS: droga back-office’u

Nawet po wydzieleniu do oddzielnych procesów, większość bazy kodu pozostała wspólna dla różnych serwisów. Wszystko, co było poniżej kontrolerów, było jednorodne i żyło w jednym repozytorium. Wykorzystywano wspólne metody serwisów, repozytoriów, wspólną bazę, w której znajdowały się wspólne tabele.

Odciążamy Tracker

Głównym problemem z trackerem jest to, że dane muszą synchronizować się między różnymi bazami. To również jest jego główna różnica w porównaniu do podziału usługi Auth, zamówienie i jego status mogą się zmieniać i powinny być wyświetlane w różnych usługach.

Przyjmujemy zamówienie w Kasa Restauracji (to jest usługa), które jest zapisywane w bazie w statusie „Przyjęte”. Następnie musi trafić do trackera, gdzie jeszcze kilka razy zmieni swój status: od „Kuchni” do „Zapakowane”. W tym czasie z zamówieniem mogą występować jakieś zewnętrzne oddziaływania ze strony Kasy lub interfejsu Menedżera zmiany. Poniżej przedstawiam tabelę statusów zamówienia z ich opisem:

Historia architektury Dodo IS: droga back-office’u
Schemat zmiany statusów zamówienia wygląda następująco:

Historia architektury Dodo IS: droga back-office’u

Statusy zmieniają się między różnymi systemami. I tutaj tracker nie jest końcowym systemem, w którym dane są zbierane. Widzieliśmy kilka możliwych podejść do podziału w takim przypadku:

  1. Koncentrujemy wszystkie działania zamówienia w jednej usłudze. W naszym przypadku ta opcja wymagałaby zbyt dużej usługi do zarządzania zamówieniem. Gdybyśmy na niej poprzestali, otrzymalibyśmy drugi monolit. Problemów byśmy nie rozwiązali.
  2. Jeden system wywołuje inny. Druga opcja jest już ciekawsza. Jednak przy niej mogą występować łańcuchy wywołań (awarie kaskadowe), powiązanie komponentów jest większe, a zarządzanie tym bardziej skomplikowane.
  3. Organizujemy zdarzenia, a każda usługa wymienia się z inną poprzez te zdarzenia. Ostatecznie wybrano właśnie trzecią opcję, w której wszystkie usługi zaczynają wymieniać zdarzenia między sobą.

To, że wybraliśmy trzecią opcję, oznaczało, że dla trackera będzie własna baza, a przy każdej zmianie zamówienia będzie wysyłać zdarzenie na ten temat, na które subskrybują się inne usługi, które również trafia do głównej bazy. W tym celu potrzebowaliśmy pewnej usługi, która zapewni dostarczenie wiadomości między usługami.

W tym czasie w naszym stacku już mieliśmy RabbitMQ, stąd ostateczna decyzja o użyciu go jako brokera wiadomości. Na schemacie pokazano przejście zamówienia z Kasy Restauracji przez Tracker, gdzie zmienia swoje statusy oraz wyświetlanie go w interfejsie Zamówienia menedżera. STAŁO SIĘ:

Historia architektury Dodo IS: droga back-office’u

Proces zamówienia krok po kroku
Proces zamówienia zaczyna się w jednej z usług źródłowych zamówienia. Tutaj jest to Kasa Restauracji:

  1. Na Kasse zamówienie jest już całkowicie gotowe i pora je wysłać do tracker'a. Zdarzenie, na które subskrybuje tracker, zostaje uruchomione.
  2. Tracker, przyjmując zamówienie, zapisuje je w swojej własnej bazie, generując przy tym zdarzenie „ZamówieniePrzyjętePrzezTracker'a” i wysyłając je do RMQ.
  3. W szynie zdarzeń na zamówienie już subskrybuje kilka obsługiwaczy. Dla nas ważny jest ten, który synchronizuje z monolityczną bazą.
  4. Obsługiwacz przyjmuje zdarzenie, wybiera z niego istotne dla siebie dane: w naszym przypadku jest to status zamówienia „PrzyjętePrzezTracker'a” i aktualizuje swoją encję zamówienia w głównej bazie.

Jeśli ktoś potrzebuje zamówienia bezpośrednio z monolitycznej tabeli orders, można je pobrać stamtąd. Na przykład, jest to potrzebne interfejsowi Zamówienia w Menedżerze Zmiany:

Historia architektury Dodo IS: droga back-office’u

Wszystkie inne usługi również mogą subskrybować zdarzenia zamówienia z trackera, aby wykorzystywać je dla siebie.

Jeśli po pewnym czasie zamówienie jest brane do realizacji, jego status najpierw zmienia się w swojej bazie (bazie Tracker'a), a następnie natychmiast generowane jest zdarzenie „ZamówienieWPracy”. Ono również trafia do RMQ, skąd synchronizuje się w monolitycznej bazie i jest dostarczane innym usługom. Po drodze mogą wystąpić różne problemy, a więcej na ten temat można zobaczyć w raporcie Żeni Peszkowa o szczegółach realizacji Eventual Consistency w Trackerze.

Finalna architektura po zmianach w Auth i Trackerze

Historia architektury Dodo IS: droga back-office’u

Podsumowując pośrednio: pierwotnie miałem pomysł, aby spakować dziewięcioletnią historię systemu Dodo IS w jeden artykuł. Chciałem szybko i prosto opowiedzieć o etapach ewolucji. Jednak kiedy zasiadłem do materiału, zrozumiałem, że wszystko jest znacznie bardziej skomplikowane i interesujące, niż się wydaje.

Rozmyślając nad użytecznością (lub jej brakiem) takiego materiału, doszedłem do wniosku, że ciągły rozwój jest niemożliwy bez rzetelnych kronik zdarzeń, rozwiniętych retrospektyw i analizy swoich wcześniejszych decyzji.

Mam nadzieję, że była to użyteczna i interesująca lektura o naszej drodze. Teraz stoję przed wyborem, którą część systemu Dodo IS opisać w następnym artykule: piszcie w komentarzach lub głosujcie.

Tylko zarejestrowani użytkownicy mogą brać udział w ankiecie. Zaloguj się, proszę.

Jaką część Dodo IS chcielibyście poznać w następnym artykule?

  • 24,1%Wczesny monolit w Dodo IS (2011-2015)14

  • 24,1%Pierwsze problemy i ich rozwiązania (2015-2016)14

  • 20,7%Droga części klienckiej: fasada nad bazą (2016-2017)12

  • 36,2%Historia prawdziwych mikrousług (2018-2019)21

  • 44,8%Zakończone wycinanie monolitu i stabilizacja architektury26

  • 29,3%O dalszych planach rozwoju systemu17

  • 19,0%Nie chcę nic wiedzieć o Dodo IS11

Zagłosowało 58 użytkowników. Wstrzymało się 6 użytkowników.

Źródło: habr.com

Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS 🔥 Kup solidny hosting stron z ochroną przed DDoS, serwery VPS VDS | ProHoster