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?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:
- Confermato il modulo di registrazione.
- Controlla i rischi dell'indirizzo dell'utente per decidere se fornirgli un conto bancario.
- Ha aperto un conto bancario.
BankController
verrà 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. Immagine, 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...
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 metodoriskCheck()
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?
- Chiamiamo microservizi tutti i servizi distribuiti separatamente, indipendentemente dalle loro dimensioni o dai limiti del dominio.
- Pensiamo a come organizzare la comunicazione tra servizi. I nostri microservizi necessitano di modi per comunicare tra loro.
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. Questo è 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é:- Molto spesso, tali progetti sono difficili da mantenere/cambiare/espandere.
- Tutti, dagli sviluppatori al management, vogliono la semplificazione.
- Hai confini di dominio (relativamente) chiari, il che significa che sai esattamente cosa dovrebbe fare il tuo software.
- 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. Per 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 MarroneProgetto da zero basato sull'architettura dei microservizi
Nel caso di nuovi progetti Java i tre punti numerati della parte precedente appaiono leggermente diversi:- Inizi con una lavagna pulita, quindi non c'è nessun "bagaglio" da mantenere.
- Gli sviluppatori vorrebbero mantenere le cose semplici in futuro.
- Problema: hai un'immagine molto più confusa dei confini del dominio: non sai cosa dovrebbe effettivamente fare il tuo software (suggerimento: agile;))
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):- Verificherà se viene ricevuto il file XML corretto.
- 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.
- Combinerà XML con alcuni altri dati burocratici.
- Inoltrerà il file XML alla compagnia assicurativa per avviare i pagamenti.
- E inoltrerà il risultato al medico, fornendogli il messaggio “successo” o “si prega di inviare nuovamente questa registrazione non appena avrà senso”.
- È 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.
- 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.
- 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.
GO TO FULL VERSION