En esta guía, aprenderá qué son los microservicios Java, cómo diseñarlos y crearlos. También cubre preguntas sobre las bibliotecas de microservicios de Java y la viabilidad de utilizar microservicios. Traducción y adaptación de microservicios Java: una guía práctica .
Microservicios Java: conceptos básicos
Para comprender los microservicios, primero hay que definir qué no son. ¿No es un "monolito"? Monolito de Java: ¿qué es y cuáles son sus ventajas o desventajas?¿Qué es un monolito de Java?
Imagina que trabajas para un banco o una startup de tecnología financiera. Proporciona a los usuarios una aplicación móvil que pueden utilizar para abrir una nueva cuenta bancaria. En el código Java esto dará como resultado la presencia de una clase de controlador. Simplificado, se ve así:@Controller
class BankController {
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
riskCheck(form);
openBankAccount(form);
// etc..
}
}
Necesitas el controlador para:
- Confirmado el formulario de registro.
- Comprobó los riesgos de la dirección del usuario para decidir si le proporciona una cuenta bancaria.
- Abrió una cuenta bancaria.
BankController
se empaquetará junto con el resto de sus fuentes en un archivo bank.jar o bank.war para su implementación; este es un buen monolito que contiene todo el código necesario para ejecutar su banco. Como estimación aproximada, el tamaño inicial de un archivo .jar (o .war) oscilará entre 1 y 100 MB. Ahora simplemente puede ejecutar el archivo .jar en su servidor... y eso es todo lo que necesita hacer para implementar su aplicación Java. Imagen, rectángulo superior izquierdo: implementación de un banco mono(lítico) java -jar bank.jar (cp .war/.ear en el servidor de aplicaciones). Rectángulo derecho: abrir navegador.
¿Cuál es el problema con los monolitos de Java?
No hay nada inherentemente malo en los monolitos de Java. Sin embargo, la experiencia ha demostrado que si en su proyecto:- Hay muchos programadores/equipos/consultores trabajando...
- ...sobre el mismo monolito bajo la presión de clientes con requisitos muy vagos...
- dentro de un par de años...
¿Cómo reducir el tamaño de un monolito de Java?
Surge una pregunta natural: ¿cómo hacer que el monolito sea más pequeño? En este momento, su bank.jar se está ejecutando en una JVM, un proceso en un servidor. Ni mas ni menos. Y en este momento puede venir a la mente un pensamiento lógico: “¡Pero el servicio de verificación de riesgos puede ser utilizado por otros departamentos de mi empresa! ¡No está directamente relacionado con mi aplicación bancaria monolítica! ¿Quizás debería cortarse del monolito e implementarse como un producto separado? Es decir, técnicamente hablando, ejecutarlo como un proceso Java separado”.¿Qué es un microservicio Java?
En la práctica, esta frase significa que ahora la llamada al métodoriskCheck()
no se realizará desde BankController: este método o componente bean con todas sus clases auxiliares se moverá a su propio proyecto Maven o Gradle. También se implementará y se colocará bajo control de versiones independientemente del monolito bancario. Sin embargo, todo este proceso de extracción no convierte su nuevo módulo RiskCheck en un microservicio per se, ya que la definición de microservicio está abierta a interpretación. Esto conduce a discusiones frecuentes dentro de los equipos y empresas.
- ¿Son 5-7 clases en un micro proyecto o qué?
- 100 o 1000 clases... ¿todavía micro?
- ¿El microservicio generalmente está relacionado con la cantidad de clases o no?
- Llamemos microservicios a todos los servicios implementados por separado, independientemente de su tamaño o límites de dominio.
- Pensemos en cómo organizar la comunicación entre servicios. Nuestros microservicios necesitan formas de comunicarse entre sí.
¿Cómo establecer comunicación entre microservicios Java?
En general, hay dos opciones: comunicación síncrona y asíncrona.Comunicación síncrona: (HTTP)/REST
Normalmente, la comunicación sincronizada entre microservicios se produce a través de HTTP y servicios tipo REST que devuelven XML o JSON. Por supuesto, puede haber otras opciones: tome al menos Google Protocol Buffers . Si necesita una respuesta inmediata, es mejor utilizar la comunicación REST. En nuestro ejemplo, esto es exactamente lo que hay que hacer, ya que se requiere verificación de riesgos antes de abrir una cuenta. Si no hay verificación de riesgos, no hay cuenta. Discutiremos las herramientas a continuación, en la sección " Qué bibliotecas son mejores para llamadas REST Java sincrónicas ".Mensajería: comunicación asincrónica
La comunicación de microservicio asincrónica generalmente se logra intercambiando mensajes con una implementación JMS y/o usando un protocolo como AMQP . Escribimos "normalmente" aquí por una razón: digamos que no se puede subestimar la cantidad de integraciones de correo electrónico/SMTP. Úselo cuando no necesite una respuesta inmediata. Por ejemplo, el usuario hace clic en el botón "comprar ahora" y usted, a su vez, desea generar una factura. Este proceso ciertamente no debería ocurrir dentro del ciclo de solicitud-respuesta de compra del usuario. A continuación describiremos qué herramientas son mejores para la mensajería Java asincrónica .Ejemplo: llamada a la API REST en Java
Supongamos que elegimos la comunicación de microservicio sincrónica. En este caso, nuestro código Java (el que presentamos arriba) en un nivel bajo se verá así. (Aquí por nivel bajo nos referimos al hecho de que para la comunicación de microservicios, generalmente se crean bibliotecas cliente que lo abstraen de las llamadas HTTP reales).@Controller
class BankController {
@Autowired
private HttpClient httpClient;
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
httpClient.send(riskRequest, responseHandler());
setupAccount(form);
// etc..
}
}
Según el código, queda claro que ahora necesitamos implementar dos (micro)servicios Java, Bank y RiskCheck. Como resultado, tendremos dos procesos JVM ejecutándose. Eso es todo lo que necesita para desarrollar un proyecto de microservicios Java: simplemente cree e implemente fragmentos más pequeños (archivos .jar o .war) en lugar de uno monolítico. La respuesta a la pregunta aún no está clara: ¿cómo deberíamos dividir el monolito en microservicios? ¿Qué tan pequeñas deben ser estas piezas? ¿Cómo determinar el tamaño correcto? Vamos a revisar.
Arquitectura de microservicios Java
En la práctica, las empresas desarrollan proyectos de microservicios de diferentes formas. El enfoque depende de si está intentando transformar un monolito existente en un proyecto de microservicios o comenzar el proyecto desde cero.Del monolito a los microservicios
Una de las ideas más lógicas es extraer microservicios de un monolito existente. Tenga en cuenta que el prefijo "micro" aquí no significa en realidad que los servicios extraídos serán realmente pequeños; este no es necesariamente el caso. Veamos los antecedentes teóricos.Idea: dividir el monolito en microservicios
Se puede aplicar un enfoque de microservicio a proyectos heredados. Y es por eso:- En la mayoría de los casos, estos proyectos son difíciles de mantener, cambiar o ampliar.
- Todo el mundo, desde los desarrolladores hasta la dirección, quiere simplificación.
- Tiene límites de dominio (relativamente) claros, lo que significa que sabe exactamente qué debe hacer su software.
- Por lo tanto, sería razonable separar el procesamiento de los datos del usuario (como nombres, direcciones, números de teléfono) en un microservicio separado, "Administración de cuentas".
- O el ya mencionado "Risk Checker Module" que comprueba los niveles de riesgo del usuario y puede ser utilizado por muchos otros proyectos o incluso departamentos de la empresa.
- O un módulo de facturación que envía facturas en formato PDF o por correo.
Implementación de una idea: dejar que otro lo haga
El enfoque descrito anteriormente se ve muy bien en papel y en diagramas tipo UML. Sin embargo, no todo es tan sencillo. Su implementación práctica requiere una preparación técnica seria: la brecha entre nuestra comprensión de lo que sería bueno extraer de un monolito y el proceso de extracción en sí es enorme. La mayoría de los proyectos empresariales llegan a una etapa en la que los desarrolladores tienen miedo de, por ejemplo, actualizar una versión de Hibernate de hace siete años a una más nueva. Las bibliotecas se actualizarán junto con él, pero existe un peligro real de que algo se rompa. Entonces, ¿esos mismos desarrolladores ahora tienen que profundizar en códigos antiguos con límites de transacciones de bases de datos poco claros y extraer microservicios bien definidos? La mayoría de las veces, este problema es muy complejo y no se puede “resolver” en una pizarra o en reuniones de arquitectura. Para citar al desarrollador de Twitter @simonbrown: Diré esto una y otra vez... si las personas no pueden construir monolitos correctamente, los microservicios no ayudarán. Simón BrownProyecto desde cero basado en arquitectura de microservicios
En el caso de nuevos proyectos Java, los tres puntos numerados de la parte anterior lucen ligeramente diferentes:- Se empieza desde cero, por lo que no hay “equipaje” que mantener.
- A los desarrolladores les gustaría mantener las cosas simples en el futuro.
- Problema: tienes una imagen mucho más confusa de los límites del dominio: no sabes qué se supone que debe hacer tu software (pista: ágil;))
Arquitectura técnica de microservicios
El primer punto parece ser el más obvio para los desarrolladores, pero también hay quienes lo desaconsejan rotundamente. Hadi Hariri recomienda la refactorización "Extract Microservice" en IntelliJ. Y aunque el siguiente ejemplo es muy simplificado, las implementaciones observadas en proyectos reales, lamentablemente, no se alejan demasiado de ello. Antes de los microservicios@Service
class UserService {
public void register(User user) {
String email = user.getEmail();
String username = email.substring(0, email.indexOf("@"));
// ...
}
}
Con microservicio Java de subcadena
@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());
// ...
}
}
Entonces, básicamente estás envolviendo una llamada a un método Java en una llamada HTTP, sin ninguna razón obvia para hacerlo. Sin embargo, una de las razones es esta: falta de experiencia y el intento de forzar un enfoque de microservicios Java. Recomendación: no hagas esto.
Arquitectura de microservicios orientada al flujo de trabajo
El siguiente enfoque común es dividir los microservicios Java en módulos basados en flujos de trabajo. Ejemplo de la vida real: en Alemania, cuando vas a un médico (público), él debe registrar tu visita en su sistema CRM médico. Para recibir el pago del seguro, enviará datos sobre su tratamiento (y el tratamiento de otros pacientes) al intermediario a través de XML. El corredor mirará este archivo XML y (simplificado):- Comprobará si se recibe el archivo XML correcto.
- Se comprobará la verosimilitud de los procedimientos: por ejemplo, un niño de un año al que un ginecólogo le realizó tres limpiezas dentales en un día parece algo sospechoso.
- Combinará XML con algunos otros datos burocráticos.
- Enviará el archivo XML a la compañía de seguros para iniciar los pagos.
- Y enviará el resultado al médico proporcionándole el mensaje “éxito” o “por favor reenvíe esta grabación tan pronto como tenga sentido”.
- ¿Es necesario implementar seis aplicaciones para procesar un archivo XML?
- ¿Son estos microservicios realmente independientes entre sí? ¿Se pueden implementar independientemente unos de otros? ¿Con diferentes versiones y esquemas API?
- ¿Qué hace el microservicio de plausibilidad de la información si el microservicio de verificación no funciona? ¿El sistema sigue funcionando?
- ¿Estos microservicios comparten la misma base de datos (ciertamente necesitan algunos datos comunes en las tablas de la base de datos) o cada uno tiene la suya propia?
- … y mucho más.
- No sólo necesita implementar una aplicación, sino al menos seis.
- Es posible que incluso necesite implementar varias bases de datos, dependiendo de hasta dónde desee llegar en la arquitectura de microservicios.
- Debe asegurarse de que cada sistema esté en línea y funcione correctamente.
- Debe asegurarse de que sus llamadas entre microservicios sean realmente resistentes (consulte ¿Cómo hacer que un microservicio Java sea resistente?).
- Y todo lo demás que implica esta configuración, desde entornos de desarrollo local hasta pruebas de integración.
- Si no eres Netflix (lo más probable es que no seas Netflix)...
- A menos que tengas habilidades laborales súper sólidas en las que abres el entorno de desarrollo y eso provoca un caos que desecha tu base de datos de producción, que se restaura fácilmente en 5 segundos.
- o te sientes como @monzo y estás dispuesto a probar 1500 microservicios sólo porque puedes.
GO TO FULL VERSION