Istoria arhitecturii Dodo IS: calea back office

Habr schimbă lumea. Facem blog de peste un an acum. În urmă cu aproximativ șase luni, am primit un feedback complet logic de la Khabroviți: „Dodo, spui peste tot că ai propriul tău sistem. Si ce este acest sistem? Și de ce are nevoie un lanț de pizza?

Ne-am așezat, ne-am gândit și am realizat că ai dreptate. Încercăm să explicăm totul pe degete, dar iese în bucăți rupte și nicăieri nu există o descriere completă a sistemului. Astfel a început o lungă călătorie de colectare de informații, căutare de autori și scrierea unei serii de articole despre Dodo IS. Să mergem!

Mulțumiri: Vă mulțumim pentru că ne-ați împărtășit feedbackul. Mulțumită lui, am descris în sfârșit sistemul, am compilat un radar tehnic și vom lansa în curând o descriere amplă a proceselor noastre. Fără tine, am fi stat acolo încă 5 ani.

Istoria arhitecturii Dodo IS: calea back office

Seria de articole „Ce este Dodo IS?” spune despre:

  1. Monolit timpuriu în Dodo IS (2011-2015). (În curs...)
  2. Calea back office: baze separate și autobuz. (Eşti aici)
  3. Calea laterală client: fațadă peste bază (2016-2017). (În curs...)
  4. Istoria adevăratelor microservicii. (2018-2019). (În curs...)
  5. Terminat tăierea monolitului și stabilizarea arhitecturii. (În curs...)

Dacă sunteți interesat să aflați altceva - scrieți în comentarii.

Opinie despre descrierea cronologică de la autor
Țin regulat o întâlnire pentru noii angajați pe tema „Arhitectura sistemului”. Îl numim „Introducere în arhitectura Dodo IS” și face parte din procesul de integrare pentru noii dezvoltatori. Povestind într-o formă sau alta despre arhitectura noastră, despre trăsăturile ei, am născut o anumită abordare istorică a descrierii.

În mod tradițional, privim sistemul ca pe un set de componente (tehnice sau de nivel superior), module de afaceri care interacționează între ele pentru a atinge un anumit scop. Și dacă o astfel de vedere este justificată pentru proiectare, atunci nu este tocmai potrivită pentru descriere și înțelegere. Există mai multe motive aici:

  • Realitatea este diferită de ceea ce este pe hârtie. Nu totul merge așa cum a fost planificat. Și ne interesează cum a ieșit și cum funcționează de fapt.
  • Prezentarea consecventă a informațiilor. De fapt, poți merge cronologic de la început la starea actuală.
  • De la simplu la complex. Nu universal, dar în cazul nostru este. Arhitectura a trecut de la abordări mai simple la abordări mai complexe. Adesea, prin complicații, au fost rezolvate problemele de viteză și stabilitate de implementare, precum și zeci de alte proprietăți din lista cerințelor nefuncționale (aici bine spus despre contrastarea complexității cu alte cerințe).

În 2011, arhitectura Dodo IS arăta astfel:

Istoria arhitecturii Dodo IS: calea back office

Până în 2020, a devenit puțin mai complicat și a devenit astfel:

Istoria arhitecturii Dodo IS: calea back office

Cum a avut loc această evoluție? De ce sunt necesare diferite părți ale sistemului? Ce decizii arhitecturale au fost luate și de ce? Să aflăm în această serie de articole.

Primele probleme ale anului 2016: de ce ar trebui serviciile să părăsească monolitul

Primele articole din ciclu vor fi despre serviciile care s-au separat primele de monolit. Pentru a vă pune în context, vă spun ce probleme am avut în sistem până la începutul lui 2016, că a trebuit să ne ocupăm de separarea serviciilor.

O singură bază de date MySql, în care toate aplicațiile care existau la acel moment în Dodo IS și-au scris înregistrările. Consecințele au fost:

  • Sarcină mare (cu 85% din solicitări au fost luate în considerare pentru citire).
  • Baza a crescut. Din această cauză, costul și suportul său au devenit o problemă.
  • Un singur punct de eșec. Dacă o aplicație care scrie în baza de date a început brusc să o facă mai activ, atunci alte aplicații au simțit-o de la sine.
  • Ineficiență în stocare și interogări. Adesea, datele au fost stocate într-o structură care era convenabilă pentru unele scenarii, dar nu era potrivită pentru altele. Indexurile accelerează unele operațiuni, dar pot încetini altele.
  • Unele dintre probleme au fost înlăturate prin cache-urile făcute în grabă și replicile de citire la baze (acesta va fi un articol separat), dar le-au permis doar să câștige timp și nu au rezolvat în mod fundamental problema.

Problema a fost prezența monolitului în sine. Consecințele au fost:

  • Lansări unice și rare.
  • Dificultate în dezvoltarea comună a unui număr mare de oameni.
  • Incapacitatea de a introduce noi tehnologii, noi cadre și biblioteci.

Problemele cu baza și monolitul au fost descrise de multe ori, de exemplu, în contextul prăbușirilor de la începutul anului 2018 (Fii ca Munch, sau câteva cuvinte despre datoria tehnică, Ziua în care Dodo IS sa oprit. Script asincron и Povestea păsării Dodo din familia Phoenix. Marea cădere a lui Dodo IS), așa că nu mă voi opri prea mult. Permiteți-mi să spun doar că am vrut să oferim mai multă flexibilitate în dezvoltarea serviciilor. În primul rând, aceasta i-a vizat pe cei care au fost cel mai încărcat și cel mai root din întregul sistem - Auth și Tracker.

Calea Back Office: baze și autobuz separate

Navigare în capitole

  1. Schema monolit 2016
  2. Începeți să descărcați Monolith: Separare Auth și Tracker
  3. Ce face Auth?
  4. De unde sunt încărcăturile?
  5. Se descarcă Auth
  6. Ce face Tracker?
  7. De unde sunt încărcăturile?
  8. Se descarcă Tracker

Schema monolit 2016

Iată principalele blocuri ale monolitului Dodo IS 2016, iar chiar mai jos este o transcriere a sarcinilor lor principale.
Istoria arhitecturii Dodo IS: calea back office
Livrare Casiera. Contabilitate pentru curieri, emitere comenzi catre curieri.
Centru de contact. Acceptarea comenzilor prin operator.
teren. Site-urile noastre web (dodopizza.ru, dodopizza.co.uk, dodopizza.by etc.).
AUTH. Serviciu de autorizare și autentificare pentru back office.
urmăritor. Tracker de comenzi în bucătărie. Serviciu de marcare a stărilor de pregătire la pregătirea unei comenzi.
Casa de marcat a Restaurantului. Preluarea comenzilor într-un restaurant, interfețe de casierie.
Export. Încărcarea rapoartelor în 1C pentru contabilitate.
Notificări și facturi. Comenzi vocale în bucătărie (de exemplu, „A sosit pizza nouă”) + tipărirea facturii pentru curieri.
Manager de ture. Interfețe pentru munca șefului de tură: listă de comenzi, grafice de performanță, transferul angajaților în tură.
Manager de birou. Interfețe pentru munca francizatului și a managerului: primirea angajaților, rapoarte despre activitatea pizzeriei.
Tabloul de bord restaurant. Afișarea meniului pe televizoarele din pizzerii.
admin. Setări într-o anumită pizzerie: meniu, prețuri, contabilitate, coduri promoționale, promoții, bannere de pe site etc.
Contul personal al angajatului. Programele de lucru ale angajaților, informații despre angajați.
Placă de motivare pentru bucătărie. Un ecran separat care atârnă în bucătărie și afișează viteza mașinilor de pizza.
Comunicare. Trimiterea de sms și e-mail.
Stocare fisiere. Serviciu propriu pentru primirea și emiterea fișierelor statice.

Primele încercări de a rezolva problemele ne-au ajutat, dar au fost doar un răgaz temporar. Nu au devenit soluții de sistem, așa că era clar că trebuia făcut ceva cu bazele. De exemplu, pentru a împărți baza de date generală în câteva altele mai specializate.

Începeți să descărcați Monolith: Separare Auth și Tracker

Principalele servicii care apoi au înregistrat și citit din baza de date mai mult decât altele:

  1. Auth. Serviciu de autorizare și autentificare pentru back office.
  2. Tracker. Tracker de comenzi în bucătărie. Serviciu de marcare a stărilor de pregătire la pregătirea unei comenzi.

Ce face Auth?

Auth este un serviciu prin care utilizatorii se conectează la back office (există o intrare independentă separată pe partea clientului). De asemenea, se solicită în cerere să se asigure că drepturile de acces necesare sunt prezente și că aceste drepturi nu s-au schimbat de la ultima conectare. Prin el, aparatele intră în pizzerie.

De exemplu, vrem să deschidem un afișaj cu stările comenzilor finalizate pe televizorul agățat în hol. Apoi deschidem auth.dodopizza.ru, selectăm „Login as a device”, apare un cod care poate fi introdus într-o pagină specială de pe computerul managerului de tură, indicând tipul de dispozitiv (dispozitiv). Televizorul însuși va trece la interfața dorită a pizzeriei sale și va începe să afișeze numele clienților ale căror comenzi sunt gata acolo.

Istoria arhitecturii Dodo IS: calea back office

De unde sunt încărcăturile?

Fiecare utilizator autentificat al back office-ului merge la baza de date, la tabelul de utilizatori pentru fiecare solicitare, scoate utilizatorul printr-o interogare sql si verifica daca are accesul si drepturile necesare la aceasta pagina.

Fiecare dintre dispozitive face la fel doar cu tabelul de dispozitive, verificându-i rolul și accesul. Un număr mare de solicitări către baza de date master duce la încărcarea acesteia și la risipa de resurse a bazei de date comune pentru aceste operațiuni.

Se descarcă Auth

Auth are un domeniu izolat, adică datele despre utilizatori, autentificări sau dispozitive intră (deocamdată) în serviciu și rămân acolo. Dacă cineva are nevoie de ele, atunci va merge la acest serviciu pentru date.

A FOST. Schema inițială de lucru a fost următoarea:

Istoria arhitecturii Dodo IS: calea back office

Aș dori să explic puțin cum a funcționat:

  1. O solicitare din exterior vine la backend (există Asp.Net MVC), aduce cu ea un cookie de sesiune, care este folosit pentru a obține date de sesiune de la Redis(1). Fie conține informații despre accesări, iar apoi accesul la controler este deschis (3,4) sau nu.
  2. Dacă nu există acces, trebuie să parcurgeți procedura de autorizare. Aici, pentru simplitate, este afișat ca parte a căii în același atribut, deși este o tranziție către pagina de autentificare. În cazul unui scenariu pozitiv, vom obține o sesiune finalizată corect și vom merge la Controllerul Backoffice.
  3. Dacă există date, atunci trebuie să le verificați pentru relevanță în baza de date a utilizatorilor. S-a schimbat rolul lui, nu ar trebui să i se permită acum pe pagină? În acest caz, după primirea sesiunii (1), trebuie să mergeți direct la baza de date și să verificați accesul utilizatorului folosind stratul logic de autentificare (2). Apoi, fie la pagina de conectare, fie accesați controlerul. Un sistem atât de simplu, dar nu chiar standard.
  4. Dacă toate procedurile sunt trecute, atunci sărim mai departe în logica în controlere și metode.

Datele utilizatorului sunt separate de toate celelalte date, sunt stocate într-un tabel separat de membri, funcțiile din stratul logic AuthService pot deveni metode API. Granițele domeniului sunt definite destul de clar: utilizatori, rolurile acestora, datele de acces, acordarea și revocarea accesului. Totul arată astfel încât să poată fi scos într-un serviciu separat.

DEVENI. Așa că au făcut:

Istoria arhitecturii Dodo IS: calea back office

Această abordare are o serie de probleme. De exemplu, apelarea unei metode în interiorul unui proces nu este același lucru cu apelarea unui serviciu extern prin http. Latența, fiabilitatea, mentenabilitatea, transparența operațiunii sunt complet diferite. Andrey Morevskiy a vorbit mai detaliat despre astfel de probleme în raportul său. „50 de nuanțe de microservicii”.

Serviciul de autentificare și, odată cu acesta, serviciul de dispozitiv sunt folosite pentru back office, adică pentru serviciile și interfețele utilizate în producție. Autentificarea pentru serviciile client (cum ar fi un site web sau o aplicație mobilă) are loc separat, fără a utiliza Auth. Separarea a durat aproximativ un an, iar acum ne ocupăm din nou de acest subiect, transferând sistemul către noi servicii de autentificare (cu protocoale standard).

De ce a durat atât de mult despărțirea?
Au fost multe probleme pe parcurs care ne-au încetinit:

  1. Am vrut să mutăm datele despre utilizatori, dispozitive și autentificare din bazele de date specifice țării într-una singură. Pentru a face acest lucru, a trebuit să traducem toate tabelele și utilizarea de la identificatorul int la identificatorul global UUId (reproiectat recent acest cod Roman Bukin "Uuid - o poveste mare a unei structuri mici" și proiect open source Primitive). Stocarea datelor utilizatorului (deoarece sunt informații personale) are limitările sale și pentru unele țări este necesar să le stocați separat. Dar id-ul global al utilizatorului trebuie să fie.
  2. Multe tabele din baza de date au informații de audit despre utilizatorul care a efectuat operația. Acest lucru a necesitat un mecanism suplimentar de consecvență.
  3. După crearea serviciilor api, a existat o perioadă lungă și graduală de tranziție la un alt sistem. Comutarea trebuia să fie fără întreruperi pentru utilizatori și necesita lucru manual.

Schema de înregistrare a dispozitivului într-o pizzerie:

Istoria arhitecturii Dodo IS: calea back office

Arhitectură generală după extragerea serviciului Auth and Devices:

Istoria arhitecturii Dodo IS: calea back office

Nota. Pentru 2020, lucrăm la o nouă versiune de Auth, care se bazează pe standardul de autorizare OAuth 2.0. Acest standard este destul de complex, dar este util pentru dezvoltarea unui serviciu de autentificare pass-through. In articol "Subtilitățile autorizației: o prezentare generală a tehnologiei OAuth 2.0» Noi, Alexey Chernyaev, am încercat să spunem despre standard cât mai simplu și clar posibil, astfel încât să economisiți timp în studierea lui.

Ce face Tracker?

Acum despre al doilea dintre serviciile încărcate. Trackerul îndeplinește un dublu rol:

  • Pe de o parte, sarcina sa este de a arăta angajaților din bucătărie ce comenzi sunt în lucru în prezent, ce produse trebuie gătite acum.
  • Pe de altă parte, să digitalizeze toate procesele din bucătărie.

Istoria arhitecturii Dodo IS: calea back office

Când un produs nou apare într-o comandă (de exemplu, pizza), acesta merge la stația de urmărire Rolling out. La această stație, există un pizzar care ia o chiflă de dimensiunea necesară și o întinde, după care notează pe tableta de urmărire că și-a îndeplinit sarcina și transferă baza de aluat rulat la următoarea stație - „Inițiere” .

Acolo, următorul pizzar umple pizza, apoi notează pe tabletă că și-a îndeplinit sarcina și pune pizza în cuptor (aceasta este și o stație separată care trebuie notă pe tabletă). Un astfel de sistem a fost încă de la început în Dodo și chiar de la începutul existenței lui Dodo IS. Vă permite să urmăriți și să digitalizați complet toate tranzacțiile. În plus, tracker-ul sugerează cum să gătești un anumit produs, ghidează fiecare tip de produs în funcție de schemele sale de fabricație, stochează timpul optim de gătire pentru produs și urmărește toate operațiunile pe produs.

Istoria arhitecturii Dodo IS: calea back officeAșa arată ecranul tabletei la stația tracker-ului „Raskatka”

De unde sunt încărcăturile?

Fiecare dintre pizzerii are aproximativ cinci tablete cu un tracker. În 2016, aveam peste 100 de pizzerii (și acum peste 600). Fiecare tabletă face o solicitare către backend o dată la 10 secunde și răzuiește date din tabelul de comenzi (conexiunea cu clientul și adresa), compoziția comenzii (conexiunea cu produsul și indicarea cantității), tabelul contabil de motivare (la timpul de apăsare este urmărit în el). Când un producător de pizza face clic pe un produs de pe tracker, intrările din toate aceste tabele sunt actualizate. Tabelul de comenzi este general, conține și inserții la acceptarea unei comenzi, actualizări din alte părți ale sistemului și numeroase citiri, de exemplu, pe un televizor care este agățat într-o pizzerie și arată comenzile finalizate clienților.

În perioada de luptă cu încărcăturile, când totul și totul a fost stocat în cache și transferat în replica asincronă a bazei, aceste operațiuni cu trackerul au continuat să meargă la baza principală. Nu ar trebui să existe niciun decalaj, datele ar trebui să fie actualizate, desincronizarea este inacceptabilă.

De asemenea, lipsa unor tabele și indici proprii asupra acestora nu a permis scrierea unor interogări mai specifice, adaptate utilizării lor. De exemplu, ar putea fi eficient pentru un tracker să aibă un index pentru o pizzerie pe o masă de comandă. Întotdeauna eliminăm comenzile de pizzerie din baza de date de urmărire. Totodată, pentru primirea unei comenzi, nu este atât de important în ce pizzerie se încadrează, mai important este ce client a făcut această comandă. Și înseamnă că acolo este necesar indexul clientului. De asemenea, nu este necesar ca trackerul să stocheze id-ul chitanței tipărite sau al promoțiilor bonus asociate comenzii în tabelul de comenzi. Aceste informații nu sunt de interes pentru serviciul nostru de urmărire. Într-o bază de date monolitică comună, tabelele ar putea fi doar un compromis între toți utilizatorii. Aceasta a fost una dintre problemele inițiale.

A FOST. Arhitectura originală a fost:

Istoria arhitecturii Dodo IS: calea back office

Chiar și după ce au fost separate în procese separate, cea mai mare parte a bazei de cod a rămas comună pentru diferite servicii. Tot ce se afla sub controlere era unic și locuia în același depozit. Am folosit metode comune de servicii, depozite, o bază comună, în care se aflau tabele comune.

Se descarcă Tracker

Principala problemă cu tracker-ul este că datele trebuie sincronizate între diferite baze de date. Aceasta este, de asemenea, principala diferență față de separarea serviciului Auth, ordinea și starea acestuia se pot schimba și ar trebui să fie afișate în diferite servicii.

Acceptăm o comandă la Casa Restaurantului (acesta este un serviciu), este stocată în baza de date în starea „Acceptat”. După aceea, ar trebui să ajungă la tracker, unde își va schimba starea de mai multe ori: de la „Bucătărie” la „Ambalat”. În același timp, odată cu comanda pot apărea și unele influențe externe din interfața Casier sau Shift Manager. Voi da stările comenzii cu descrierea lor în tabel:

Istoria arhitecturii Dodo IS: calea back office
Schema pentru schimbarea stărilor comenzii arată astfel:

Istoria arhitecturii Dodo IS: calea back office

Statusurile se schimbă între diferite sisteme. Și aici tracker-ul nu este un sistem final în care datele sunt închise. Am văzut mai multe abordări posibile pentru partiţionare într-un astfel de caz:

  1. Concentrăm toate acțiunile de comandă într-un singur serviciu. În cazul nostru, această opțiune necesită prea mult service pentru a funcționa cu comanda. Dacă ne-am opri la el, am obține al doilea monolit. Nu vom rezolva problema.
  2. Un sistem efectuează un apel către altul. A doua variantă este deja mai interesantă. Dar odată cu el, sunt posibile lanțuri de apeluri (eșecuri în cascadă), conectivitatea componentelor este mai mare, este mai greu de gestionat.
  3. Noi organizăm evenimente, iar fiecare serviciu comunică cu altul prin aceste evenimente. Drept urmare, a fost a treia opțiune aleasă, conform căreia toate serviciile încep să facă schimb de evenimente între ele.

Faptul că am ales cea de-a treia variantă însemna că tracker-ul ar avea propria bază de date, iar pentru fiecare modificare a comenzii ar trimite un eveniment despre aceasta, la care se abonează și alte servicii și care se încadrează și în baza de date master. Pentru a face acest lucru, aveam nevoie de un serviciu care să asigure livrarea mesajelor între servicii.

Până atunci, aveam deja RabbitMQ în stivă, de unde decizia finală de a-l folosi ca broker de mesaje. Diagrama arată trecerea unei comenzi de la Casieria Restaurantului prin Tracker, unde își schimbă starea și afișarea acesteia pe interfața Comenzile Managerului. DEVENI:

Istoria arhitecturii Dodo IS: calea back office

Calea comenzii pas cu pas
Calea comenzii începe la unul dintre serviciile sursă a comenzii. Iată casieria restaurantului:

  1. La checkout, comanda este complet gata și este timpul să o trimiteți către tracker. Evenimentul la care tracker-ul este abonat este aruncat.
  2. Tracker-ul, acceptând o comandă pentru el însuși, o salvează în propria bază de date, realizând evenimentul „Comandă acceptată de Tracker” și trimițând-o către RMQ.
  3. Există mai mulți handler deja abonați la magistrala de evenimente per comandă. Pentru noi este importantă cea care face sincronizarea cu o bază monolitică.
  4. Handler-ul primește un eveniment, selectează din el datele care sunt semnificative pentru acesta: în cazul nostru, acesta este starea comenzii „Acceptată de Tracker” și își actualizează entitatea de comandă în baza de date principală.

Dacă cineva are nevoie de o comandă din comenzile de masă monolitică, atunci o puteți citi și de acolo. De exemplu, interfața Comenzi din Managerul de ture are nevoie de acest lucru:

Istoria arhitecturii Dodo IS: calea back office

Toate celelalte servicii se pot abona și pentru a comanda evenimente de la tracker pentru a le utiliza singure.

Dacă după un timp comanda este luată în funcțiune, atunci starea sa se schimbă mai întâi în baza de date (baza de date Tracker), iar apoi este generat imediat evenimentul „OrderIn Progress”. De asemenea, intră în RMQ, de unde este sincronizat într-o bază de date monolitică și livrat către alte servicii. Pot exista diverse probleme pe parcurs, mai multe detalii despre ele pot fi găsite în raportul lui Zhenya Peshkov despre detaliile de implementare a Eventual Consistency în Tracker.

Arhitectura finală după modificări în Auth și Tracker

Istoria arhitecturii Dodo IS: calea back office

Rezumând rezultatul intermediar: Inițial, am avut ideea să împachetez istoria de nouă ani a sistemului Dodo IS într-un singur articol. Am vrut să vorbesc rapid și simplu despre etapele evoluției. Totuși, așezându-mă pentru material, mi-am dat seama că totul este mult mai complicat și mai interesant decât pare.

Reflectând la beneficiile (sau lipsa acestora) ale unui astfel de material, am ajuns la concluzia că dezvoltarea continuă este imposibilă fără anale cu drepturi depline ale evenimentelor, retrospective detaliate și analiza deciziilor mele din trecut.

Sper că a fost util și interesant pentru tine să înveți despre drumul nostru. Acum mă confrunt cu o alegere care parte a sistemului Dodo IS să descriu în următorul articol: scrieți în comentarii sau votați.

Numai utilizatorii înregistrați pot participa la sondaj. Loghează-te, Vă rog.

Despre ce parte din Dodo IS ați dori să aflați în următorul articol?

  • 24,1%Monolit timpuriu în Dodo IS (2011-2015)14

  • 24,1%Primele probleme și soluțiile lor (2015-2016)14

  • 20,7%Calea din partea clientului: fațadă peste bază (2016-2017)12

  • 36,2%Istoria microserviciilor reale (2018-2019)21

  • 44,8%Taierea completa a monolitului si stabilizarea arhitecturii26

  • 29,3%Despre planuri ulterioare de dezvoltare a sistemului17

  • 19,0%Nu vreau să știu nimic despre Dodo IS11

Au votat 58 utilizatori. 6 utilizatori s-au abținut.

Sursa: www.habr.com

Adauga un comentariu