Beruflich Dokumente
Kultur Dokumente
INTEGRANTES:
Chapa Carranza Kathiuska
Lara Soto Jhonatan
López Zapata Francisco
Reyes Avalos Deivy
Valverde Solís Abraham
DOCENTE:
Mg. Camilo Suarez Rebaza
CICLO: IX
NUEVO CHIMBOTE – PERÚ
2019
Microservicios Reactivos en JAVA 1
Universidad Nacional Del Santa
Ing. Sistemas e Informática
Contenido
1 ENTENDIENDO LOS MICROSERVICIOS REACTIVOS Y VERT.X ...................... 2
1.1 Programación reactiva ............................................................................................. 2
1.2 RXJAVA2 ................................................................................................................ 4
1.3 Flujos reactivos ........................................................................................................ 5
1.4 Sistemas reactivos .................................................................................................... 5
1.5 Microservicios reactivos .......................................................................................... 6
1.6 Modelo de desarrollo asíncrono ............................................................................... 7
1.7 Vértices: los Building Blocks .................................................................................. 9
1.8 De devoluciones de llamada a observables ............................................................ 10
2 CONSTRUCCIÓN DE MICROSERVICIOS REACTIVOS....................................... 17
2.1. .................................................................................................................................... 17
2.2. .................................................................................................................................... 18
2.3. .................................................................................................................................... 22
2.4. .................................................................................... Error! Bookmark not defined.
2.5. El bus de eventos Vert.x: una red troncal de mensajería ........................................... 27
2.6. Microservicios basados en mensajes ......................................................................... 28
2.6.1. Creación de proyectos ........................................................................................ 28
2.6.2. Escribir el artículo dirigido por el mensaje .................................................... 28
2.7. Iniciar interacciones basadas en mensajes ................................................................. 29
2.8. ¿Somos reactivos ahora? ............................................................................................ 32
2.8.1. Elasticidad .......................................................................................................... 32
2.8.2. Resistencia .......................................................................................................... 32
3 CONSTRUCCIÓN DE SISTEMAS DE MICROSERVICIOS REACTIVOS. ........... 34
3.1 Descubrimiento de servicios .................................................................................. 34
3.1.1. Descubrimiento de servicios del lado del cliente y del servidor .................... 35
3.1.3. Descubrimiento de servicios Vert.x.................................................................... 36
3.2 Patrones de Estabilidad y Resiliencia .................................................................... 38
3.2.1 Gestión de Fallos en Microservicios Reactivos .............................................. 39
3.2.2 Usando tiempos de espera .............................................................................. 40
3.2.3 Rompedores de circuito .................................................................................. 42
3.2.4 Controles de Salud y de Conmutación por error ............................................ 44
CONSTRUCCIÓN DE MICROSERVICIOS
REACTIVOS EN JAVA
el flujo de cálculo no está controlado por el programador, sino por los estímulos. En este
capítulo, veremos cómo Vert.x lo ayuda a ser reactivo al combinar:
Programación reactiva: un modelo de desarrollo que se enfoca en la observación de flujos de
datos, reacciona a los cambios y los propaga.
Para que estos conceptos sean menos abstractos, veamos un ejemplo utilizando RxJava
(https://github.com/ReactiveX/RxJava), una biblioteca que implementa las
Extensiones reactivas en Java.
Los observables son flujos limitados o ilimitados que se espera que contengan
una secuencia de valores.
Los solteros son flujos con un solo valor, generalmente el resultado diferido de
una operación, similar a los futuros o promesas.
Los complementos son flujos sin valor, pero con una indicación de si una
operación se completó o falló.
1.2 RXJAVA2
Si bien RxJava 2.x se ha lanzado recientemente, este informe aún utiliza la versión
anterior (RxJava 1.x). RxJava 2 introdujo el tipo Maybe, que modela una secuencia en
la que podría haber 0 o 1 elemento o un error.
¿Qué podemos hacer con RxJava? Por ejemplo, podemos describir secuencias de
acciones asíncronas y organizarlas. Imaginemos que desea descargar un documento,
procesarlo y cargarlo. Las operaciones de descarga y carga son asíncronas. Para
desarrollar esta secuencia, usas algo como:
También puede orquestar tareas asíncronas. Por ejemplo, para combinar los resultados
de dos operaciones asíncronas, utiliza el operador zip que combina valores de
diferentes flujos
El uso de estos operadores le brinda superpoderes: puede coordinar tareas asíncronas
y flujo de datos de manera declarativa y elegante. ¿Cómo se relaciona esto con los
microservicios reactivos? Para responder a esta pregunta, echemos un vistazo a los
sistemas reactivos.
ejecuta con cada solicitud entrante. Tenga en cuenta que un controlador no devuelve
un resultado. Sin embargo, un controlador puede proporcionar un resultado.
Con muy pocas excepciones, ninguna de las API en Vert.x bloquea el subproceso de
llamada. Si un resultado puede ser proporcionado inmediatamente, será devuelto; de lo
contrario, un controlador se utiliza para recibir eventos en un momento posterior. Se
notifica al controlador cuando un evento está listo para ser procesado o cuando se ha
calculado el resultado de una operación asíncrona.
En la programación imperativa tradicional, escribirías algo como:
Debido a que nada bloquea, un bucle de eventos puede entregar una gran cantidad de
eventos en un corto período de tiempo. Esto se llama el patrón del reactor Imaginemos,
por un momento, que rompes la regla. En el fragmento de código anterior, el
controlador de solicitudes siempre se llama desde el mismo bucle de eventos. Por lo
tanto, si el procesamiento de solicitudes HTTP bloquea en lugar de responder al usuario
Verticle de trabajo
A diferencia de las verticles normales, las verticles de trabajo no se ejecutan en el bucle
de eventos, lo que significa que pueden ejecutar código de bloqueo. Sin embargo, esto
limita su escalabilidad.
Los vértices tienen acceso al miembro vertx (proporcionado por la clase
AbstractVerticle) para crear servidores y clientes e interactuar con los otros verticles.
Los vértices también pueden implementar otros verticles, configurarlos y establecer el
número de instancias para crear. Las instancias están asociadas con los diferentes
bucles de eventos (implementando el patrón de multirreactor), y Vert.x equilibra la
carga entre estas instancias.
Aunque aún es manejable, el ejemplo muestra que las devoluciones de llamada pueden
conducir rápidamente a código ilegible. También puede usar Vert.x Futures para
manejar acciones asíncronas. A diferencia de los futuros de Java, los futuros de Vert.x
no están bloqueados. Los futuros proporcionan operadores de composición de nivel
superior para construir secuencias de acciones o para ejecutar acciones en paralelo.
Normalmente, como se demuestra en el siguiente fragmento de código, componemos
futuros para construir la secuencia de acciones asíncronas:
Sin embargo, aunque los futuros hacen que el código sea un poco más declarativo,
estamos recuperando todas las filas en un lote y procesándolas. Este resultado puede
ser enorme y llevar mucho tiempo recuperarlo. Al mismo tiempo, no necesita todo el
resultado para comenzar a procesarlo. Podemos procesar cada fila una por una tan
pronto como las tengas. Afortunadamente, Vert.x proporciona una respuesta a este
desafío de modelo de desarrollo y le ofrece una manera de implementar microservicios
reactivos utilizando un modelo de desarrollo de programación reactiva. Vert.x
proporciona las API de RxJava para:
• Combinar y coordinar tareas asíncronas
• Reaccionar a los mensajes entrantes como un flujo de entrada Reescribamos el
código anterior utilizando las API de RxJava:
Creación de proyectos
Cree un directorio llamado my-first-vertx-app y avance a este directorio:
Este comando genera la estructura del proyecto Maven, configura el plugin vertx-
maven-plugin y crea una clase de vertículo (io.vertx.sam ple.MyFirstVerticle), que no
hace nada.
Escribe tu primer vertículo
Ahora es el momento de escribir el código para su primer vértice. Modifique el archivo
src / main / java / io / vertx / sample / MyFirstVerticle.java con el siguiente contenido:
Si todo salió bien, debería poder ver su aplicación abriendo http: // localhost: 8080 en
un navegador. El objetivo vertx: run inicia la aplicación Vert.x y también observa las
alteraciones del código. Entonces, si edita el código fuente, la aplicación se recompilará
y reiniciará automáticamente.
La solicitud ha sido procesada por el bucle de eventos 0. Puede intentar emitir más
solicitudes. Las solicitudes siempre serán procesadas por el mismo bucle de eventos,
aplicando el modelo de concurrencia de Vert.x. Presiona Ctrl + C para detener la
ejecución.
Usando RxJava
En este punto, echemos un vistazo al soporte RxJava proporcionado por Vert.x para
comprender mejor cómo funciona. En su archivo pom.xml, agregue la siguiente
dependencia:
Las variantes RxJava de las API Vert.x se proporcionan en paquetes con rxjava en su
nombre. Los métodos RxJava tienen el prefijo rx, como rxListen. Además, las API se
mejoran con métodos que proporcionan objetos Observables en los que puede
suscribirse para recibir los datos transmitidos.
En este informe, usaremos frascos gruesos, es decir, JAR autónomos que incorporen el
código de la aplicación, sus recursos y todas sus dependencias. Esto incluye Vert.x, los
componentes Vert.x que está utilizando y sus dependencias. Este modelo de empaque
utiliza un mecanismo de cargador de clase plana, lo que facilita la comprensión del
inicio de la aplicación, el pedido de dependencias y los registros. Más importante aún,
ayuda a reducir la cantidad de piezas móviles que deben instalarse en la producción.
No implemente una aplicación en un servidor de aplicaciones existente. Una vez que
está empaquetado en su frasco gordo, la aplicación está lista para ejecutarse con un
simple java -jar <name.jar>. El complemento Vert.x Maven crea un tarro gordo para
usted, pero también puede usar otro complemento Maven como el complemento
maven-shader.
No se preocupe: Vert.x ofrece todas estas funciones. Y debido a que Vert.x es neutral,
ofrece varias alternativas, permitiéndole elegir o implementar la suya. Por ejemplo,
para el registro, Vert.x no aplica un marco de registro específico, sino que le permite
utilizar el marco de registro que desee, como Apache Log4J 1 o 2, SLF4J o incluso
JUL (la API de registro JDK). Si está interesado en los mensajes registrados por Vert.x,
el registro interno de Vert.x se puede configurar para usar cualquiera de estos marcos
de registro. La supervisión de las aplicaciones Vert.x generalmente se realiza mediante
JMX. El módulo Métrico Vert.x Dropwizard proporciona métricas Vert.x a JMX.
También puede optar por publicar estas métricas en un servidor de monitoreo como
Prometheus (https://prometheus.io/) o CloudForms (https://www.redhat.com/en/
technologies / management / cloudforms).
En el capítuloe anterior,
interacciones basadas
vimos en mensajes
dos formas diferentes de usar las API de Vert.x:
devoluciones de llamada y RxJava. Para ilustrar las diferencias y ayudarlo a encontrar
su enfoque preferido, los microservicios hola se implementan utilizando el modelo de
desarrollo basado en devolución de llamada, mientras que los consumidores se
implementan utilizando RxJava.
Empezando
Cree un directorio llamado hello-microservice-http y luego genere la estructura del
proyecto:
El verticle
Abra src / main / java / io / vertx / book / http / HelloMicroser vice.java. El código
generado del vértice no hace nada muy interesante, pero es un punto de partida:
Ahora puede editar la vertical. Cada vez que guarde el archivo, la aplicación se
recompilará y reiniciará automáticamente.
Microservicio HTTP
Es hora de hacer que nuestra clase MyVerticle haga algo. Comencemos con un servidor
HTTP. Como se vio en el capítulo anterior, para crear un servidor HTTP con Vert.x
solo usa:
Una vez agregado y guardado, debería poder ver hola en http: // localhost: 8080 en un
navegador. Este código crea un servidor HTTP onport 8080 y registra un
requestHandler que se invoca en cada solicitud HTTP entrante. Por ahora, solo
escribimos hola en la respuesta.
Una vez que hemos creado el objeto Router, registramos dos rutas. El primero maneja
las solicitudes en / y solo escribe hola. La segunda ruta tiene un parámetro de ruta (:
nombre). El controlador agrega el valor pasado al mensaje de saludo. Finalmente,
cambiamos el requestHandler del servidor HTTP para usar el método accept del
enrutador.
Si no detuvo la ejecución de vertx: run, debería poder abrir un navegador para:
Produciendo JSON
JSON se usa a menudo en microservicios. Modifiquemos la clase anterior para producir
cargas JSON:
Vert.x proporciona una clase JsonObject para crear y manipular estructuras JSON. Con
este código, debe poder abrir un navegador para:
Packaging y funcionamiento
Detenga el vertx: ejecute la ejecución usando Ctrl + C y ejecute el siguiente comando
desde el mismo directorio:
Puede verificar si se está ejecutando abriendo: http: // host local: 8080. Mantenga el
proceso en ejecución ya que el próximo microservicio lo invocará.
Creación de proyectos
Como de costumbre, vamos a crear un nuevo proyecto:
El último comando agrega otra dependencia: el cliente web Vert.x, un cliente HTTP
asíncrono. Utilizaremos este cliente para llamar al primer microservicio. El comando
también ha agregado el enlace Vert.x RxJava que vamos a usar más adelante.
Ahora edite el archivo src / main / java / io / vertx / book / http / HelloConsumer
Microservice.java y actualícelo para que contenga:
Una vez que se crea la solicitud HTTP, llamamos enviar para emitir la solicitud. El
controlador que pasamos se invoca cuando llega la respuesta o se produce un error. El
bloque if-else verifica si la invocación ha tenido éxito. No olvide que es una interacción
remota y tiene muchas razones para fallar. Por ejemplo, el primer microservicio puede
no estar ejecutándose. Cuando tiene éxito, escribimos la carga recibida en la respuesta;
de lo contrario, respondemos con una respuesta de 500.
Con RX, el código complejo que habríamos escrito para llamar a las dos solicitudes y
generar una respuesta a partir de ellas se vuelve mucho más simple:
Observe las llamadas al método rxSend. Los métodos RxJava de Vert.x tienen el prefijo
rx para ser fácilmente reconocibles. El resultado de rxSend es Single, es decir, un
elemento observable de un elemento que representa el resultado diferido de una
operación. El método single.zip toma como entrada un conjunto de Single, y una vez
que todos han recibido su valor, llama a una función con los resultados. Single.zip
produce otro Single que contiene el resultado de la función. Finalmente, nos
suscribimos. Este método toma dos funciones como parámetros:
Con este código, si abrimos http: // localhost: 8081 y el microservicio hola aún se está
ejecutando, deberíamos ver:
El problema principal con el diseño actual es el acoplamiento estrecho entre los dos
microservicios. El cliente web está configurado para apuntar al primer microservicio
explícitamente. Si falla el primer microservicio, no podremos recuperarnos llamando a
otro. Si estamos bajo carga, crear una nueva instancia del hola microservicio no nos
ayudará. Gracias al cliente web Vert.x, las interacciones son asíncronas. Sin embargo,
como no utilizamos una dirección virtual (destino) para invocar el microservicio, sino
su URL directa, no proporciona la resistencia y elasticidad que necesitamos.
Es importante tener en cuenta que el uso de la programación reactiva como en el
segundo microservicio no le brinda los beneficios del sistema reactivo. Proporciona un
Una vez generado, es posible que tengamos que configurar Infinispan para construir
el clúster. La configuración predeterminada utiliza multidifusión para descubrir los
nodos. Si su red admite multidifusión, debería estar bien. De lo contrario, compruebe
el directorio de recursos / clúster del repositorio de código
El -cluster le dice a Vert.x que comience en modo cluster. Ahora vamos a escribir un
microservicio que consume este servicio.
Aquí también agregamos el soporte de Vert.x RxJava para beneficiarse de las API de
RXified proporcionadas por Vert.x. Si actualizó la configuración de Infinispan en la
sección anterior, necesita copiarla en este nuevo proyecto. Ahora edite el vicio
io.vertx.book.message.HelloConsumerMicroser. Como vamos a usar RxJava, cambie
la declaración de importación para que coincida con
io.vertx.rxjava.core.AbstractVerticle. Luego implementa el método de inicio con:
Este código es muy similar al código del capítulo anterior. En lugar de usar un
WebClient para invocar un punto final HTTP, usaremos el bus de eventos para enviar
un mensaje a la dirección de saludo y extraer el cuerpo de la respuesta. Usamos la
operación zip para recuperar las dos respuestas y generar el resultado final. En el
método de suscripción, imprimimos el resultado final en la consola o imprimimos el
seguimiento de la pila. Combinemos esto con un servidor HTTP. Cuando se recibe una
solicitud HTTP, invocamos el servicio de saludo dos veces y devolvemos el resultado
generado como respuesta:
Esto lanza dos instancias del microservicio Hello. Vuelva a su navegador y actualice
la página y debería ver algo como:
Se utilizan las dos instancias de Hello. El clúster Vert.x conecta los diferentes nodos,
y el bus de eventos está agrupado. Gracias al round-robin del bus de eventos, el bus de
eventos Vert.x envía mensajes a las instancias disponibles y, por lo tanto, equilibra la
carga entre los diferentes nodos que escuchan la misma dirección.
2.8.2. Resistencia
¿Qué pasa con la resiliencia? En el código actual, si fallase el microservicio de saludo,
obtendríamos un error y ejecutaríamos este código:
Vuelva a empaquetar y reinicie las dos instancias del microservicio Hello. Con esta
inyección de fallas implementada, debemos mejorar la tolerancia a fallas de nuestros
consumidores. De hecho, el consumidor puede obtener un tiempo de espera o recibir
una falla explícita. En el microservicio de consumo hola, cambie la forma en que
invocamos el servicio de saludo para:
Se pueden utilizar dos tipos de patrones para consumir servicios. Cuando se utiliza la
detección de servicios del lado del cliente, el servicio del consumidor busca un
servicio basado en su nombre y metadatos en el registro de servicios, selecciona un
servicio coincidente y lo usa. La referencia recuperada del registro de servicios
contiene un enlace directo a un microservicio. Como los microservicios son entidades
dinámicas, la infraestructura de descubrimiento de servicios no solo debe permitir
que los proveedores publiquen sus servicios y que los consumidores busquen
servicios, sino que también proporcionen información sobre las llegadas y salidas de
servicios. Cuando se utiliza la detección de servicios del lado del cliente, el registro
de servicios puede adoptar diversas formas, como una estructura de datos
Puede recuperar servicios por tipos para obtener un cliente de servicio configurado
listo para ser utilizado. Un tipo de servicio puede ser un punto final HTTP, una
dirección de bus de eventos, una fuente de datos, etc. Por ejemplo, si desea recuperar
el punto final HTTP llamado hola que implementamos en el capítulo anterior,
escribiría el siguiente código:
El modelo de desarrollo Vert.x hace que los fallos sean una entidad central. Cuando se utiliza
el modelo de desarrollo de devolución de llamada, los Manejadores a menudo reciben un
AsyncResult como parámetro. Esta estructura encapsula el resultado de una operación
asíncrona. En el caso de éxito, puede recuperar el resultado. En caso de fallo, contiene un
Throwable que describe el fallo:
client.get("/").as(BodyCodec.jsonObject())
.send(ar -> {
if (ar.failed()) {
Throwable cause = ar.cause();
// Necesitas gestionar el fallo.
} else {
// Es un exito
JsonObject json = ar.result().body();
}
});
Cuando se usan las API de RxJava, la administración de fallas se puede hacer en el método
de suscripción:
client.get("/").as(BodyCodec.jsonObject())
.rxSend()
.map(HttpResponse::body)
.subscribe(
json -> { /* success */ },
err -> { /* failure */ }
);
Si se produce una falla en una de las secuencias observadas, se llama al manejador de errores.
También puede manejar el error antes, evitando el controlador de errores en el método de
suscripción:
client.get("/").as(BodyCodec.jsonObject())
.rxSend()
.map(HttpResponse::body)
.onErrorReturn(t -> {
// Llamado si rxSend produce una falla
// Podemos devolver un valor por defecto
return new JsonObject();
})
.subscribe(
json -> {
// Siempre llamado, ya sea con el resultado
real.
// o con el valor por defecto.
}
);
}
);
Los tiempos de espera a menudo se utilizan junto con los reintentos. Cuando se produce un
tiempo de espera, podemos intentarlo de nuevo. Inmediatamente, volver a intentar una
operación después de una falla tiene varios efectos, pero solo algunos de ellos son
beneficiosos.
invocar varias veces sin cambiar el resultado más allá de la llamada inicial. Antes de volver
a intentarlo, compruebe siempre que su sistema puede manejar las operaciones reintentadas
con gracia.
Reintentar también hace que el consumidor espere aún más para obtener una respuesta, lo
cual tampoco es bueno. A menudo es mejor devolver un respaldo que reintentar una
operación demasiadas veces. Además, martillar continuamente un servicio que falla no puede
ayudarlo a volver a la pista. Estas dos preocupaciones son manejadas por otro patrón de
resiliencia: el interruptor automático.
En este código, la interacción HTTP está protegida por el interruptor automático. Cuando el
número de fallas alcanza el umbral configurado, el interruptor de circuito dejará de llamar al
microservicio y, en su lugar, llamará un repliegue. Periódicamente, el interruptor automático
dejará pasar una invocación para verificar si el microservicio está de nuevo en marcha y
actuará en consecuencia. Este ejemplo utiliza un cliente web, pero cualquier interacción
puede administrarse con un interruptor de circuito y protegerlo contra servicios escamosos,
excepciones y otros tipos de fallas.
Un interruptor de circuito que cambie a un estado abierto debe ser supervisado por su equipo
de operaciones. Tanto Hystrix como el interruptor de circuito Vert.x tienen capacidades de
monitoreo.
Una comprobación de estado es una API proporcionada por un microservicio que indica su
estado. Le dice a la persona que llama si el servicio es bueno o no. La invocación a menudo
utiliza interacciones HTTP pero no es necesaria. Después de la invocación, se ejecuta un
conjunto de comprobaciones y el estado global se calcula y se devuelve. Cuando se detecta
que un microservicio no es saludable, no debe volver a llamarse, ya que el resultado
probablemente será un fracaso. Tenga en cuenta que llamar a un microservicio saludable
tampoco garantiza un éxito. Una comprobación de estado simplemente indica que el
microservicio se está ejecutando, no que manejará su solicitud con precisión o que la red
responderá.
},
future::fail
);
});
// Un segundo procedimiento (comercial)
hch.register("business-check", future -> {
// ...
});
// Mapa/salud para el controlador de control de salud
router.get("/health").handler(hch);
// ...
Una vez que haya completado las comprobaciones de estado, puede implementar una
estrategia de conmutación por error. En general, la estrategia simplemente reinicia la parte
muerta del sistema, esperando lo mejor. Si bien la infraestructura de tiempo de ejecución a
menudo proporciona la conmutación por error, Vert.x ofrece una conmutación por error
integrada, que se activa cuando un nodo del clúster muere. Con la conmutación por error
Vert.x incorporada, no necesita una comprobación de estado personalizada, ya que el clúster
Vert.x emite nodos periódicamente. Cuando Vert.x pierde la pista de un nodo, Vert.x elige
un nodo en buen estado del clúster y vuelve a desplegar la parte muerta.
Hasta ahora, solo hemos implementado nuestros microservicios en una máquina local. ¿Qué
sucede cuando implementamos un microservicio en la nube? La mayoría de las plataformas
en la nube incluyen servicios para facilitar su implementación y operaciones. La capacidad
de escalar hacia arriba y hacia abajo y el equilibrio de carga son algunas de las características
comunes que son particularmente relevantes para el desarrollo de microservicios reactivos.
En este capítulo, veremos cómo se pueden usar estas características (y otras) para desarrollar
e implementar microservicios reactivos. Para ilustrar estos beneficios, utilizaremos
Kubernetes (en azul en la Figura 5-1) es un proyecto con mucha funcionalidad para ejecutar
clústeres de microservicios dentro de contenedores de Linux a escala. Google ha
empaquetado más de una década de experiencia con contenedores en Kubernetes. OpenShift
se basa en esta experiencia y la amplía con la automatización de compilación y despliegue
(en verde en la Figura 5-1). Los casos de uso, como las actualizaciones sucesivas, los
despliegues de canarios y los procesos de entrega continua se proporcionan de forma
inmediata.
OpenShift tiene un puñado de entidades simples, como se muestra en la Figura 5-2, que
debemos comprender antes de ponerlo en funcionamiento.
4.1.3 Pods
Los “pods” son un grupo de uno o más contenedores. Sin embargo, normalmente se compone
de un solo contenedor. La organización, programación y administración de pod se delegan a
Kubernetes. Las vainas son fungibles y pueden ser reemplazadas en cualquier momento por
otra instancia. Por ejemplo, si el contenedor falla, se generará otra instancia.
Para instalar Minishift, simplemente descargue el archivo más reciente para su sistema
operativo desde la página de lanzamientos de Minishift
(https://github.com/minishift/minishift/releases), desempaquételo en su ubicación preferida y
agregue el binario de minishift a su RUTA Variable ambiental. Una vez instalado, inicie
Minishift usando:
minishift start
También necesitamos el cliente OpenShift (oc), una utilidad de línea de comandos que se
utiliza para interactuar con su instancia de OpenShift. Descargue la versión más reciente del
cliente de OpenShift desde https://github.com/openshift/origin/releases/latest.
Descomprímalo en su ubicación preferida y agregue el binario oc a su variable de entorno
PATH.
OpenShift tiene un concepto de espacio de nombres llamado proyecto. Para crear proyectos
para los ejemplos que vamos a implementar, ejecute:
oc new-project reactive-microservices
oc policy add-role-to-user admin developer -n
reactive-microservices
oc policy add-role-to-user view -n reactive-microservices
-z default
En su navegador, abra https://192.168.64.12:8443/console/project/reactive-microservices/.
Debería poder ver el proyecto, que no es muy interesante en este momento ya que no hemos
implementado nada (Figura 5-3).
package io.vertx.book.openshift;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.http.HttpHeaders;
import io.vertx.core.json.JsonObject;
import io.vertx.ext.web.*;
public class HelloHttpVerticle extends AbstractVerticle {
static final String HOSTNAME = System.getenv("HOSTNAME");
@Override
public void start() {
Router router = Router.router(vertx);
router.get("/").handler(this::hello);
router.get("/:name").handler(this::hello);
vertx.createHttpServer()
.requestHandler(router::accept)
.listen(8080);
}
private void hello(RoutingContext rc) {
String message = "hello";
if (rc.pathParam("name") != null) {
message += " " + rc.pathParam("name");
}
JsonObject json = new JsonObject()
.put("message", message)
.put("served-by", HOSTNAME);
rc.response()
.putHeader(HttpHeaders.CONTENT_TYPE, "application/json")
.end(json.encode());
}
}
La separación del código Java de las opciones de implementación debe ser una elección
deliberada de diseño para que el código pueda ejecutarse en cualquier plataforma de nube.
el complemento Fabric8 Maven. Por defecto, crea un pod. El complemento también crea un
servicio. Puede encontrar toda esta información en el panel de OpenShift, como se muestra
en la Figura 5-4.
Las rutas no se crean de forma predeterminada por el complemento Fabric8 Maven. Sin
embargo, creamos uno a partir de su descripción (src / main / fabric8 / route.yml). Si abre su
navegador en http://hello-microservicereactive-microservices.192.168.64.nip.io/Luke,
debería ver algo como:
{"message":"hello Luke","served-by":
"hello-microservice-1-9r8uv"}
@Override
public void start() {
Router router = Router.router(vertx);
router.get("/").handler(this::invokeHelloMicroservice);
// Create the service discovery instance
ServiceDiscovery.create(vertx, discovery -> {
// Look for an HTTP endpoint named "hello-microservice"
// you can also filter on 'label'
Single<WebClient> single = HttpEndpoint.rxGetWebClient
(discovery, rec -> rec.getName().equals
("hello-microservice"),
new JsonObject().put("keepAlive", false));
single.subscribe(
client -> {
// the configured client to call the microservice
this.hello = client;
vertx.createHttpServer()
.requestHandler(router::accept)
.listen(8080);
},
err -> System.out.println("Oh no, no service")
);
});
}
{
"luke" : "hello Luke hello-microservice-1-sa5pf",
"leia" : "hello Leia hello-microservice-1-sa5pf"
}
Es posible que vea una página de error 503, ya que el pod aún no se ha iniciado. Solo
actualiza hasta que obtengas la página correcta. Hasta ahora, nada sorprendente. Los
valores de publicación mostrados siempre indican el mismo pod (ya que solo tenemos
uno).
# scale up to 2 replicas
oc scale --replicas=2 dc hello-microservice
# scale down to 0
oc scale --replicas=0 dc hello-microservice
Vamos a crear una segunda instancia de nuestro microservicio de saludo. Luego, espere
hasta que el segundo microservicio se haya iniciado correctamente (el tiempo de espera
es molesto, pero lo solucionaremos más adelante), y vuelva a la página de
helloconsumer en un navegador. Deberías ver algo como:
{
"luke" : "hello Luke hello-microservice-1-h6bs6",
Si actualiza varias veces, verá que el servicio OpenShift equilibra la carga entre las dos
instancias. Te acuerdas de la ¿Mantenemos la configuración para mantenernos vivos?
Cuando la conexión HTTP usa una conexión de mantenimiento, OpenShift reenvía la
solicitud al mismo pod, proporcionando afinidad de conexión. Tenga en cuenta que en
la práctica, keep-alive es un encabezado muy deseable ya que permite reutilizar las
conexiones.
El complemento Fabric8 Maven está configurado para usar / health para las
comprobaciones de estado de preparación y vida. Una vez implementada esta versión
de hello microservice, todas las implementaciones posteriores utilizarán la verificación
de preparación para evitar el tiempo de inactividad, como se muestra en la Figura 5-6.
Cuando el pod está listo, OpenShift enruta las solicitudes a este pod y apaga el viejo.
Cuando escalamos, OpenShift no enrutar las solicitudes a un pod que no esté listo.
En el artículo, estamos usando un solo interruptor para proteger Contra las dos llamadas
al hola microservicio. El siguiente código usa este diseño; Sin embargo, es sólo uno
entre un gran conjunto de posibles enfoques, como el uso de un interruptor automático
por llamada, el uso de un solo interruptor de circuito pero protegiendo las dos llamadas
de forma independiente, etc .:
.as(BodyCodec.jsonObject());
HttpRequest<JsonObject> request2 = hello.get("/Leia")
.as(BodyCodec.jsonObject());
Single<JsonObject> s1 = request1
.rxSend().map(HttpResponse::body);
Single<JsonObject> s2 = request2
.rxSend().map(HttpResponse::body);
Single
.zip(s1, s2, (luke, leia) -> {
// We have the result of both request in Luke and Leia
return new JsonObject()
.put("Luke", luke.getString("message")
+ " " + luke.getString("served-by"))
.put("Leia", leia.getString("message")
+ " " + leia.getString("served-by"));
})
.subscribe(future::complete, future::fail);
},
error -> new JsonObject().put("message", "hello (fallback, "
+ circuit.state().toString() + ")")
).subscribe(
x -> rc.response().end(x.encodePrettily()),
t -> rc.response().end(t.getMessage()));
}
Ahora reduzcamos el microservicio de saludo a 0. Para hacer esto, podemos haga clic
en la flecha hacia abajo cerca del pod, o ejecute:
{
"message" : "hello (fallback, CLOSED)"
}
debería recuperar la salida normal una vez que el microservicio esté listo.
¿Puede cualquier sistema que utilice HTTP sin bloqueo asíncrono ser reactivo?
Sistema en una nube que proporciona equilibrio de carga y cierta capacidad de
recuperación. ¿caracteristicas? Sí, pero no olvides los costes. Vert.x usa un bucle de
evento para manejar un alto nivel de concurrencia con un mínimo de subprocesos,
Exhibiendo una nube nativa de la naturaleza. Cuando se utilizan enfoques basados en
grupos de subprocesos, necesitará
1) ajustar el grupo de subprocesos para encontrar el Talla correcta;
2) manejar la concurrencia en su código, lo que significa depuración de puntos muertos,
condiciones de carrera y cuellos de botella; y
3) monitor
actuación. Los entornos de nube se basan en la virtualización, y la programación de
subprocesos puede convertirse en un problema importante cuando tiene muchos hilos.
Hay muchas tecnologías de no bloqueo, pero no todas utilizan El mismo modelo de
ejecución para manejar la naturaleza asíncrona. Puede clasificar estas tecnologías en
tres categorías:
1. Enfoques utilizando un grupo de subprocesos en segundo plano: luego se enfrentan
a un reto de ajuste, programación y concurrencia cambiando la carga a ops.
2. Enfoques que usan otro hilo para las devoluciones de llamada: todavía necesita para
gestionar la seguridad de subprocesos de su código y evitar puntos muertos y cuellos
de botella.
3. Enfoques, como Vert.x, que usan el mismo hilo: se usa un un pequeño número de
subprocesos y se liberan de la depuración de puntos muertos.
¿Podríamos usar sistemas de mensajería en la nube para implementar reactivos?
sistemas de microservicio? Por supuesto. Podríamos haber utilizado el Vert.x Bus de
eventos para construir nuestro microservicio reactivo en OpenShift. Pero No habría
demostrado servicio de dirección virtual y balanceo de carga. proporcionado por
OpenShift como habría sido manejado por Vert.x en sí. Aquí decidimos ir con HTTP,
un diseño entre un número infinito de opciones. Da forma a tu sistema de la forma que
quieras ¡eso!
5.6 Resumen
En este capítulo, desplegamos microservicios en OpenShift y vimos cómo se combinan
las características de Vert.x y OpenShift para construir reactivo microservicios
Combinando servidores y clientes HTTP asíncronos, Servicios OpenShift, balanceo de
carga, failover y del lado del consumidor La resiliencia nos da las características de un
sistema reactivo.
Este informe se centra en reactivo. Sin embargo, al construir un microservicio sistema,
muchas otras preocupaciones deben gestionarse como seguridad, configuración,
registro, etc. La mayoría de las plataformas en la nube, incluyendo OpenShift, brinda
servicios para manejar estas inquietudes. Si desea obtener más información sobre estos
temas, consulte los siguientes recursos:
• Sitio web de OpenShift
• Conceptos básicos de OpenShift
• sitio web de kubernetes
• Documentación de controles de salud de OpenShift
6 CONCLUSIÓN
Estamos al final de nuestro viaje juntos, pero ustedes tienen muchos nuevas avenidas
para explorar. ¡Hemos cubierto mucho contenido en este pequeño informe, pero
ciertamente no cubrió todo! Acabamos de arañar la superficie. Hay más cosas a
considerar cuando se mueve hacia Microservicios reactivos. Vert.x tampoco se limita a
microservicios y puede manejar un gran conjunto de diferentes casos de uso.
¿Qué hemos aprendido?
Entonces, ¿qué aprendiste en este informe? Primero, comenzamos con microservicios.
Y cuáles son los microservicios reactivos. Aprendimos que reactiva microservicios son
los bloques de construcción de microservicio de respuesta sistemas También vimos
cómo la programación reactiva ayuda a construir estos microservicios Descubrimos
Eclipse Vert.x, un kit de herramientas utilizado para construir microservicios reactivos
(entre muchas otras cosas). Vert.x proporciona el perfecto paradigma para abarcar
microservicios: asíncronos, fallas como ciudadanos de primera clase, y sin bloqueo. Para
domesticar el desarrollo asíncrono. Modelo, Vert.x combina su poder con RxJava.
Nuestro descubrimiento