JavaRush /Java Blog /Random-IT /Una guida ai microservizi Java. Parte 1: nozioni di base ...

Una guida ai microservizi Java. Parte 1: nozioni di base e architettura dei microservizi

Pubblicato nel gruppo Random-IT
In questa guida imparerai cosa sono i microservizi Java, come progettarli e crearli. Copre anche domande sulle librerie di microservizi Java e sulla fattibilità dell'utilizzo dei microservizi. Traduzione e adattamento dei microservizi Java: una guida pratica .

Microservizi Java: nozioni di base

Per comprendere i microservizi, devi prima definire cosa non sono. Non è un “monolite” - monolite Java: cos'è e quali sono i suoi vantaggi e svantaggi? Una guida ai microservizi Java.  Parte 1: Nozioni di base e architettura dei microservizi - 1

Cos'è un monolite Java?

Immagina di lavorare per una banca o una startup fintech. Fornisci agli utenti un'app mobile che possono utilizzare per aprire un nuovo conto bancario. Nel codice Java ciò risulterà nella presenza di una classe controller. Semplificato, assomiglia a questo:
@Controller
class BankController {

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        riskCheck(form);
        openBankAccount(form);
        // etc..
    }
}
È necessario che il controller:
  1. Confermato il modulo di registrazione.
  2. Controlla i rischi dell'indirizzo dell'utente per decidere se fornirgli un conto bancario.
  3. Ha aperto un conto bancario.
La classe BankControllerverrà impacchettata insieme al resto dei tuoi sorgenti in un file bank.jar o bank.war per la distribuzione: questo è un buon vecchio monolite contenente tutto il codice necessario per gestire la tua banca. Come stima approssimativa, la dimensione iniziale di un file .jar (o .war) varierà da 1 a 100 MB. Ora puoi semplicemente eseguire il file .jar sul tuo server... e questo è tutto ciò che devi fare per distribuire la tua applicazione Java. Una guida ai microservizi Java.  Parte 1: Nozioni di base e architettura dei microservizi - 2Immagine, rettangolo in alto a sinistra: distribuzione di una banca mono(litica) java -jar bank.jar (cp .war/.ear in appserver). Rettangolo destro: browser aperto.

Qual è il problema con i monoliti Java?

Non c'è nulla di intrinsecamente sbagliato nei monoliti Java. Tuttavia, l'esperienza ha dimostrato che se nel tuo progetto:
  • Ci sono molti programmatori/team/consulenti che lavorano...
  • ...sullo stesso monolite sotto la pressione di clienti con requisiti molto vaghi...
  • nel giro di un paio d'anni...
... quindi in questo caso il tuo piccolo file bank.jar si trasforma in un immenso gigabyte di codice da solo, il che è spaventoso anche solo da avvicinare, per non parlare di distribuire.

Come ridurre le dimensioni di un monolite Java?

Sorge spontanea una domanda: come rimpicciolire il monolite? In questo momento il tuo bank.jar è in esecuzione su una JVM, un processo su un server. Ne più ne meno. E in questo momento potrebbe venirmi in mente un pensiero logico: “Ma il servizio di verifica dei rischi può essere utilizzato da altri reparti della mia azienda! Non è direttamente correlato alla mia applicazione bancaria monolitica! Forse dovrebbe essere tagliato fuori dal monolite e distribuito come prodotto separato? Cioè, tecnicamente parlando, eseguirlo come un processo Java separato.

Cos'è un microservizio Java?

In pratica questa frase significa che ora la chiamata al metodo riskCheck()non verrà effettuata da BankController: questo metodo o componente bean con tutte le sue classi ausiliarie verrà spostato nel proprio progetto Maven o Gradle. Sarà inoltre distribuito e posto sotto controllo di versione indipendentemente dal monolite bancario. Tuttavia, l'intero processo di estrazione non trasforma il nuovo modulo RiskCheck in un microservizio di per sé, poiché la definizione di microservizio è aperta all'interpretazione. Ciò porta a frequenti discussioni all’interno di team e aziende.
  • Ci sono 5-7 lezioni in un progetto micro o cosa?
  • 100 o 1000 lezioni... ancora micro?
  • Il microservizio è generalmente correlato al numero di classi o no?
Lasciamo alle spalle il ragionamento teorico e atteniamoci invece a considerazioni pragmatiche e facciamo questo:
  1. Chiamiamo microservizi tutti i servizi distribuiti separatamente, indipendentemente dalle loro dimensioni o dai limiti del dominio.
  2. Pensiamo a come organizzare la comunicazione tra servizi. I nostri microservizi necessitano di modi per comunicare tra loro.
Quindi, per riassumere: in precedenza avevi un processo JVM, un solido monolite per gestire la banca. Ora disponi di un processo JVM monolitico bancario e di un microservizio RiskCheck separato che viene eseguito all'interno del proprio processo JVM. E ora, per verificare i rischi, il tuo monolite deve chiamare questo microservizio. Come fare questo?

Come stabilire la comunicazione tra i microservizi Java?

In generale e in generale ci sono due opzioni: comunicazione sincrona e asincrona.

Comunicazione sincrona: (HTTP)/REST

In genere, la comunicazione sincronizzata tra i microservizi avviene tramite HTTP e servizi simili a REST che restituiscono XML o JSON. Naturalmente potrebbero esserci altre opzioni: prendi almeno Google Protocol Buffers . Se hai bisogno di una risposta immediata, è meglio utilizzare la comunicazione REST. Nel nostro esempio, questo è esattamente ciò che deve essere fatto, poiché è necessaria la verifica del rischio prima di aprire un conto. Se non c’è controllo del rischio, non c’è conto. Discuteremo gli strumenti di seguito, nella sezione “ Quali librerie sono le migliori per le chiamate REST Java sincrone ”.

Messaggistica - Comunicazione asincrona

La comunicazione asincrona dei microservizi viene in genere eseguita scambiando messaggi con un'implementazione JMS e/o utilizzando un protocollo come AMQP . Abbiamo scritto “solitamente” qui per un motivo: diciamo che il numero di integrazioni email/SMTP non può essere sottovalutato. Usalo quando non hai bisogno di una risposta immediata. Ad esempio, l'utente fa clic sul pulsante "acquista ora" e tu, a tua volta, desideri generare una fattura. Questo processo certamente non dovrebbe avvenire all'interno del ciclo di richiesta-risposta di acquisto dell'utente. Di seguito descriveremo quali strumenti sono i migliori per la messaggistica Java asincrona .

Esempio: chiamata API REST in Java

Supponiamo di scegliere la comunicazione sincrona dei microservizi. In questo caso, il nostro codice Java (quello che abbiamo presentato sopra) a basso livello sarà simile a questo. (per livello basso qui intendiamo il fatto che per la comunicazione dei microservizi vengono solitamente create librerie client che ti astraono dalle effettive chiamate HTTP).
@Controller
class BankController {

    @Autowired
    private HttpClient httpClient;

    @PostMapping("/users/register")
    public void register(RegistrationForm form) {
        validate(form);
        httpClient.send(riskRequest, responseHandler());
        setupAccount(form);
        // etc..
    }
}
In base al codice risulta chiaro che ora dobbiamo implementare due (micro)servizi Java, Bank e RiskCheck. Di conseguenza, avremo due processi JVM in esecuzione. Una guida ai microservizi Java.  Parte 1: Nozioni di base e architettura dei microservizi - 3Questo è tutto ciò che serve per sviluppare un progetto di microservizi Java: basta creare e distribuire blocchi più piccoli (file .jar o .war) anziché uno monolitico. La risposta alla domanda rimane poco chiara: come dovremmo suddividere il monolite in microservizi? Quanto piccoli dovrebbero essere questi pezzi, come determinare la dimensione corretta? Controlliamo.

Architettura dei microservizi Java

In pratica, le aziende sviluppano progetti di microservizi in modi diversi. L'approccio dipende dal fatto che tu stia tentando di trasformare un monolite esistente in un progetto di microservizi o di avviare il progetto da zero.

Dal monolite ai microservizi

Una delle idee più logiche è estrarre microservizi da un monolite esistente. Si noti che il prefisso "micro" qui in realtà non significa che i servizi estratti saranno veramente piccoli; non è necessariamente così. Diamo un'occhiata al contesto teorico.

Idea: suddividere il monolite in microservizi

Un approccio basato sui microservizi può essere applicato ai progetti legacy. Ed ecco perché:
  1. Molto spesso, tali progetti sono difficili da mantenere/cambiare/espandere.
  2. Tutti, dagli sviluppatori al management, vogliono la semplificazione.
  3. Hai confini di dominio (relativamente) chiari, il che significa che sai esattamente cosa dovrebbe fare il tuo software.
Tornando al nostro esempio, ciò significa che puoi guardare il tuo monolite bancario Java e provare a scomporlo oltre i confini del dominio.
  • Sarebbe quindi ragionevole separare il trattamento dei dati degli utenti (come nomi, indirizzi, numeri di telefono) in un microservizio separato “Gestione account”.
  • Oppure il già citato "Modulo Risk Checker" che controlla i livelli di rischio dell'utente e può essere utilizzato da molti altri progetti o addirittura reparti dell'azienda.
  • Oppure un modulo di fatturazione che invia fatture in formato PDF o tramite posta.

Realizzazione di un'idea: lascia che lo faccia qualcun altro

L'approccio sopra descritto sembra ottimo su carta e diagrammi simili a UML. Tuttavia, tutto non è così semplice. La sua implementazione pratica richiede una seria preparazione tecnica: il divario tra la nostra comprensione di cosa sarebbe bello estrarre da un monolite e il processo di estrazione stesso è enorme. La maggior parte dei progetti aziendali raggiungono uno stadio in cui gli sviluppatori hanno paura, ad esempio, di aggiornare una versione di Hibernate vecchia di 7 anni a una più recente. Le biblioteche verranno aggiornate insieme ad esso, ma c'è il pericolo reale di rompere qualcosa. Quindi quegli stessi sviluppatori ora devono scavare nel vecchio codice legacy con confini delle transazioni del database poco chiari ed estrarre microservizi ben definiti? Nella maggior parte dei casi, questo problema è molto complesso e non può essere “risolto” su una lavagna o in riunioni di architettura. Una guida ai microservizi Java.  Parte 1: Nozioni di base e architettura dei microservizi - 4Per citare lo sviluppatore di Twitter @simonbrown: lo dirò ancora e ancora... se le persone non riescono a costruire correttamente i monoliti, i microservizi non saranno d'aiuto. Simone Marrone

Progetto da zero basato sull'architettura dei microservizi

Nel caso di nuovi progetti Java i tre punti numerati della parte precedente appaiono leggermente diversi:
  1. Inizi con una lavagna pulita, quindi non c'è nessun "bagaglio" da mantenere.
  2. Gli sviluppatori vorrebbero mantenere le cose semplici in futuro.
  3. Problema: hai un'immagine molto più confusa dei confini del dominio: non sai cosa dovrebbe effettivamente fare il tuo software (suggerimento: agile;))
Ciò sta portando le aziende a provare nuovi progetti con i microservizi Java.

Architettura tecnica dei microservizi

Il primo punto sembra essere il più ovvio per gli sviluppatori, ma c'è anche chi lo sconsiglia vivamente. Hadi Hariri consiglia il refactoring "Extract Microservice" in IntelliJ. E sebbene l'esempio seguente sia molto semplificato, le implementazioni osservate nei progetti reali, sfortunatamente, non si discostano troppo da esso. Prima dei microservizi
@Service
class UserService {

    public void register(User user) {
        String email = user.getEmail();
        String username =  email.substring(0, email.indexOf("@"));
        // ...
    }
}
Con microservizio Java sottostringa
@Service
class UserService {

    @Autowired
    private HttpClient client;

    public void register(User user) {
        String email = user.getEmail();
        //теперь вызываем substring microservice via http
        String username =  httpClient.send(substringRequest(email), responseHandler());
        // ...
    }
}
Quindi stai essenzialmente racchiudendo una chiamata al metodo Java in una chiamata HTTP, senza una ragione ovvia per farlo. Uno dei motivi, tuttavia, è questo: la mancanza di esperienza e il tentativo di forzare un approccio basato sui microservizi Java. Raccomandazione: non farlo.

Architettura di microservizi orientata al flusso di lavoro

Il prossimo approccio comune consiste nel dividere i microservizi Java in moduli basati sul flusso di lavoro. Esempio di vita reale: in Germania, quando vai da un medico (pubblico), lui deve registrare la tua visita nel suo sistema CRM medico. Per ottenere il pagamento dall'assicurazione, invierà i dati sul tuo trattamento (e sul trattamento di altri pazienti) all'intermediario tramite XML. Il broker esaminerà questo file XML e (semplificato):
  1. Verificherà se viene ricevuto il file XML corretto.
  2. Verificherà la plausibilità delle procedure: ad esempio, un bambino di un anno che ha ricevuto tre procedure di pulizia dei denti in un giorno da un ginecologo sembra alquanto sospettoso.
  3. Combinerà XML con alcuni altri dati burocratici.
  4. Inoltrerà il file XML alla compagnia assicurativa per avviare i pagamenti.
  5. E inoltrerà il risultato al medico, fornendogli il messaggio “successo” o “si prega di inviare nuovamente questa registrazione non appena avrà senso”.
Nota. In questo esempio la comunicazione tra microservizi non ha alcun ruolo, ma potrebbe essere effettuata in modo asincrono da un broker di messaggi (ad es. RabbitMQ), poiché il medico non riceve comunque un feedback immediato. Una guida ai microservizi Java.  Parte 1: Nozioni di base e architettura dei microservizi - 5Ancora una volta, questo sembra fantastico sulla carta, ma sorgono domande naturali:
  • È necessario distribuire sei applicazioni per elaborare un file XML?
  • Questi microservizi sono davvero indipendenti l’uno dall’altro? Possono essere schierati indipendentemente l'uno dall'altro? Con versioni e schemi API diversi?
  • Cosa fa il microservizio di plausibilità delle informazioni se il microservizio di verifica non funziona? Il sistema funziona ancora?
  • Questi microservizi condividono lo stesso database (hanno sicuramente bisogno di alcuni dati comuni nelle tabelle DB) o ciascuno di essi ha il proprio?
  • … e altro ancora.
È interessante notare che il diagramma sopra sembra più semplice perché ogni servizio ora ha il suo scopo preciso e ben definito. Un tempo somigliava a questo spaventoso monolite: Una guida ai microservizi Java.  Parte 1: Nozioni di base e architettura dei microservizi - 6anche se puoi discutere sulla semplicità di questi diagrammi, ora devi sicuramente risolvere queste ulteriori sfide operative.
  • Non è necessario distribuire solo un'applicazione, ma almeno sei.
  • Potrebbe anche essere necessario distribuire più database, a seconda di quanto si desidera approfondire l'architettura dei microservizi.
  • È necessario assicurarsi che ciascun sistema sia online e funzioni correttamente.
  • È necessario assicurarsi che le chiamate tra i microservizi siano veramente resilienti (vedere Come rendere resiliente un microservizio Java?).
  • E tutto ciò che questa configurazione implica, dalle impostazioni di sviluppo locale ai test di integrazione.
Quindi la raccomandazione sarebbe:
  • Se non sei Netflix (è probabile che non sei Netflix)...
  • A meno che tu non abbia capacità lavorative molto forti in cui apri l'ambiente di sviluppo e ciò provoca una scimmia del caos che butta via il tuo database di produzione che viene facilmente ripristinato in 5 secondi.
  • oppure ti senti come @monzo e sei disposto a provare 1500 microservizi solo perché puoi.
→ Non farlo. E ora è meno iperbolico. Cercare di modellare i microservizi oltre i confini del dominio sembra abbastanza ragionevole. Ma questo non significa che devi prendere un flusso di lavoro e dividerlo in piccole parti individuali (ricevere XML, convalidare XML, inoltrare XML). Pertanto, ogni volta che inizi un nuovo progetto con microservizi Java e i confini del dominio sono ancora molto vaghi, cerca di mantenere la dimensione dei tuoi microservizi a un livello basso. Puoi sempre aggiungere più moduli in seguito. E assicurati di disporre di DevOps avanzati nel team/azienda/divisione per supportare la tua nuova infrastruttura.

Architettura di microservizi poliglotta o orientata al team

Esiste un terzo approccio, quasi libertario, allo sviluppo di microservizi: consentire a team o anche singoli individui di implementare storie di utenti utilizzando un numero qualsiasi di linguaggi o microservizi (gli esperti di marketing chiamano questo approccio “programmazione poliglotta”). Pertanto, il servizio di validazione XML sopra descritto potrebbe essere scritto in Java, mentre il microservizio di validazione allo stesso tempo potrebbe essere scritto in Haskell (per renderlo matematicamente valido). Per il microservizio di inoltro assicurativo, puoi utilizzare Erlang (perché ha davvero bisogno di essere scalato ;)). Ciò che può sembrare divertente dal punto di vista di uno sviluppatore (sviluppare il sistema perfetto con il proprio linguaggio perfetto in un ambiente isolato) non è, infatti, mai ciò che l'organizzazione desidera: omogeneizzazione e standardizzazione. Ciò significa un insieme relativamente standardizzato di linguaggi, librerie e strumenti in modo che altri sviluppatori possano continuare a supportare il tuo microservizio Haskell in futuro quando passerai a pascoli più verdi. Una guida ai microservizi Java.  Parte 1: Nozioni di base e architettura dei microservizi - 8La storia dimostra che la standardizzazione di solito diventa troppo radicata. Ad esempio, agli sviluppatori delle grandi aziende Fortune 500 a volte non era nemmeno consentito utilizzare Spring perché "non faceva parte della roadmap tecnologica dell'azienda". Tuttavia, una transizione completa all’approccio poliglotta è quasi la stessa cosa, l’altra faccia della stessa medaglia. Raccomandazione: se intendi utilizzare la programmazione poliglotta, prova meno varietà all'interno dello stesso ecosistema di linguaggi di programmazione. Quindi è meglio usare Kotlin e Java insieme (entrambi i linguaggi sono basati sulla JVM e sono compatibili tra loro al 100%) piuttosto che Java e, ad esempio, Haskell. Nella parte successiva imparerai come distribuire e testare i microservizi Java.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION