JavaRush /Blog Java /Random-ES /Una guía para los microservicios de Java. Parte 1: Concep...

Una guía para los microservicios de Java. Parte 1: Conceptos básicos y arquitectura de los microservicios

Publicado en el grupo Random-ES
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? Una guía para los microservicios de Java.  Parte 1: Conceptos básicos y arquitectura de microservicios - 1

¿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:
  1. Confirmado el formulario de registro.
  2. Comprobó los riesgos de la dirección del usuario para decidir si le proporciona una cuenta bancaria.
  3. Abrió una cuenta bancaria.
La clase BankControllerse 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. Una guía para los microservicios de Java.  Parte 1: Conceptos básicos y arquitectura de microservicios - 2Imagen, 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...
... entonces, en este caso, su pequeño archivo bank.jar se convierte en un inmenso gigabyte de código, algo que da miedo incluso abordar, y mucho menos implementar.

¿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étodo riskCheck()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?
Dejemos atrás el razonamiento teórico y, en cambio, nos atengamos a consideraciones pragmáticas y hagamos esto:
  1. Llamemos microservicios a todos los servicios implementados por separado, independientemente de su tamaño o límites de dominio.
  2. Pensemos en cómo organizar la comunicación entre servicios. Nuestros microservicios necesitan formas de comunicarse entre sí.
Entonces, para resumir: anteriormente tenías un proceso JVM, un monolito sólido para administrar el banco. Ahora tiene un proceso JVM monolítico bancario y un microservicio RiskCheck independiente que se ejecuta dentro de su propio proceso JVM. Y ahora, para comprobar los riesgos, su monolito debe llamar a este microservicio. ¿Como hacer esto?

¿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. Una guía para los microservicios de Java.  Parte 1: Conceptos básicos y arquitectura de microservicios - 3Eso 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:
  1. En la mayoría de los casos, estos proyectos son difíciles de mantener, cambiar o ampliar.
  2. Todo el mundo, desde los desarrolladores hasta la dirección, quiere simplificación.
  3. Tiene límites de dominio (relativamente) claros, lo que significa que sabe exactamente qué debe hacer su software.
Volviendo a nuestro ejemplo, esto significa que puede observar su monolito bancario Java e intentar dividirlo a través de los límites del dominio.
  • 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. Una guía para los microservicios de Java.  Parte 1: Conceptos básicos y arquitectura de microservicios - 4Para 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 Brown

Proyecto 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:
  1. Se empieza desde cero, por lo que no hay “equipaje” que mantener.
  2. A los desarrolladores les gustaría mantener las cosas simples en el futuro.
  3. 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;))
Esto está llevando a las empresas a probar nuevos proyectos con microservicios Java.

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):
  1. Comprobará si se recibe el archivo XML correcto.
  2. 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.
  3. Combinará XML con algunos otros datos burocráticos.
  4. Enviará el archivo XML a la compañía de seguros para iniciar los pagos.
  5. 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”.
Nota. En este ejemplo, la comunicación entre microservicios no juega ningún papel, pero bien podría realizarse de forma asincrónica mediante un intermediario de mensajes (por ejemplo, RabbitMQ), ya que de todos modos el médico no recibe comentarios inmediatos. Una guía para los microservicios de Java.  Parte 1: Conceptos básicos y arquitectura de microservicios - 5Una vez más, esto parece muy bien sobre el papel, pero naturalmente surgen preguntas:
  • ¿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.
Curiosamente, el diagrama anterior parece más simple porque ahora cada servicio tiene su propio propósito preciso y bien definido. Solía ​​parecerse a este aterrador monolito: Una guía para los microservicios de Java.  Parte 1: Conceptos básicos y arquitectura de microservicios - 6si bien se puede discutir sobre la simplicidad de estos diagramas, ahora definitivamente es necesario resolver estos desafíos operativos adicionales.
  • 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.
Entonces la recomendación sería:
  • 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.
→ No hagas esto. Y ahora es menos hiperbólico. Intentar modelar microservicios a través de los límites de los dominios parece bastante razonable. Pero esto no significa que deba tomar un flujo de trabajo y dividirlo en pequeñas partes individuales (recibir XML, validar XML, reenviar XML). Por lo tanto, siempre que inicie un nuevo proyecto con microservicios Java y los límites del dominio aún sean muy vagos, intente mantener el tamaño de sus microservicios en un nivel bajo. Siempre puedes agregar más módulos más adelante. Y asegúrese de tener DevOps avanzado en el equipo/empresa/división para respaldar su nueva infraestructura.

Arquitectura de microservicio políglota o orientada a equipos

Existe un tercer enfoque, casi libertario, para desarrollar microservicios: permitir que equipos o incluso individuos implementen historias de usuarios utilizando cualquier cantidad de lenguajes o microservicios (los especialistas en marketing llaman a este enfoque “programación políglota”). Por lo tanto, el servicio de validación XML descrito anteriormente podría escribirse en Java, mientras que el microservicio de validación podría escribirse al mismo tiempo en Haskell (para que sea matemáticamente sólido). Para el microservicio de reenvío de seguros, puede usar Erlang (porque realmente necesita escalar;)). Lo que puede parecer divertido desde el punto de vista de un desarrollador (desarrollar el sistema perfecto con el lenguaje perfecto en un entorno aislado) en realidad nunca es lo que la organización quiere: homogeneización y estandarización. Esto significa un conjunto relativamente estandarizado de lenguajes, bibliotecas y herramientas para que otros desarrolladores puedan continuar brindando soporte a su microservicio Haskell en el futuro cuando avance hacia pastos más verdes. Una guía para los microservicios de Java.  Parte 1: Conceptos básicos y arquitectura de microservicios - 8La historia muestra que la estandarización suele estar demasiado arraigada. Por ejemplo, a los desarrolladores de grandes empresas Fortune 500 a veces ni siquiera se les permitía usar Spring porque "no formaba parte de la hoja de ruta tecnológica de la empresa". Sin embargo, una transición completa al enfoque políglota es casi lo mismo, la otra cara de la misma moneda. Recomendación: Si vas a utilizar programación políglota, prueba con menos variedad dentro del mismo ecosistema de lenguajes de programación. Por lo tanto, es mejor usar Kotlin y Java juntos (ambos lenguajes se basan en JVM y son 100% compatibles entre sí), en lugar de Java y, digamos, Haskell. En la siguiente parte, aprenderá cómo implementar y probar microservicios Java.
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION