Il direttore delle operazioni del portale Banki.ru, Andrey Nikolsky, ha parlato alla conferenza dell'anno scorso sui servizi orfani: come identificare un orfano nell'infrastruttura, quali siano i problemi dei servizi orfani, cosa fare e come comportarsi se non c'è altra soluzione.
Di seguito troverete la versione testuale della relazione.

Salve, colleghi! Mi chiamo Andrey e mi occupo delle operazioni in Banki.ru.
Abbiamo grandi servizi, ci sono monolith-service, ci sono servizi in una comprensione più classica e ci sono quelli molto piccoli. Nella mia terminologia di lavoro dico che se un servizio è semplice e piccolo, è micro, se non è molto semplice e non è piccolo, è semplicemente un servizio.
Vantaggi dei servizi
Darò un rapido sguardo ai vantaggi dei servizi.

Primo: scalabilità. Puoi rapidamente fare qualcosa su un servizio e avviarlo in produzione. Se ricevi traffico, cloni il servizio. Se ricevi altro traffico, lo cloni di nuovo e continui così. Questo è un buon vantaggio e, in effetti, quando abbiamo iniziato, era considerato il motivo principale per cui facciamo tutto questo.

In secondo luogo, lo sviluppo isolato, quando hai più team di sviluppo, diversi sviluppatori in ogni team, e ogni team sviluppa il proprio servizio.
Con i team ci sono delle sfide. Gli sviluppatori sono diversi. Esistono, ad esempio, . L'ho visto per la prima volta da Maxim Dorofeev. A volte, le persone uniche sono presenti in alcuni team, mentre in altri no. Questo rende i diversi servizi utilizzati in azienda un po' disomogenei.

Guarda l'immagine: questo è un buon sviluppatore, ha grandi mani e può fare molte cose. Il problema principale è capire da dove provengono queste mani.

I servizi offrono la possibilità di utilizzare diversi linguaggi di programmazione, più adatti a compiti specifici. Alcuni servizi sono in Go, altri in Erlang, altri in Ruby, alcuni in PHP, altri in Python. Insomma, si può spaziare molto. Anche qui ci sono delle sfide.

L'architettura orientata ai servizi riguarda soprattutto il devops. Cioè, se non hai automazione, non hai un processo di deployment, se configuri manualmente, le tue configurazioni possono cambiare da una istanza all'altra e devi entrare per fare qualcosa, sei nei guai.
Ad esempio, hai 20 servizi e devi deployare manualmente, hai 20 console, e premi contemporaneamente 'invio', come un ninja. Non è una situazione molto ideale.
Se hai un servizio dopo il testing (se ovviamente ci sono stati test) e hai ancora bisogno di perfezionarlo per farlo funzionare in produzione, ho anche brutte notizie per te.
Se fai affidamento su specifici servizi di Amazon e lavori in Russia, due mesi fa anche tu avevi 'tutto intorno brucia, sto bene, va tutto alla grande'.

Utilizziamo Ansible per automatizzare il deploy, Puppet per la convergenza, Bamboo per l'automazione del deployment, Confluence per documentare tutto questo.
Non ci approfondirò perché la presentazione riguarda più le pratiche di interazione piuttosto che l'implementazione tecnica.

Ci sono state volte in cui, ad esempio, Puppet sul server funziona con Ruby 2, mentre un'applicazione è scritta per Ruby 1.8, e insieme non funzionano. Si verifica qualche problema. Quando devi mantenere più versioni di Ruby su una sola macchina, in genere iniziano i guai.
Noi, ad esempio, forniamo a ogni sviluppatore un ambiente in cui ci sono più o meno tutti i servizi disponibili, così che abbia un ambiente isolato, possa romperlo e ricostruirlo come desidera.
A volte serve un pacchetto compilato specificamente con supporto per alcune funzionalità. È una questione piuttosto rigida. Ho ascoltato una presentazione il cui'immagine Docker pesa 45 GB. Certo, su Linux è più semplice, tutto è più leggero, ma comunque non ci sarà mai abbastanza spazio.
Inoltre, ci sono dipendenze conflittuali, quando un pezzo del progetto dipende da una versione di una libreria, mentre un altro pezzo dipende da un'altra versione, e queste librerie non possono essere installate insieme in alcun modo.

Abbiamo siti e servizi su PHP 5.6, di cui ci vergogniamo, ma che ci possiamo fare. Questa è una delle nostre piattaforme. Abbiamo siti e servizi su PHP 7, che sono di più e di cui non ci vergogniamo. E ogni sviluppatore ha il suo database, dove lavora felice.
Se scrivete in azienda in un'unica lingua, tre macchine virtuali per sviluppatore suona normale. Se avete diversi linguaggi di programmazione, la situazione peggiora.

Avete siti e servizi su questo, su quello, poi un'altra piattaforma per Go, una piattaforma per Ruby, e qualche Redis aggiuntivo. Alla fine, tutto ciò si trasforma in un grande campo di supporto, e qualcosa potrebbe rompersi in qualsiasi momento.

Perciò abbiamo sostituito le comodità del linguaggio di programmazione con l'uso di diversi framework, poiché i framework su PHP sono abbastanza diversi, con varie possibilità, comunità e supporto. E si può scrivere un servizio in modo tale che ci sia già qualcosa di pronto per esso.
Ogni servizio ha il proprio team.

Il nostro principale vantaggio, che si è cristallizzato nel corso degli anni, è che ogni servizio ha il proprio team. Questo è comodo per grandi progetti, poiché consente di risparmiare tempo sulla documentazione, e i manager conoscono bene il loro progetto.
È possibile gestire facilmente i compiti di supporto. Ad esempio, se un servizio di assicurazione si guasta, immediatamente il team che si occupa delle assicurazioni interviene per ripararlo.
Nuove funzionalità vengono implementate rapidamente, perché quando avete un servizio atomico, è possibile integrare qualcosa di operativo in modo tempestivo.
E quando il vostro servizio si guasta, cosa che inevitabilmente succede, non toccate i servizi di altri, e i programmatori di altri team non vengono da voi impugnando mazze dicendo: «Ah-ah, non fare così».

Come sempre, ci sono delle sfide. Abbiamo team stabili, i manager sono ben legati ai loro team. Ci sono documenti chiari, e i manager monitorano attentamente tutto. Ogni team ha diversi servizi assegnati al manager, e c'è un punto di competenza definito.
Se i team sono fluttuanti (questo a volte accade anche da noi), c'è un buon metodo chiamato 'mappa stellare'.

Hai un elenco di servizi e persone. L'asterisco indica che una persona è un esperto in quel servizio, mentre il libro indica che una persona sta studiando quel servizio. L'obiettivo della persona è cambiare il libro in un asterisco. Se non c'è nulla scritto accanto al servizio, allora ci sono problemi di cui parlerò più avanti.
Come nascono i servizi orfani?

Il primo problema, il primo modo per avere un servizio orfano nella propria infrastruttura, è il licenziamento delle persone. Qualcuno ha mai vissuto il momento in cui scadenze aziendali arrivano prima della valutazione delle attività? A volte ci sono scadenze rigide e non c'è nemmeno tempo per la documentazione. 'Devi consegnare il servizio in produzione, poi lo completeremo.'
Se il team è piccolo, può capitare che ci sia un solo sviluppatore che scrive tutto, mentre gli altri sono a supporto. «Ho scritto l'architettura principale, tu occupati delle interfacce». Poi, a un certo punto, il manager se ne va. E in quel periodo, quando il manager è andato via e non è ancora stato nominato un nuovo, gli sviluppatori decidono da soli in quale direzione va il servizio, cosa sta succedendo. E come sappiamo (torniamo indietro di qualche slide), in alcuni team ci sono persone-uniche, a volte una persona-unica è il team leader. Poi si dimette, e ci troviamo con un servizio-orfano.

Nel frattempo, le richieste di supporto e quelle aziendali non scompaiono, si accumulano nel backlog. Se durante lo sviluppo del servizio ci sono stati errori architettonici, anch'essi si accumulano nel backlog. Il servizio degrada lentamente.
Come riconoscere un orfano?
Questa lista descrive abbastanza bene la situazione. Chi ha riconosciuto qualcosa nella propria infrastruttura?

Riguardo ai work-around documentati: c'è un servizio che, in generale, funziona, ha un manuale di due pagine su come utilizzarlo, ma come funziona internamente, nessuno lo sa.
Oppure, ad esempio, ci sono dei servizi di accorciamento link. Noi, per esempio, attualmente utilizziamo tre diversi servizi di accorciamento link per scopi diversi in vari servizi. Sono queste le conseguenze.

Ora sarò il capitano dell'ovvietà. Cosa bisogna fare? Prima di tutto, è necessario trasferire il servizio a un altro manager, a un altro team. Se il tuo team leader non si è ancora dimesso, allora in questo altro team, quando capisci che il servizio è simile a un orfano, bisogna includere qualcuno che ne comprenda almeno un po'.
La cosa principale: devono esserci procedure di trasferimento scritte come inchiostro. Nel nostro caso, di solito mi occupo di questo, perché ho bisogno che tutto funzioni. I manager hanno bisogno che venga consegnato rapidamente, e quel che accadrà dopo non è più così importante per loro.

Il modo successivo per creare un orfano è: "Facciamolo in outsourcing, sarà più veloce, e poi lo daremo al team". È chiaro che tutti hanno dei piani nel team, una lista d'attesa. Spesso il cliente aziendale pensa che l'outsourcing farà le cose allo stesso modo del tech team presente nell'azienda. Anche se i motivatori sono diversi. In outsourcing ci possono essere soluzioni tecnologiche strane e soluzioni algoritmiche bizzarre.

Ad esempio, avevamo un servizio in cui Sphinx si trovava in posti inaspettati. Più tardi spiegherò cosa ho dovuto fare.
Gli outsourcer utilizzano framework scritti da loro. È semplicemente PHP puro con copia-incolla da un progetto precedente, dove si può trovare di tutto. Grandi patch nei script di deployment, quando è necessario modificare alcune righe in un file utilizzando complesse script Bash, mentre questi script di deployment vengono chiamati da un terzo script. Alla fine, cambi il sistema di deployment, scegli qualcosa di diverso, e puff, il tuo servizio smette di funzionare. Perché dovevi anche impostare 8 link tra diverse cartelle. Oppure può succedere che mille record funzionano, mentre centomila no.
Continuerò a fare da capitano. L'accettazione del servizio dall'outsourcing è una procedura necessaria. A chi è capitato che un servizio esternalizzato arrivi e non venga accettato? Non è così popolare come un servizio orfano, ma comunque.

È necessario controllare il servizio, rivedere il servizio, cambiare le password. Abbiamo avuto un caso in cui ci hanno proposto un servizio, con un'admin che diceva 'if login == ‘admin’ && password == ‘admin’...'. È scritto direttamente nel codice! Stiamo qui a pensare: ma sono davvero persone che scrivono questo nel 2018?
Testare lo spazio di archiviazione è fondamentale. Bisogna vedere cosa succede con centomila registrazioni, prima di lanciare questo servizio in produzione.

Non dovrebbe essere imbarazzante inviare un servizio per ulteriori miglioramenti. Quando dici: 'Non accetteremo questo servizio, abbiamo 20 compiti, completate questi e lo accetteremo', è normale. La coscienza non dovrebbe pesare nel mettere in difficoltà un manager o nel spendere soldi per un business. Alla fine il business spenderà di più.
Abbiamo avuto un caso in cui abbiamo deciso di avviare un progetto pilota in outsourcing.

È stato consegnato in tempo, ed è stato l'unico criterio di qualità. Così abbiamo realizzato un altro progetto pilota, non proprio più pilota. Questi servizi sono stati accolti, hanno detto per vie amministrative, ecco il vostro codice, ecco il team, ecco il vostro manager. I servizi hanno già iniziato a generare profitto. Tuttavia, di fatto, sono rimasti ancora orfani, nessuno capisce come funzionano, e i manager si dissociano in tutti i modi dai loro compiti.

C'è un altro concetto interessante: lo sviluppo partigiano. Quando qualche dipartimento, di solito quello marketing, vuole testare un'ipotesi e fa un ordine per un servizio interamente in outsourcing. Inizia a ricevere traffico, chiudono i documenti, firmano contratti con il fornitore, entrano in produzione e dicono: «Ragazzi, abbiamo qui un servizio, ha già traffico, ci sta generando entrate, accettiamolo». E noi diciamo: «Ecco, come mai?»

Un altro modo per ottenere un servizio orfano è quando un team si trova all'improvviso sovraccarico; la direzione dice: «Trasferiamo il servizio di questo team a un altro team, che ha meno lavoro». Poi lo trasferiamo a un terzo team, cambiando anche il manager. Alla fine ci ritroviamo di nuovo con un orfano.
Qual è il problema con gli orfani?

Chi non lo sa, è la nave da guerra Wasa, costruita in Svezia, famosa per essere affondato cinque minuti dopo essere stata varata. E il re di Svezia, tra l'altro, non ha fatto giustiziare nessuno per questo. È stata costruita da due generazioni di ingegneri che non sapevano costruire tali navi. Un effetto prevedibile.
La nave avrebbe potuto affondare, per esempio, in modo molto peggiore, ad esempio se il re ci fosse salito per andare da qualche parte durante una tempesta. Così, è affondata subito, il che è positivo in un'ottica agile: il fallimento precoce è buono.
Se falliamo presto, di solito non ci sono problemi. Ad esempio, durante l'accettazione, viene rimandato per le modifiche. Ma se falliamo già in produzione, quando sono stati investiti dei soldi, potrebbero sorgere dei problemi. Conseguenze, come vengono chiamate in ambito commerciale.
Quali sono i pericoli dei servizi orfani:
- Il servizio può rompersi all'improvviso.
- Il servizio richiede molto tempo per essere riparato o non può essere riparato affatto.
- Problemi di sicurezza.
- Problemi con le modifiche e gli aggiornamenti.
- Se un servizio importante si guasta, la reputazione dell'azienda ne risente.
Cosa fare con i servizi orfani?

Ribadisco cosa fare. In primo luogo, deve esserci documentazione. 7 anni in Banki.ru mi hanno insegnato che i tester non devono fidarsi ciecamente degli sviluppatori, e l'operatività non deve fidarsi di nessuno a scatola chiusa. È fondamentale controllare.

In secondo luogo, è necessario scrivere schemi di interazione, perché a volte i servizi che non vengono accolti bene contengono dipendenze di cui nessuno ha parlato. Ad esempio, gli sviluppatori hanno integrato il servizio usando una chiave per Yandex.Maps o Dadata. Se hai esaurito il limite gratuito, tutto si rompe e non sai cosa sia successo. Tutte queste problematiche devono essere documentate: nel servizio è utilizzato Dadata, Sms, altro ancora.

In terzo luogo, gestire il debito tecnico. Quando crei delle soluzioni temporanee o accetti un servizio dicendo che qualcosa deve essere fatto, è importante assicurarsi che venga effettuato. Perché poi potrebbe rivelarsi che un piccolo problema non è così piccolo e tu ci cadi dentro.
Abbiamo avuto una storia con Sphinx proprio riguardo a compiti di architettura. In uno dei servizi, Sphinx è stato utilizzato per gestire elenchi. Era semplicemente un elenco con paginazione, ma veniva riindicizzato ogni notte. Era composto da due indici: uno di grandi dimensioni che veniva indicizzato ogni notte e uno più piccolo che veniva collegato a esso. Ogni giorno, con una probabilità del 50%, o andava bene, o no; durante il caricamento, l'indice si rompeva e le notizie smettevano di aggiornarsi sulla pagina principale. Inizialmente, ci metteva 5 minuti per riindicizzarsi, poi l'indice è cresciuto e a un certo punto ha iniziato a riindicizzarsi in 40 minuti. Quando abbiamo risolto il problema, abbiamo tirato un sospiro di sollievo, perché era chiaro che sarebbe passato ancora del tempo e avremmo avuto l'indice da riindicizzare per un'intera giornata lavorativa. Sarebbe stato un fallimento per il nostro portale: otto ore senza notizie — per noi significava che l'attività si sarebbe fermata.
Piano di lavoro con il servizio orfano

In realtà, è molto difficile farlo, perché il DevOps riguarda la comunicazione. È importante avere buone relazioni con i colleghi, ma quando si colpisce i colleghi e i manager con normative rigide, possono provare sentimenti contrastanti nei confronti di chi agisce in questo modo.
Oltre a tutti questi punti, c'è un'altra cosa importante: per ogni servizio specifico, ogni parte della procedura di distribuzione deve essere responsabilità di persone specifiche. Quando le persone non ci sono e si devono coinvolgere altre persone per studiare il tutto, diventa difficile.

Se tutto ciò non ha funzionato e il servizio orfano è ancora tale, nessuno lo vuole, la documentazione non viene redatta, e il team convocato per quel servizio si rifiuta di fare qualsiasi cosa, c'è un modo semplice: rifare tutto.
Quindi prendi nuovamente i requisiti per il servizio e crei un nuovo servizio, migliore, su una piattaforma migliore, senza soluzioni tecnologiche strane. E migri a questo in produzione.

Abbiamo avuto una situazione in cui abbiamo adottato un servizio su Yii 1 e ci siamo resi conto che non potevamo continuare a svilupparlo, perché non avevamo più programmatori capaci di scrivere bene in Yii 1. Tutti i programmatori scrivono bene in Symfony 3. Cosa fare? Abbiamo dedicato tempo, abbiamo formato un team, assegnato un manager, riscritto il progetto e gradualmente spostato il traffico su di esso.
Dopo di che, il vecchio servizio può essere eliminato. Questa è la mia procedura preferita, quando dalla gestione della configurazione è necessario prendere un servizio e rimuoverlo, e poi controllare che tutte le macchine in produzione siano state spente, per assicurarsi che non rimangano tracce per gli sviluppatori. Il repository in Git rimane.
Questo è tutto ciò di cui volevo parlare, sono pronto a discutere, è un tema controverso, molti ci si sono cimentati.
Nelle diapositive si parlava di come avete unificato i linguaggi. Come esempio c'era il ridimensionamento delle immagini. È davvero necessario limitarsi a un solo linguaggio? Perché ridimensionare un'immagine in PHP si poteva realmente fare anche in Golang.
In realtà, non è obbligatorio, come molte pratiche. In alcuni casi potrebbe addirittura essere indesiderato. Tuttavia, bisogna comprendere che se nella vostra azienda ci sono 50 persone nel dipartimento tecnico, di cui 45 sono sviluppatori PHP, 3 sono DevOps che sanno utilizzare Python, Ansible, Puppet e simili, e solo uno di loro scrive un servizio in Go per il ridimensionamento delle immagini, quando se ne va, anche la sua expertise se ne va con lui. In questo caso, dovrete cercare sul mercato uno sviluppatore specifico che conosca quel linguaggio, specialmente se raro. Quindi, dal punto di vista organizzativo, è problematico. Dal punto di vista DevOps, non basta clonare un insieme di playbook che utilizzate per distribuire servizi; dovrete riscriverli da zero.
Attualmente stiamo sviluppando un servizio su Node.js, e sarà proprio un ambiente dedicato per ogni sviluppatore con un linguaggio separato. Tuttavia, abbiamo pensato che ne valga la pena. Quindi, qui c'è da sedersi e riflettere.
Come monitorate i vostri servizi? Come raccogliete e tracciate i log?
Raccogliamo i log in Elasticsearch e li visualizziamo in Kibana. A seconda che si tratti di ambienti di produzione o di test, utilizziamo diversi raccoglitori. In alcuni casi usiamo Lumberjack, in altri non ricordo. Ci sono anche alcuni posti in servizi specifici dove impostiamo Telegraf e lo inviamo separatamente.
Come convivere con Puppet e Ansible in un unico ambiente?
In realtà, attualmente abbiamo due ambienti, uno con Puppet e l'altro con Ansible. Stiamo lavorando per ibridarli. Ansible è un buon ambiente per la configurazione iniziale, mentre Puppet non è ideale per questo perché richiede un lavoro manuale diretto con la piattaforma e garantisce la convergenza della configurazione. Questo significa che la piattaforma si mantiene da sola aggiornata, mentre per mantenere una macchina con Ansible aggiornata è necessario eseguire costantemente i playbook con una certa periodicità. Questa è la differenza.
Come mantenete la compatibilità? Avete configurazioni sia in Ansible che in Puppet?
È un nostro grande problema, supportiamo la compatibilità manualmente e stiamo pensando a come trasferirci altrove. Attualmente, Puppet gestisce i pacchetti e mantiene alcuni riferimenti, mentre Ansible, ad esempio, implementa il codice e adatta lì le nuove configurazioni delle applicazioni.
Nella presentazione si parlava delle diverse versioni di Ruby. Qual è la soluzione?
Ci siamo imbattuti in questo in un luogo e dobbiamo tenerlo sempre a mente. Abbiamo semplicemente disabilitato quella parte che funzionava con il Ruby incompatibile con le applicazioni e l'abbiamo tenuta separata.
Quest'anno la conferenza si terrà il 7 dicembre al «Tecnopoli». Fino all'11 novembre accettiamo proposte per le relazioni. se volete partecipare come relatori.
La registrazione per i partecipanti è aperta, unitevi a noi!
Fonte: habr.com
