Storia dell'architettura Dodo IS: il percorso di back office

Habr sta cambiando il mondo. Scriviamo sul blog da più di un anno. Circa sei mesi fa abbiamo ricevuto feedback abbastanza logici dai residenti di Khabrovsk: “Dodo, dici ovunque che hai il tuo sistema. Che tipo di sistema è questo? E perché ne ha bisogno la catena di pizzerie?”

Ci siamo seduti, abbiamo pensato e ci siamo resi conto che hai ragione. Stiamo cercando di spiegare tutto con le dita, ma il risultato è frammentario e non c'è da nessuna parte una descrizione completa del sistema. Inizia così un lungo viaggio di raccolta informazioni, ricerca di autori e scrittura di una serie di articoli su Dodo IS. Andiamo!

Ringraziamenti: Grazie per aver condiviso il tuo feedback con noi. Grazie a lui abbiamo finalmente descritto il sistema, compilato un technoradar e presto pubblicheremo un'ampia descrizione dei nostri processi. Senza di te saremmo rimasti così per altri 5 anni.

Storia dell'architettura Dodo IS: il percorso di back office

Serie di articoli “Cos’è Dodo IS?” parlerà di:

  1. Primo monolite a Dodo IS (2011-2015). (In corso...)
  2. Percorso backoffice: sedi separate e bus. (Tu sei qui)
  3. Percorso della parte committente: facciata sopra il basamento (2016-2017). (In corso...)
  4. La storia dei microservizi reali. (2018-2019). (In corso...)
  5. Taglio completato del monolite e stabilizzazione dell'architettura. (In corso...)

Se sei interessato a imparare qualcos'altro, scrivi nei commenti.

Opinione sulla descrizione cronologica dell'autore
Tengo regolarmente un incontro per i nuovi dipendenti sul tema "Architettura di sistema". Lo chiamiamo "Introduzione all'architettura Dodo IS" e fa parte del processo di onboarding per i nuovi sviluppatori. Parlando in una forma o nell'altra della nostra architettura, delle sue caratteristiche, ho sviluppato un certo approccio storico alla descrizione.

Tradizionalmente, consideriamo un sistema come un insieme di componenti (tecnici o di livello superiore), moduli aziendali che interagiscono tra loro per raggiungere determinati obiettivi. E sebbene tale visione sia giustificata per la progettazione, non è del tutto adatta alla descrizione e alla comprensione. Ci sono diversi motivi:

  • La realtà è diversa da ciò che è sulla carta. Non tutto funziona come previsto. E siamo interessati a come tutto è andato e funziona effettivamente.
  • Presentazione coerente delle informazioni. In effetti, puoi andare cronologicamente dall'inizio allo stato attuale.
  • Dal semplice al complesso. Non universale, ma nel nostro caso è così. L’architettura è passata da approcci più semplici a quelli più complessi. Spesso, a causa delle complicazioni, si verificano problemi di velocità e stabilità di implementazione, nonché decine di altre proprietà dall'elenco dei requisiti non funzionali (ecco si è parlato molto del contrasto della complessità con altri requisiti).

Nel 2011, l'architettura Dodo IS si presentava così:

Storia dell'architettura Dodo IS: il percorso di back office

Nel 2020, tutto è diventato un po’ più complicato ed è diventato così:

Storia dell'architettura Dodo IS: il percorso di back office

Come è avvenuta questa evoluzione? Perché sono necessarie diverse parti del sistema? Quali decisioni architettoniche sono state prese e perché? Scopriamolo in questa serie di articoli.

I primi problemi del 2016: perché i servizi dovrebbero uscire dal monolite?

I primi articoli della serie riguarderanno i servizi che per primi si separarono dal monolite. Per contestualizzarvi vi racconto quali problemi abbiamo avuto nel sistema all’inizio del 2016, che abbiamo dovuto affrontare con la separazione dei servizi.

Un unico database MySql in cui tutte le applicazioni esistenti in quel momento in Dodo IS scrivevano i loro record. Le conseguenze furono:

  • Carico pesante (con l'85% delle richieste lette).
  • La base stava crescendo. Per questo motivo, costi e supporto sono diventati un problema.
  • Singolo punto di guasto. Se un'applicazione scriveva nel database improvvisamente iniziava a farlo in modo più attivo, anche altre applicazioni ne risentivano.
  • Inefficienza nell'archiviazione e nelle query. Spesso i dati venivano archiviati in una struttura conveniente per alcuni scenari ma non per altri. Gli indici velocizzano alcune operazioni, ma possono rallentarne altre.
  • Alcuni problemi sono stati risolti creando cache e repliche di lettura nei database (questo sarà discusso in un articolo separato), ma ci hanno solo permesso di guadagnare tempo e non hanno risolto fondamentalmente il problema.

Il problema era la presenza del monolite stesso. Le conseguenze furono:

  • Edizioni uniche e rare.
  • La difficoltà sta nello sviluppo collaborativo di un gran numero di persone.
  • Incapacità di introdurre nuove tecnologie, nuovi framework e librerie.

Problemi con la base e il monolite sono stati descritti più volte, ad esempio nel contesto degli incidenti all'inizio del 2018 (Sii come Munch, o qualche parola sul debito tecnico, Il giorno in cui Dodo IS si è fermato. Scrittura asincrona и La storia dell'uccello Dodo della famiglia Phoenix. La Grande Caduta del Dodo IS), quindi non mi dilungherò troppo. Lasciatemi solo dire che volevamo garantire maggiore flessibilità nello sviluppo dei servizi. Prima di tutto, ciò riguardava quelli che erano i più caricati e root nell'intero sistema: Auth e Tracker.

Percorso backoffice: sedi separate e bus

Navigazione nei capitoli

  1. Schema del monolite 2016
  2. Iniziamo a scaricare il monolite: separazione di Auth e Tracker
  3. Cosa fa Auth?
  4. Da dove provengono i carichi?
  5. Aut. scarico
  6. Cosa fa Tracker?
  7. Da dove provengono i carichi?
  8. Scaricamento del localizzatore

Schema del monolite 2016

Ecco i blocchi principali del monolite Dodo IS del 2016, e subito sotto c'è una ripartizione dei loro compiti principali.
Storia dell'architettura Dodo IS: il percorso di back office
Cassa di consegna. Contabilità per i corrieri, emissione ordini ai corrieri.
Centralino. Accettazione ordini tramite operatore.
Website. I nostri siti web (dodopizza.ru, dodopizza.co.uk, dodopizza.by, ecc.).
auth. Servizio di autorizzazione e autenticazione per il backoffice.
inseguitore. Tracker degli ordini in cucina. Servizio per contrassegnare gli stati di disponibilità durante la preparazione di un ordine.
Cassa del ristorante. Prendere ordini in un ristorante, interfacce cassiere.
Esportare. Caricamento di report in 1C per la contabilità.
Avvisi e fatture. Comandi vocali in cucina (ad esempio “È arrivata la nuova pizza”) + stampa fatture per corrieri.
Responsabile del turno. Interfacce per il lavoro di un capoturno: elenco degli ordini, grafici di produttività, portare i dipendenti ai turni.
Capo ufficio. Interfacce per il lavoro di affiliati e gestori: accoglienza dei dipendenti, resoconti sul lavoro della pizzeria.
Consiglio del ristorante. Visualizzazione dei menù sui televisori delle pizzerie.
Ammin. Impostazioni per una pizzeria specifica: menu, prezzi, contabilità, codici promozionali, promozioni, banner per il sito, ecc.
Conto personale del dipendente. Orari di lavoro dei dipendenti, informazioni sui dipendenti.
Pannello motivazionale in cucina. Uno schermo separato appeso in cucina e mostra la velocità dei pizzaioli.
Comunicazione. Invio di sms ed e-mail.
Archiviazione file. Proprio servizio per la ricezione e l'emissione di file statici.

I primi tentativi di risolvere i problemi ci hanno aiutato, ma sono stati solo una tregua temporanea. Non sono diventate soluzioni di sistema, quindi era chiaro che bisognava fare qualcosa con le basi. Ad esempio, dividere il database generale in diversi database più specializzati.

Iniziamo a scaricare il monolite: separazione di Auth e Tracker

I principali servizi che poi hanno scritto e letto dal database più di altri:

  1. Aut. Servizio di autorizzazione e autenticazione per il backoffice.
  2. Localizzatore. Tracker degli ordini in cucina. Servizio per contrassegnare gli stati di disponibilità durante la preparazione di un ordine.

Cosa fa Auth?

L'autenticazione è un servizio attraverso il quale gli utenti accedono al back office (esiste un accesso indipendente separato sul lato client). Viene inoltre fatto riferimento nella richiesta per garantire che siano presenti i diritti di accesso corretti e che tali diritti non siano cambiati dall'ultimo accesso. Attraverso di essa i dispositivi entrano nelle pizzerie.

Vogliamo ad esempio aprire sul televisore appeso nell'ingresso una visualizzazione con lo stato degli ordini completati. Quindi apriamo auth.dodopizza.ru, selezioniamo "Accedi come dispositivo", appare un codice che può essere inserito in una pagina speciale sul computer del capoturno, indicando il tipo di dispositivo (dispositivo). La TV stessa andrà all'interfaccia desiderata della sua pizzeria e inizierà a visualizzare lì i nomi dei clienti i cui ordini sono pronti.

Storia dell'architettura Dodo IS: il percorso di back office

Da dove provengono i carichi?

Ogni utente del backoffice registrato per ogni richiesta va al database, alla tabella utenti, estrae l'utente da lì tramite una query SQL e controlla se ha l'accesso e i diritti necessari su questa pagina.

Ciascuno dei dispositivi fa la stessa cosa solo con la tabella dei dispositivi, controllandone il ruolo ed i suoi accessi. Un gran numero di richieste al database master porta al suo caricamento e allo spreco di risorse generali del database in queste operazioni.

Aut. scarico

Auth ha un dominio isolato, ovvero i dati su utenti, accessi o dispositivi entrano nel servizio (attualmente futuro) e rimangono lì. Se qualcuno ne ha bisogno, andrà a questo servizio per i dati.

ERA. Inizialmente il flusso di lavoro era questo:

Storia dell'architettura Dodo IS: il percorso di back office

Vorrei spiegare un po' come funziona:

  1. Una richiesta esterna arriva al backend (Asp.Net MVC lì), portando con sé un cookie di sessione, che viene utilizzato per ottenere dati di sessione da Redis(1). Contiene informazioni sugli accessi e quindi l'accesso al controller è aperto (3,4) oppure no.
  2. Se non è possibile accedere, è necessario seguire la procedura di autorizzazione. Qui, per semplicità, viene mostrato come parte del percorso nello stesso attributo, sebbene si tratti di una transizione alla pagina di login. In caso di scenario positivo, otterremo una sessione completata correttamente e andremo al Backoffice Controller.
  3. Se sono presenti dati, è necessario verificarne la pertinenza nel database utenti. Il suo ruolo è cambiato, non dovrebbe essere ammesso sulla pagina adesso? In questo caso, dopo aver ricevuto la sessione (1), è necessario recarsi direttamente al database e verificare l'accesso dell'utente utilizzando il livello logico di autenticazione (2). Successivamente, vai alla pagina di accesso o vai al controller. Questo è un sistema semplice, ma non del tutto standard.
  4. Se tutte le procedure vengono completate, salteremo ulteriormente la logica nei controller e nei metodi.

I dati dell'utente sono separati da tutti gli altri dati, sono archiviati in una tabella di appartenenza separata, le funzioni del livello logico AuthService potrebbero benissimo diventare metodi API. I confini del dominio sono definiti in modo abbastanza chiaro: utenti, loro ruoli, dati di accesso, rilascio e revoca dell'accesso. Sembra che tutto possa essere spostato in un servizio separato.

DIVENNE. Questo è quello che hanno fatto:

Storia dell'architettura Dodo IS: il percorso di back office

Questo approccio presenta una serie di problemi. Ad esempio, chiamare un metodo all'interno di un processo non è la stessa cosa che chiamare un servizio esterno tramite http. Latenza, affidabilità, supportabilità e trasparenza dell'operazione sono completamente diverse. Andrei Morevskij ha parlato più dettagliatamente proprio di questi problemi nel suo rapporto "50 sfumature di microservizi".

Il servizio di autenticazione e con esso il servizio dispositivo vengono utilizzati per il back office, cioè per servizi e interfacce utilizzati in produzione. L'autenticazione per i servizi client (come un sito Web o un'applicazione mobile) avviene separatamente senza utilizzare Auth. La separazione è durata circa un anno, e ora ci occupiamo nuovamente di questo argomento, trasferendo il sistema su nuovi servizi di autenticazione (con protocolli standard).

Perché la separazione è durata così tanto tempo?
Ci sono stati molti problemi lungo il percorso che ci hanno rallentato:

  1. Volevamo trasferire i dati su utenti, dispositivi e autenticazione dai database nazionali in uno solo. Per fare ciò, abbiamo dovuto trasferire tutte le tabelle e l'utilizzo dall'identificatore int all'identificatore UUId globale (abbiamo recentemente rielaborato questo codice Roman Bukin “Uuid – la grande storia di una piccola struttura” e progetto open source Primitivi). La memorizzazione dei dati dell'utente (poiché si tratta di informazioni personali) ha i suoi limiti e per alcuni paesi è necessario memorizzarli separatamente. Ma deve esserci un ID utente globale.
  2. Molte tabelle nel database contengono informazioni di controllo sull'utente che ha eseguito l'operazione. Ciò ha richiesto un meccanismo aggiuntivo per garantire la coerenza.
  3. Dopo la creazione dei servizi API c'è stato un lungo e graduale periodo di trasferimento su un altro sistema. I cambiamenti dovevano avvenire senza problemi per gli utenti e richiedevano lavoro manuale.

Schema per la registrazione di un dispositivo in una pizzeria:

Storia dell'architettura Dodo IS: il percorso di back office

Architettura generale dopo aver separato il servizio Auth e Devices:

Storia dell'architettura Dodo IS: il percorso di back office

Nota. Per il 2020 stiamo lavorando a una nuova versione di Auth, basata sullo standard di autorizzazione OAuth 2.0. Questo standard è piuttosto complesso, ma utile per sviluppare un servizio di autenticazione end-to-end. Nell'articolo "Sottigliezze dell'autorizzazione: panoramica della tecnologia OAuth 2.0» noi Alexey Chernyaev abbiamo cercato di parlare dello standard nel modo più semplice e chiaro possibile in modo da risparmiare tempo nello studio.

Cosa fa Tracker?

Ora circa il secondo dei servizi caricati. Il tracker svolge un duplice ruolo:

  • Da un lato, il suo compito è mostrare ai dipendenti in cucina quali ordini sono attualmente in corso, quali prodotti devono essere preparati adesso.
  • D’altra parte, digitalizza tutti i processi in cucina.

Storia dell'architettura Dodo IS: il percorso di back office

Quando un nuovo prodotto (ad esempio la pizza) appare in un ordine, va alla stazione di localizzazione "Rolling". In questa stazione c'è un pizzaiolo che prende un panino della dimensione richiesta e lo stende, dopodiché segna sulla tavoletta tracciatrice che ha completato il suo compito e passa la base di pasta stesa alla stazione successiva - “Ripieno” .

Lì il pizzaiolo successivo ricopre la pizza, poi segna sulla tavoletta che ha terminato il suo compito e inforna la pizza (anche questa è una stazione separata che deve essere segnata sulla tavoletta). Tale sistema era presente fin dall'inizio in Dodo e fin dall'inizio di Dodo IS. Ti consente di tracciare e digitalizzare completamente tutte le operazioni. Inoltre, il tracker suggerisce come preparare un particolare prodotto, realizza ogni tipo di prodotto secondo i propri schemi di produzione, memorizza il tempo di cottura ottimale per il prodotto e tiene traccia di tutte le operazioni sul prodotto.

Storia dell'architettura Dodo IS: il percorso di back officeEcco come appare lo schermo del tablet alla stazione di localizzazione Raskatka.

Da dove provengono i carichi?

Ogni pizzeria dispone di circa cinque tablet con localizzatore. Nel 2016 avevamo più di 100 pizzerie (e ora sono più di 600). Ciascuno dei tablet effettua una richiesta al backend una volta ogni 10 secondi e preleva i dati dalla tabella degli ordini (collegamento con il cliente e indirizzo), dalla composizione dell'ordine (collegamento con il prodotto e indicazione della quantità), dalla tabella contabile motivazionale (il in esso viene registrato il tempo di pressatura). Quando un pizzaiolo clicca su un prodotto nel tracker, le voci di tutte queste tabelle vengono aggiornate. La tabella degli ordini è generale, contiene anche inserti all'accettazione di un ordine, aggiornamenti da altre parti del sistema e numerose letture, ad esempio, sulla TV appesa in pizzeria e mostra ai clienti gli ordini finiti.

Durante il periodo di lotta con i carichi, quando tutto e tutto veniva memorizzato nella cache e trasferito alla replica asincrona della base, queste operazioni con il tracker continuavano ad andare alla base principale. Non dovrebbe esserci alcun ritardo, i dati dovrebbero essere aggiornati, la mancata sincronizzazione è inaccettabile.

Inoltre, la mancanza di tabelle e indici propri su di essi non ha consentito di scrivere query più specifiche su misura per il loro utilizzo. Ad esempio, potrebbe essere efficiente per un tracker avere un indice per una pizzeria su una tabella degli ordini. Estraiamo sempre gli ordini delle pizzerie dal database dei tracker. Allo stesso tempo, per ricevere un ordine, non è così importante in quale pizzeria si trova, è più importante quale cliente ha effettuato questo ordine. Ciò significa che è necessario che sia presente un indice sul client. Inoltre, non è necessario che il tracker memorizzi l'ID della ricevuta stampata o delle promozioni bonus associate all'ordine nella tabella degli ordini. Il nostro servizio di localizzazione non è interessato a queste informazioni. In un comune database monolitico, le tabelle potrebbero essere solo un compromesso tra tutti gli utenti. Questo era uno dei problemi originali.

ERA. Inizialmente l'architettura era questa:

Storia dell'architettura Dodo IS: il percorso di back office

Anche dopo essere stata separata in processi separati, la maggior parte del codice base è rimasta comune a diversi servizi. Tutto sotto i controller era unificato e viveva in un unico repository. Sono stati utilizzati metodi comuni di servizi, repository e un database comune contenente tabelle comuni.

Scaricamento del localizzatore

Il problema principale con il tracker è che i dati devono essere sincronizzati tra diversi database. Questa è anche la differenza principale rispetto alla separazione del servizio Auth, l'ordine e il suo stato possono cambiare e dovrebbero essere visualizzati in servizi diversi.

Accettiamo un ordine alla cassa del ristorante (questo è un servizio), viene archiviato nel database nello stato "Accettato". Dopodiché, dovrebbe raggiungere il tracker, dove cambierà il suo stato più volte: da "Cucina" a "Imballato". Allo stesso tempo, sull'ordine potrebbero verificarsi alcune influenze esterne da parte del cassiere o dell'interfaccia del responsabile del turno. Fornirò gli stati dell'ordine con le relative descrizioni nella tabella:

Storia dell'architettura Dodo IS: il percorso di back office
Lo schema di modifica dello stato dell'ordine è simile al seguente:

Storia dell'architettura Dodo IS: il percorso di back office

Gli stati cambiano tra i diversi sistemi. E qui il tracker non è il sistema finale in cui vengono bloccati i dati. Abbiamo visto diversi possibili approcci per la separazione in questo caso:

  1. Concentriamo tutte le azioni relative agli ordini in un unico servizio. Nel nostro caso, questa opzione richiede troppo servizio per elaborare l'ordine. Se ci fossimo fermati lì, ci saremmo ritrovati con un secondo monolite. Non avremmo risolto i problemi.
  2. Un sistema effettua una chiamata a un altro. La seconda opzione è più interessante. Ma con esso sono possibili catene di chiamate (fallimenti a cascata), la connettività dei componenti è più elevata ed è più difficile da gestire.
  3. Organizziamo eventi e ogni servizio scambia con l'altro attraverso questi eventi. Di conseguenza, è stata scelta la terza opzione, secondo la quale tutti i servizi iniziano a scambiarsi eventi tra loro.

Il fatto che abbiamo scelto la terza opzione significava che il tracker avrebbe avuto il proprio database e per ogni modifica nell'ordine avrebbe inviato un evento al riguardo, al quale si sarebbero iscritti altri servizi e che sarebbe stato incluso anche nel database principale. Per fare ciò, avevamo bisogno di un servizio che garantisse la consegna dei messaggi tra i servizi.

A quel punto, avevamo già RabbitMQ nello stack, da qui la decisione finale di utilizzarlo come broker di messaggi. Il diagramma mostra la transizione di un ordine dalla Cassa del ristorante al Tracker, dove cambia il suo stato e la sua visualizzazione sull'interfaccia Ordini del Gestore. ERA:

Storia dell'architettura Dodo IS: il percorso di back office

Percorso dell'ordine passo dopo passo
Il percorso dell'ordine inizia in uno dei servizi di origine dell'ordine. Ecco la Cassa del Ristorante:

  1. L'ordine è completamente pronto alla cassa ed è ora di inviarlo al tracker. Viene generato l'evento a cui è iscritto il tracker.
  2. Il tracker, accettando un ordine per se stesso, lo salva nel proprio database, creando l'evento "Ordine accettato dal tracker" e inviandolo a RMQ.
  3. Diversi gestori sono già iscritti al bus di eventi personalizzato. Per noi è importante quello che si sincronizza con il database monolitico.
  4. L'handler riceve l'evento, seleziona da esso i dati per esso significativi: nel nostro caso si tratta dello stato dell'ordine “Accettato dal Tracker” e aggiorna la sua entità ordine nel database principale.

Se qualcuno ha bisogno di un ordine specifico dalla tabella degli ordini monolitica, può leggerlo anche da lì. Ad esempio, questo è ciò di cui ha bisogno l'interfaccia Ordini nel Gestore Turni:

Storia dell'architettura Dodo IS: il percorso di back office

Tutti gli altri servizi possono anche iscriversi per ordinare eventi dal tracker per utilizzarli autonomamente.

Se dopo qualche tempo un ordine viene messo in produzione, il suo stato cambia prima nel suo database (database Tracker), e poi viene immediatamente generato l'evento “OrderInWork”. Entra anche in RMQ, da dove viene sincronizzato in un database monolitico e distribuito ad altri servizi. Lungo questo percorso potrebbero esserci vari problemi; maggiori dettagli al riguardo possono essere trovati nel rapporto di Zhenya Peshkov sui dettagli di implementazione di Eventual Consistency in Tracker.

Architettura finale dopo le modifiche ad Auth e Tracker

Storia dell'architettura Dodo IS: il percorso di back office

Riassumere: Inizialmente, ho avuto l'idea di racchiudere i nove anni di storia del sistema Dodo IS in un unico articolo. Volevo parlare velocemente e semplicemente delle fasi dell'evoluzione. Tuttavia, sedendomi sul materiale, mi sono reso conto che tutto è molto più complicato e interessante di quanto sembri.

Riflettendo sui vantaggi (o sulla loro mancanza) di tale materiale, sono giunto alla conclusione che lo sviluppo continuo è impossibile senza cronache complete degli eventi, retrospettive dettagliate e analisi delle proprie decisioni passate.

Spero che tu abbia trovato utile e interessante conoscere il nostro viaggio. Ora mi trovo di fronte alla scelta di quale parte del sistema Dodo IS descrivere nel prossimo articolo: scrivi nei commenti o vota.

Solo gli utenti registrati possono partecipare al sondaggio. AccediPer favore.

Quale parte di Dodo IS vorresti conoscere nel prossimo articolo?

  • 24,1%Primo monolite di Dodo IS (2011-2015)14

  • 24,1%Primi problemi e loro soluzioni (2015-2016)14

  • 20,7%Percorso della parte committente: facciata sopra il basamento (2016-2017)12

  • 36,2%Storia dei microservizi reali (2018-2019)21

  • 44,8%Taglio completato del monolite e stabilizzazione dell'architettura26

  • 29,3%Su ulteriori piani per lo sviluppo del sistema17

  • 19,0%Non voglio sapere nulla di Dodo IS11

58 utenti hanno votato. 6 utenti si sono astenuti.

Fonte: habr.com

Aggiungi un commento