Historie architektury Dodo IS: raný monolit

Nebo každá nešťastná firma s monolitem je nešťastná svým způsobem.

Vývoj systému Dodo IS začal okamžitě, stejně jako podnikání Dodo Pizza, v roce 2011. Vycházel z myšlenky úplné a úplné digitalizace podnikových procesů a sám, což už tehdy v roce 2011 vyvolalo spoustu otázek a skepse. Ale už 9 let jdeme touto cestou - vlastním vývojem, který začal monolitem.

Tento článek je „odpovědí“ na otázky „Proč přepisovat architekturu a provádět tak rozsáhlé a dlouhodobé změny?“ zpět k předchozímu článku „Historie architektury Dodo IS: Cesta back Office“. Začnu tím, jak začal vývoj Dodo IS, jak vypadala původní architektura, jak se objevovaly nové moduly a kvůli jakým problémům bylo nutné provést rozsáhlé změny.

Historie architektury Dodo IS: raný monolit

Série článků "Co je Dodo IS?" vypráví o:

  1. Raný monolit v Dodo IS (2011-2015). (jsi tady)

  2. Cesta Back Office: Oddělené základny a autobus.

  3. Cesta na straně klienta: fasáda nad základnou (2016-2017). (Probíhá...)

  4. Historie skutečných mikroslužeb. (2018-2019). (Probíhá...)

  5. Hotové pilování monolitu a stabilizace architektury. (Probíhá...)

Počáteční architektura

V roce 2011 vypadala architektura Dodo IS takto:

Historie architektury Dodo IS: raný monolit

Prvním modulem v architektuře je přijímání objednávek. Obchodní proces byl:

  • klient zavolá do pizzerie;

  • vedoucí zvedne telefon;

  • přijímá objednávku telefonicky;

  • vyplní jej paralelně v rozhraní přijímání objednávky: zohledňuje informace o klientovi, údaje o detailech objednávky, dodací adresu. 

Rozhraní informačního systému vypadalo asi takto...

První verze z října 2011:

Mírné zlepšení v lednu 2012

Dodo Pizza Informační systém Rozvoz Pizza Restaurace

Zdroje na vývoj prvního modulu pro příjem objednávek byly omezené. Museli jsme toho udělat hodně, rychle a s malým týmem. Malý tým tvoří 2 vývojáři, kteří položili základ celému budoucímu systému.

Jejich první rozhodnutí určilo osud technologického zásobníku:

  • Backend na ASP.NET MVC, jazyk C#. Vývojáři byli dotnetchiki, tento stack jim byl známý a příjemný.

  • Frontend na Bootstrap a JQuery: uživatelská rozhraní na vlastních stylech a skriptech. 

  • Databáze MySQL: žádné licenční náklady, snadné použití.

  • Servery na Windows Server, protože .NET pak mohl být pouze pod Windows (nebudeme diskutovat o Mono).

Fyzicky bylo toto vše vyjádřeno v „dedicu u hostitele“. 

Objednat Intake Application Architecture

Pak už všichni mluvili o mikroslužbách a SOA se používala ve velkých projektech 5 let, například WCF bylo vydáno v roce 2006. Pak ale zvolili spolehlivé a osvědčené řešení.

Tady to je.

Historie architektury Dodo IS: raný monolit

Asp.Net MVC je Razor, který na žádost z formuláře nebo od klienta vykreslí HTML stránku se serverovým vykreslováním. Na klientovi již skripty CSS a JS zobrazují informace a v případě potřeby provádějí požadavky AJAX prostřednictvím JQuery.

Požadavky na serveru končí ve třídách *Controller, kde v metodě probíhá zpracování a generování finální HTML stránky. Řadiče zadávají požadavky na vrstvu logiky nazvanou *Služby. Každá ze služeb odpovídala nějakému aspektu podnikání:

  • Například DepartmentStructureService rozdával informace o pizzeriích, o odděleních. Oddělení je skupina pizzerií ​​provozovaných jedním franšízantem.

  • ReceivingOrdersService přijal a vypočítal složení objednávky.

  • A SmsService odeslal SMS voláním služeb API k odeslání SMS.

Služby zpracovávají data z databáze, ukládají obchodní logiku. Každá služba měla jedno nebo více *úložišť s příslušným názvem. Obsahovaly již dotazy na uložené procedury v databázi a vrstvu mapovačů. V úložištích byla obchodní logika, zvláště hodně v těch, která vydávala hlášení. ORM se nepoužívalo, všichni spoléhali na ručně psané sql. 

Byla zde také vrstva doménového modelu a běžné pomocné třídy, například třída Order, která ukládala objednávku. Na stejném místě se ve vrstvě nacházel pomocník pro převod zobrazovaného textu podle zvolené měny.

To vše může reprezentovat takový model:

Historie architektury Dodo IS: raný monolit

Způsob objednávky

Zvažte zjednodušený počáteční způsob vytvoření takové objednávky.

Historie architektury Dodo IS: raný monolit

Zpočátku byl web statický. Byly na něm ceny a nahoře - telefonní číslo a nápis "Pokud chcete pizzu - zavolejte na číslo a objednejte." K objednávce potřebujeme implementovat jednoduchý postup: 

  • Klient navštíví statickou stránku s cenami, vybere si produkty a zavolá na číslo uvedené na stránce.

  • Zákazník pojmenuje produkty, které chce přidat do objednávky.

  • Uvádí svou adresu a jméno.

  • Provozovatel objednávku akceptuje.

  • Objednávka se zobrazí v rozhraní přijatých objednávek.

Vše začíná zobrazením menu. Přihlášený uživatel-operátor přijímá vždy pouze jednu objednávku. Proto může být koncept košíku uložen v jeho relaci (relace uživatele je uložena v paměti). Je zde objekt košíku obsahující produkty a informace o zákaznících.

Zákazník pojmenuje produkt, obsluha klikne + vedle produktu a na server je odeslán požadavek. Informace o produktu se vytáhnou z databáze a informace o produktu se vloží do košíku.

Historie architektury Dodo IS: raný monolit

Poznámka. Ano, zde nemůžete vytáhnout produkt z databáze, ale přenést jej z frontendu. Ale pro názornost jsem přesně ukázal cestu z databáze. 

Dále zadejte adresu a jméno klienta. 

Historie architektury Dodo IS: raný monolit

Když kliknete na "Vytvořit objednávku":

  • Požadavek je odeslán do OrderController.SaveOrder().

  • Dostáváme košík z relace, jsou zde produkty v množství, které potřebujeme.

  • Do košíku doplníme informace o klientovi a předáme jej metodě AddOrder třídy ReceivingOrderService, kde se uloží do databáze. 

  • Databáze má tabulky s objednávkou, složením objednávky, klientem a všechny jsou propojené.

  • Rozhraní zobrazení objednávek přejde a vytáhne nejnovější objednávky a zobrazí je.

Nové moduly

Přijetí objednávky bylo důležité a nutné. Nemůžete podnikat s pizzou, pokud nemáte objednávku na prodej. Systém proto začal získávat funkčnost - přibližně od roku 2012 do roku 2015. Během této doby se objevilo mnoho různých bloků systému, které budu nazývat moduly, na rozdíl od konceptu služby nebo produktu. 

Modul je soubor funkcí, které spojuje nějaký společný obchodní cíl. Přitom jsou fyzicky ve stejné aplikaci.

Moduly lze nazvat systémové bloky. Jedná se například o reportovací modul, administrátorská rozhraní, food tracker v kuchyni, oprávnění. To vše jsou různá uživatelská rozhraní, některá mají dokonce různé vizuální styly. Vše je přitom v rámci jedné aplikace, jednoho běžícího procesu. 

Technicky byly moduly navrženy jako Area (taková myšlenka dokonce zůstala v jádro asp.net). Existovaly samostatné soubory pro frontend, modely a také jejich vlastní třídy řadičů. V důsledku toho byl systém transformován z tohoto ...

Historie architektury Dodo IS: raný monolit

...do tohoto:

Historie architektury Dodo IS: raný monolit

Některé moduly jsou implementovány samostatnými weby (spustitelným projektem), kvůli zcela samostatné funkcionalitě a částečně kvůli mírně oddělenému, více zaměřenému vývoji. Tento:

  • Site - první verze stránky dodopizza.ru.

  • Vývoz: nahrávání reportů z Dodo IS pro 1C. 

  • Osobní - osobní účet zaměstnance. Byl vyvinut samostatně a má svůj vlastní vstupní bod a samostatný design.

  • fs — projekt hostingu statiky. Později jsme se od něj odstěhovali a veškerou statiku jsme přesunuli do Akamai CDN. 

Zbytek bloků byl v aplikaci BackOffice. 

Historie architektury Dodo IS: raný monolit

Vysvětlení názvu:

  • Pokladník - Pokladní restaurace.

  • ShiftManager - rozhraní pro roli "Manager směny": provozní statistiky prodeje pizzerie, možnost zařadit produkty na stoplist, změnit objednávku.

  • OfficeManager – rozhraní pro role „Pizzeria Manager“ a „Franchisee“. Zde jsou shromážděny funkce pro zřízení pizzerie, její bonusové akce, příjem a práci se zaměstnanci, reporty.

  • PublicScreens - rozhraní pro televizory a tablety zavěšené v pizzeriích. Televizory při dodání zobrazují menu, reklamní informace, stav objednávky. 

Používali společnou vrstvu služeb, společný blok doménové třídy Dodo.Core a společnou základnu. Někdy ještě mohly vést po přechodech k sobě. Včetně jednotlivých webů, jako je dodopizza.ru nebo personal.dodopizza.ru, šlo do obecných služeb.

Když se objevily nové moduly, snažili jsme se maximálně využít již vytvořený kód služeb, uložené procedury a tabulky v databázi. 

Pro lepší pochopení rozsahu modulů vytvořených v systému je zde schéma z roku 2012 s plány rozvoje:

Historie architektury Dodo IS: raný monolit

V roce 2015 bylo vše na mapě a ještě více bylo ve výrobě.

  • Příjem objednávek se rozrostl do samostatného bloku Kontaktního centra, kde objednávku přijímá operátor.

  • V pizzeriích visely veřejné obrazovky s jídelním lístkem a informacemi.

  • V kuchyni je modul, který automaticky přehraje hlasovou zprávu „Nová pizza“ při příchodu nové objednávky a také vytiskne fakturu pro kurýra. To výrazně zjednodušuje procesy v kuchyni, umožňuje zaměstnancům, aby nebyli rozptylováni velkým množstvím jednoduchých operací.

  • Z doručovací jednotky se stala samostatná Doručovací pokladna, kde byla objednávka vystavena kurýrovi, který předtím směnu převzal. Jeho pracovní doba byla zohledněna při výpočtu mezd. 

Paralelně se od roku 2012 do roku 2015 objevilo více než 10 vývojářů, otevřelo se 35 pizzerií, nasadili systém do Rumunska a připravovali se na otevření prodejen ve Spojených státech. Vývojáři se již nezabývali všemi úkoly, ale byli rozděleni do týmů. každý se specializuje na svou vlastní část systému. 

Problémy

Včetně kvůli architektuře (ale nejen).

Chaos v základně

Jedna základna je pohodlná. Lze v něm dosáhnout konzistence, a to na úkor nástrojů zabudovaných do relačních databází. Práce s ním je známá a pohodlná, zvláště pokud je málo tabulek a málo dat.

Ale během 4 let vývoje se ukázalo, že databáze má asi 600 tabulek, 1500 uložených procedur, z nichž mnohé měly také logiku. Bohužel, uložené procedury nepřinášejí mnoho výhod při práci s MySQL. Nejsou ukládány do mezipaměti základny a ukládání logiky v nich komplikuje vývoj a ladění. Opětovné použití kódu je také obtížné.

Mnoho tabulek nemělo vhodné indexy, někde bylo naopak hodně rejstříků, což znesnadňovalo vkládání. Bylo potřeba upravit cca 20 tabulek - transakce k vytvoření objednávky mohla trvat cca 3-5 sekund. 

Údaje v tabulkách nebyly vždy v nejvhodnější formě. Někde bylo nutné provést denormalizaci. Část pravidelně přijímaných dat byla ve sloupci ve formě XML struktury, což prodloužilo dobu provádění, prodloužilo dotazy a zkomplikovalo vývoj.

Ke stejným stolům byly vyrobeny velmi heterogenní požadavky. Obzvláště utrpěly oblíbené stoly, stejně jako výše zmíněná tabulka. objednávky nebo tabulky pizzerie. Byly použity pro zobrazení provozních rozhraní v kuchyni, analytiky. Jiný web je kontaktoval (dodopizza.ru), kde v danou chvíli mohlo najednou přijít mnoho požadavků. 

Údaje nebyly agregovány a mnoho výpočtů probíhalo za chodu pomocí základny. Vznikly tak zbytečné výpočty a dodatečné zatížení. 

Kód často šel do databáze, když to nemohl udělat. Někde bylo málo hromadných operací, někde by bylo nutné pro zrychlení a zvýšení spolehlivosti rozložit jeden požadavek do více kódem. 

Soudržnost a mlžení v kódu

Moduly, které měly být zodpovědné za svou část podnikání, to nedělaly poctivě. Některé z nich měly duplicitní funkce pro role. Například místní obchodník, který je zodpovědný za marketingovou aktivitu sítě ve svém městě, musel používat jak rozhraní „Admin“ (k vytváření promo akcí), tak rozhraní „Office Manager“ (k zobrazení dopadu promo akcí na podnikání). Samozřejmě uvnitř obou modulů byla použita stejná služba, která fungovala s bonusovými akcemi.

Služby (třídy v rámci jednoho monolitického velkého projektu) si mohly navzájem volat, aby obohatily svá data.

Se samotnými modelovými třídami, které ukládají data, práce v kódu byla prováděna jinak. Někde byly konstruktory, přes které bylo možné specifikovat požadovaná pole. Někde to bylo provedeno prostřednictvím veřejných nemovitostí. Získávání a transformace dat z databáze byla samozřejmě různorodá. 

Logika byla buď v ovladačích nebo ve třídách služeb. 

Zdá se, že jde o drobné problémy, ale značně zpomalily vývoj a snížily kvalitu, což vedlo k nestabilitě a chybám. 

Složitost velkého vývoje

Potíže nastaly při samotném vývoji. Bylo nutné vytvořit různé bloky systému a paralelně. Zařadit potřeby každé komponenty do jediného kódu bylo stále obtížnější. Nebylo jednoduché se dohodnout a potěšit všechny složky zároveň. K tomu se přidala omezení v technologii, zejména s ohledem na základnu a frontend. Bylo nutné opustit jQuery směrem k high-level frameworkům, zejména co se týče klientských služeb (web).

V některých částech systému by mohly být použity databáze, které jsou k tomu vhodnější.. Například později jsme měli případ použití přechodu z Redis na CosmosDB k uložení košíku objednávek. 

Týmy a vývojáři zapojení do svého oboru zjevně chtěli více autonomie pro své služby, a to jak z hlediska vývoje, tak zavádění. Konflikty sloučení, problémy s uvolněním. Pokud je tento problém pro 5 vývojářů bezvýznamný, pak s 10 a ještě více s plánovaným růstem by se vše stalo vážnější. A před námi měl být vývoj mobilní aplikace (začal v roce 2017 a v roce 2018 to bylo velký pád). 

Různé části systému vyžadovaly různé úrovně stability, ale kvůli silné konektivitě systému jsme to nemohli zajistit. Chyba při vývoji nové funkce v admin panelu se klidně mohla stát při přijetí objednávky na webu, protože kód je společný a opakovaně použitelný, databáze a data jsou také stejná.

Těmto chybám a problémům by se v rámci takové monoliticko-modulární architektury asi dalo vyhnout: udělat rozdělení odpovědnosti, refaktorovat kód i databázi, jasně oddělit vrstvy od sebe, každý den sledovat kvalitu. Ale zvolená architektonická řešení a zaměření na rychlé rozšiřování funkčnosti systému vedly k problémům se stabilitou.

Jak blog Power of the Mind umístil pokladny do restaurací

Pokud by růst sítě pizzerií ​​(a zatížení) pokračoval stejným tempem, tak by po nějaké době byly propady takové, že by systém nestoupal. Dobře ilustruje problémy, kterým jsme začali čelit v roce 2015, zde je takový příběh. 

Na blogu"Síla mysli“ byl widget, který ukazoval údaje o tržbách za rok celé sítě. Widget přistoupil k veřejnému rozhraní API Dodo, které poskytuje tato data. Tato statistika je aktuálně dostupná na http://dodopizzastory.com/. Widget se zobrazoval na každé stránce a každých 20 sekund zadával požadavky na časovač. Požadavek šel na api.dodopizza.ru a požadoval:

  • počet pizzerií ​​v síti;

  • celkové síťové výnosy od začátku roku;

  • příjem za dnešek.

Požadavek na statistiku tržeb šel přímo do databáze a začal vyžadovat data o objednávkách, shromažďovat data za chodu a rozdávat částku. 

Pokladny v restauracích šly ke stejnému stolu objednávek, vyložily seznam přijatých objednávek pro dnešek a do něj byly přidány nové objednávky. Pokladny prováděly své požadavky každých 5 sekund nebo při obnovení stránky.

Diagram vypadal takto:

Historie architektury Dodo IS: raný monolit

Jednou na podzim napsal Fjodor Ovčinnikov na svůj blog dlouhý a oblíbený článek. Na blog přišlo hodně lidí a začali vše pozorně číst. Zatímco každý z lidí, kteří přišli, četl článek, widget příjmů fungoval správně a každých 20 sekund požadoval API.

API volalo uloženou proceduru pro výpočet součtu všech objednávek od začátku roku pro všechny pizzerie v síti. Agregace byla založena na tabulce objednávek, která je velmi oblíbená. Chodí do ní všechny pokladny všech v té době otevřených restaurací. Pokladny přestaly odpovídat, objednávky nebyly přijímány. Také nebyly přijaty z webu, neobjevily se na trackeru, vedoucí směny je neviděl ve svém rozhraní. 

Toto není jediný příběh. Na podzim roku 2015 bylo zatížení systému každý pátek kritické. Několikrát jsme vypnuli veřejné API a jednou jsme dokonce museli vypnout web, protože nic nepomohlo. Byl tam dokonce seznam služeb s příkazem k odstavení při velkém zatížení.

Od této chvíle začíná náš boj se zátěží a o stabilizaci systému (od podzimu 2015 do podzimu 2018). Tehdy se to stalo"skvělý podzim". Dále se občas vyskytly poruchy, některé byly velmi citlivé, ale obecné období nestability lze nyní považovat za prošlé.

Rychlý obchodní růst

Proč to nešlo udělat hned? Stačí se podívat na následující grafy.

Historie architektury Dodo IS: raný monolit

Také v letech 2014-2015 proběhlo otevření v Rumunsku a připravovalo se otevření v USA.

Síť se velmi rychle rozrůstala, otevíraly se nové země, objevovaly se nové formáty pizzerií, například byla otevřena pizzerie u food courtu. To vše vyžadovalo značnou pozornost konkrétně rozšíření funkcí Dodo IS. Bez všech těchto funkcí, bez sledování v kuchyni, účtování produktů a ztrát v systému, zobrazování vystavení objednávky v hale food courtu bychom stěží mluvili o „správné“ architektuře a „správném“ přístupu k vývoj nyní.

Další překážkou včasné revize architektury a obecně pozornosti k technickým problémům byla krize v roce 2014. Věci, jako je tato, tvrdě zasáhly příležitosti pro týmy k růstu, zejména pro mladý podnik, jako je Dodo Pizza.

Rychlá řešení, která pomohla

Problémy potřebovaly řešení. Obvykle lze řešení rozdělit do 2 skupin:

  • Rychlé, které uhasí oheň a poskytnou malou rezervu bezpečí a poskytnou nám čas na změnu.

  • Systémové a tedy dlouhé. Reengineering řady modulů, rozdělení monolitické architektury na samostatné služby (většina z nich vůbec nejsou mikro, ale spíše makro služby a něco na tom je Zpráva Andreje Morevského). 

Suchý seznam rychlých změn je následující:

Zvětšit základní předlohu

Samozřejmě, že první věcí, která se dělá pro řešení zátěže, je zvýšení kapacity serveru. To bylo provedeno pro hlavní databázi a pro webové servery. To je bohužel možné jen do určitého limitu, pak je to příliš drahé.

Od roku 2014 jsme přešli do Azure, o tomto tématu jsme tehdy také psali v článku “Jak Dodo Pizza doručuje pizzu pomocí cloudu Microsoft Azure". Ale po sérii navýšení serveru pro základnu narazili na náklady. 

Základní repliky pro čtení

Pro základnu byly vyrobeny dvě repliky:

ReadReplica pro referenční žádosti. Používá se ke čtení adresářů, typu, města, ulice, pizzerie, produktů (pomalu změněná doména) a v těch rozhraních, kde je přijatelné malé zpoždění. Tyto repliky byly 2, jejich dostupnost jsme zajišťovali stejně jako předlohy.

ReadReplica pro požadavky na sestavy. Tato databáze měla nižší dostupnost, ale všechny zprávy do ní chodily. Nechte je mít těžké požadavky na obrovské přepočty dat, ale neovlivňují hlavní databázi a provozní rozhraní. 

Mezipaměti v kódu

Nikde v kódu nebyly žádné keše (vůbec). To vedlo k dalším, ne vždy nutným, požadavkům na načtenou databázi. Mezipaměti byly nejprve jak v paměti, tak na externí službě mezipaměti, to byl Redis. Vše bylo zneplatněno časem, nastavení bylo uvedeno v kódu.

Více backendových serverů

Backend aplikace bylo také potřeba škálovat, aby zvládl zvýšené pracovní zatížení. Z jednoho iis-serveru bylo nutné vytvořit cluster. Přeložili jsme termín relace aplikace z paměti do RedisCache, což umožnilo vytvořit několik serverů za jednoduchým nástrojem pro vyrovnávání zatížení s kruhovým provozem. Nejprve se používal stejný Redis jako u keší, pak se rozdělil na několik. 

V důsledku toho se architektura stala složitější ...

Historie architektury Dodo IS: raný monolit

… ale část napětí byla odstraněna.

A pak bylo potřeba předělat načtené komponenty, čehož jsme se ujali. O tom si povíme v příštím díle.

Zdroj: www.habr.com

Přidat komentář