miércoles, 10 de noviembre de 2021

Primeros pasos con Apache Kafka parte 20



Seguimos con Kafka

En el corazón de la API del consumidor hay un bucle simple para sondear el servidor en busca de datos.

Una vez que el consumidor se suscribe a los temas, el ciclo de sondeo maneja todos los detalles de coordinación, reequilibrio de particiones, pings y obtención de datos, dejando al desarrollador con una API limpia que simplemente que devuelve los datos disponibles de las particiones asignadas. Veamos un ejemplo :

try {

    while (true) {

        ConsumerRecords<String, String> records = consumer.poll(100);

        for (ConsumerRecord<String, String> record : records) {

            log.debug("topic = %s, partition = %s, offset = %d, customer = %s, country = %s\n",

                record.topic(), record.partition(), record.offset(), record.key(), record.value());

            int updatedCount = 1;

            if (custCountryMap.countainsValue(record.value())) {

                updatedCount = custCountryMap.get(record.value()) + 1;

            }

            custCountryMap.put(record.value(), updatedCount)

            JSONObject json = new JSONObject(custCountryMap);

            System.out.println(json.toString(4))

        }

    }

} finally {

    consumer.close();

}

Este es un bucle infinito. Los consumidores suelen ser aplicaciones de larga duración que sondean continuamente a Kafka en busca de más datos. 

ConsumerRecords<String, String> records = consumer.poll(100);  en esta linea se puede ver que los consumidores deben seguir sondeando a Kafka o serán considerados muertos y las particiones que están consumiendo serán entregadas a otro consumidor del grupo para que continúe consumiendo. El parámetro que pasamos, poll (), es un intervalo de tiempo de espera y controla cuánto tiempo se bloqueará poll () si los datos no están disponibles en el búfer del consumidor. Si se establece en 0, poll () regresará inmediatamente; de lo contrario, esperará el número especificado de milisegundos para que lleguen los datos del intermediario.

poll () devuelve una lista de registros. Cada registro contiene el tema y la partición de la que proviene el registro, el desplazamiento del registro dentro de la partición y, por supuesto, la clave y el valor del registro. Por lo general, queremos iterar sobre la lista y procesar los registros individualmente. El método poll () toma un parámetro de tiempo de espera. Esto especifica cuánto tiempo tardará la encuesta en regresar, con o sin datos. El valor suele depender de las necesidades de la aplicación para obtener respuestas rápidas: ¿qué tan rápido desea devolver el control al subproceso que realiza el sondeo?

El procesamiento generalmente termina escribiendo un resultado en un almacén de datos o actualizando un registro almacenado. Aquí, el objetivo es mantener un recuento continuo de clientes de cada condado, por lo que actualizamos una tabla hash e imprimimos el resultado como JSON. Un ejemplo más realista almacenaría el resultado de las actualizaciones en un almacén de datos.

Siempre se debe cerrar la conexión del consumidor antes de salir. Esto cerrará las conexiones de red y los slots. También activará un reequilibrio de inmediato en lugar de esperar a que el coordinador del grupo descubra que el consumidor dejó de enviar pings y es probable que esté muerto, lo que llevará más tiempo y, por lo tanto, dará como resultado un período de tiempo más largo en el que los consumidores no pueden consumir mensajes de un subconjunto de las particiones.

El ciclo de la encuesta hace mucho más que simplemente obtener datos. La primera vez que llama a poll () con un nuevo consumidor, es responsable de encontrar el GroupCoordinator, unirse al grupo de consumidores y recibir una asignación de partición. Si se activa un reequilibrio, también se manejará dentro del ciclo de sondeo. Y, por supuesto, los latidos que mantienen vivos a los consumidores se envían desde dentro del ciclo de la encuesta. Por esta razón, intentamos asegurarnos de que cualquier procesamiento que hagamos entre iteraciones sea rápido y eficiente.

Primeros pasos con Apache Kafka parte 19



Seguimos con Kafka

Una vez que creamos un consumidor, el siguiente paso es suscribirse a uno o más temas. El método subcribe () toma una lista de temas como parámetro, por lo que es bastante simple de usar:

consumer.subscribe(Collections.singletonList("customerCountries"));

También es posible llamar a subscribe con una expresión regular. La expresión puede coincidir con varios nombres de temas, y si alguien crea un nuevo tema con un nombre que coincida, se producirá un reequilibrio casi de inmediato y los consumidores comenzarán a consumir desde el nuevo tema. Esto es útil para aplicaciones que necesitan consumir de múltiples temas y pueden manejar los diferentes tipos de datos que contendrán los temas.

La suscripción a varios temas mediante una expresión regular se usa con mayor frecuencia en aplicaciones que replican datos entre Kafka y otro sistema.

Para suscribirse a todos los temas de prueba, podemos llamar a:

consumer.subscribe("test.*");


Essential Programming Books


 No conocía este sitio y esta rebueno. Un montón de libros gratuitos.  La lista es : 

Book
Essential Go
Essential C++
Essential Javascript
Essential CSS
Essential HTML
Essential HTML5 Canvas
Essential Java
Essential Kotlin
Essential C#
Essential Python
Essential PostgreSQL
Essential MySQL
Essential iOS
Essential Android
Essential Bash
Essential PowerShell
Essential Batch
Essential Git
Essential PHP
Essential Ruby
Essential .NET framework
Essential Node
Essential Dart
Essential TypeScript
Essential Swift
Essential Algorithms
Essential C
Essential Objective-C
Essential React
Essential React Native
Essential Ruby On Rails
Essential SQL

martes, 9 de noviembre de 2021

GraalVM 21.3 soporta Java 17


Oracle Labs lanzó GraalVM 21.3, que ofrece soporte para Java 17 y JDK Flight Recorder (JFR) para la generación de perfiles de producción de bajo costo de ejecutables nativos de Java. En comparación con la versión 21.1 de abril de 2021, esta versión crea ejecutables nativos un 14% más pequeños para Spring PetClinic JDBC con un 20% menos de tiempo de compilación. La versión ejecuta aplicaciones más rápido y comienza a admitir Java Platform Module System.

GraalVM también inicia aplicaciones Java no nativas interpretadas más rápido ahora. Esto ayuda durante el desarrollo donde la ejecución de ejecutables nativos de Java no es práctica debido a los largos tiempos de compilación.

GraalVM viene en dos ediciones: Community Edition y Enterprise Edition. La licencia GPL de Community Edition con "Classpath" Exception significa que es "de uso gratuito para cualquier propósito y viene sin condiciones, pero tampoco garantías ni soporte". Sus lanzamientos reciben actualizaciones durante un año. Enterprise Edition requiere la suscripción a Oracle Java SE para uso en producción, pagada por usuario o por procesador.

Enterprise Edition también incluye soporte de Oracle y tiene características exclusivas de rendimiento y seguridad, como optimizaciones guiadas por perfiles y el recolector de basura G1. Es por eso que sus ejecutables nativos alcanzan el 98% del rendimiento de OpenJDK en una combinación de referencia frente al 43% con la Community Edition, todo mientras usan menos memoria y se inician más rápido que las aplicaciones OpenJDK.

Oracle afirma que los ejecutables nativos de Enterprise Edition son incluso hasta un 40% más rápidos que OpenJDK en algunos escenarios de aprendizaje automático. Constant Blinding es un ejemplo de una función de seguridad en Enterprise Edition. Defiende contra ataques de pulverización JIT y se puede habilitar con -Dgraal.BlindConstants = true.

Una nueva opción de configuración en tiempo de compilación para ejecutables nativos permite deshabilitar funciones como la reflexión, JNI, objetos de proxy dinámico y excluir los recursos de classpath si no se puede acceder a una clase. Eso puede llevar a ejecutables nativos más pequeños.

La nueva proftool (Linux solo por ahora) recopila métricas de rendimiento en tiempo de ejecución de aplicaciones Java de JVM, la herramienta perf de Linux y HotSpot LogCompilation. Esto ayuda con el análisis de rendimiento JIT.

GraalVM Polyglot Runtime ejecuta varios lenguajes además de Java. El tiempo de ejecución de JavaScript se actualizó a Node.js 14.17.6 y mejoró su compatibilidad con WebAssembly. El tiempo de ejecución de Python ahora puede ejecutar paquetes binarios de HPy sin volver a compilarlos. También admite el módulo de multiprocesamiento para orquestar tareas en múltiples contextos de Python en una máquina de múltiples núcleos y tiene un módulo de socket escrito en código nativo.

Ruby en GraalVM ahora usa TRegex, un motor de expresión regular más eficiente, y es hasta 9 veces más rápido en algunos puntos de referencia. El tiempo de ejecución de R actualizado de PCRE a PCRE2 versión 10.37. La cadena de herramientas LLVM para compilar C / C ++ se actualizó a la versión 12.0.1. Y WebAssembly se ejecuta más rápido en algunos escenarios en GraalVM Enterprise Edition.

Las herramientas de GraalVM mejoradas en Visual Studio Code: las herramientas de GraalVM para Java se pueden adjuntar a ejecutables nativos para la depuración. Y las herramientas GraalVM para Micronaut pueden implementar, ejecutar y depurar aplicaciones Micronaut en un clúster de Kubernetes.

Spring Native, una nueva iniciativa de Spring, crea ejecutables nativos para aplicaciones Spring. La versión 0.11, cuyo lanzamiento está programado para el 19 de noviembre de 2021, se basará en GraalVM 21.3 y el próximo lanzamiento de Spring Boot 2.6. La pila Java nativa de Kubernetes Quarkus utilizará GraalVM 21.3 como la versión recomendada en la próxima versión 2.5. El marco de pila completa Micronaut admitirá oficialmente GraalVM 21.3 con el próximo lanzamiento de la versión 3.2.0 programado para fines de noviembre o diciembre de 2021.

Dejo link: https://medium.com/graalvm/graalvm-21-3-is-here-java-17-native-image-performance-updates-and-more-ac4cbafcfc05

domingo, 7 de noviembre de 2021

Microservice routing patterns


Los patrones de enrutamiento de microservicios se ocupan de cómo una aplicación cliente desea consumir un microservicio, como descubre la ubicación del servicio y se enruta a él.

En una aplicación basada en la nube, es posible que tenga cientos de instancias de microservicio en ejecución. Deberá abstraer la dirección IP física de estos servicios y tener un único punto de entrada para las llamadas de servicio, de modo que pueda hacer cumplir de manera constante las políticas de seguridad y contenido para todas las llamadas de servicio.

El descubrimiento y el enrutamiento de servicios responden a la pregunta: "¿Cómo obtengo la solicitud de un servicio de mi cliente a una instancia específica de un servicio?"

Descubrimiento de servicios: ¿cómo puede hacer que su microservicio sea reconocible para que las aplicaciones cliente puedan encontrarlos sin tener la ubicación del servicio codificada en la aplicación? ¿Cómo se asegura de que las instancias de microservicio que funciona mal se eliminen del grupo de instancias de servicio disponibles? 

Enrutamiento de servicios: ¿cómo proporciona un único punto de entrada para todos sus servicios de modo que las políticas de seguridad y las reglas de enrutamiento se apliquen de manera uniforme a múltiples servicios e instancias de servicio en sus aplicaciones de microservicio? ¿Cómo se asegura de que cada desarrollador de su equipo no tenga que idear sus propias soluciones para proporcionar enrutamiento a sus servicios? 

El descubrimiento de servicios y el enrutamiento de servicios parecen tener una secuencia de eventos codificada de forma rígida entre ellos (primero viene el enrutamiento de servicios y el descubrimiento de servicios). Sin embargo, los dos patrones no dependen el uno del otro. Por ejemplo, podemos implementar el descubrimiento de servicios sin enrutamiento de servicios. Puede implementar el enrutamiento de servicios sin descubrimiento de servicios (aunque su implementación es más difícil).

viernes, 5 de noviembre de 2021

Core development patterns


Los patrones de desarrollo core de microservicios abordan los conceptos básicos de construcción un microservicio. 

Granularidad del servicio: ¿cómo aborda la descomposición de un dominio empresarial en microservicios para que cada microservicio tenga el nivel adecuado de responsabilidad? Hacer que un servicio sea demasiado grueso con responsabilidades que se superponen en diferentes dominios de problemas comerciales hace que el servicio sea difícil de mantener y cambiar con el tiempo. Hacer que el servicio sea demasiado detallado aumenta la complejidad general de la aplicación y convierte el servicio en una capa de abstracción de datos “tonta” sin lógica.

Protocolos de comunicación: ¿cómo se comunicarán los desarrolladores con su servicio? ¿Utiliza XML (Extensible Markup Language), JSON (JavaScript Object Notation) o un protocolo binario como Thrift para enviar datos de un lado a otro de sus microservicios? 

Diseño de interfaz: ¿cuál es la mejor manera de diseñar las interfaces de servicio reales que los desarrolladores usarán para llamar a su servicio? ¿Cómo estructura las URL de sus servicios para comunicar la intención del servicio? ¿Qué pasa con el control de versiones de sus servicios? 

Gestión de la configuración del servicio: ¿cómo gestiona la configuración de su microservicio para que, a medida que se mueva entre diferentes entornos en la nube, nunca tenga que cambiar el código o la configuración de la aplicación principal?

Procesamiento de eventos entre servicios: ¿cómo desacopla su microservicio mediante eventos para minimizar las dependencias codificadas entre sus servicios y aumentar la resistencia de su aplicación? 

Los microservicios son más que escribir el código


Si bien los conceptos relacionados con la creación de microservicios individuales son fáciles de entender, ejecutar y admitir una aplicación de microservicio robusta (especialmente cuando se ejecuta en la nube) implica más que escribir el código para el servicio. Escribir un servicio sólido incluye considerar varios temas. 

Tamaño adecuado: ¿cómo nos aseguramos de que los microservicios tengan el tamaño adecuado para que no tenga un microservicio que asuma demasiada responsabilidad? Un servicio con el tamaño adecuado nos permite realizar cambios rápidamente en una aplicación y reduce el riesgo general de una interrupción en toda la aplicación.

Transparencia en la ubicación: ¿cómo gestionamos los detalles físicos de la invocación del servicio cuando, en una aplicación de microservicio, se pueden iniciar y cerrar varias instancias de servicio rápidamente?

Resiliente: ¿cómo protege a sus consumidores de microservicios y la integridad general de su aplicación al enrutar los servicios que fallan y asegurarse de adoptar un enfoque "fail-fast"?

Repetible: ¿cómo se asegura de que se garantice que cada nueva instancia de su servicio que aparece tenga la misma configuración y base de código que todas las demás instancias de servicio en producción?

Escalable: ¿cómo se utilizan los eventos y el procesamiento asincrónico para minimizar las dependencias directas entre sus servicios y asegurarse de poder escalar correctamente sus microservicios?

Con un enfoque basado en patrones, tenemos soluciones comunes que se pueden utilizar en diferentes implementaciones de tecnología para estos problemas. Entre los patrones existe seis categorías de patrones de microservicio:

  •  Core development patterns
  •  Routing patterns
  •  Client resiliency patterns
  •  Security patterns
  •  Logging and tracing patterns
  •  Build and deployment patterns

Repasemos estos patrones con más detalle en próximos posts. 

martes, 2 de noviembre de 2021

Oracle JDK 17 es gratuita nuevamente para uso comercial

 

Oracle JDK 17 es gratuita nuevamente para uso comercial, bajo la nueva licencia "Términos y condiciones sin cargo de Oracle" (NFTC). Este movimiento revierte la decisión de 2018 de cobrar por el uso en producción de Oracle JDK y no afecta la distribución de OpenJDK de Oracle. La NFTC se aplica a la versión 17 recientemente lanzada de Oracle JDK y versiones futuras.

En conclusión oracle revierte una mala decisión. 

Dejo link: https://www.oracle.com/downloads/licenses/no-fee-license.html


sábado, 30 de octubre de 2021

Primeros pasos con Apache Kafka parte 18


Seguimos con Kafka

El primer paso para comenzar a consumir registros es crear una instancia de KafkaConsumer. Crear un KafkaConsumer es muy similar a crear un KafkaProducer: crea una instancia de propiedades de Java con las propiedades que desea pasar al consumidor. Para comenzar, solo necesitamos usar las tres propiedades obligatorias: bootstrap.servers, key.deserializer y value.deserializer.

La primera propiedad, bootstrap.servers, es la cadena de conexión a un clúster de Kafka. Se usa exactamente de la misma manera que en KafkaProducer. Las otras dos propiedades, key.deserializer y value.deserializer, son similares a los serializadores definidos para el productor, pero en lugar de especificar clases que conviertan los objetos Java en matrices de bytes, debe especificar clases que puedan tomar una matriz de bytes y convertirla en un objeto Java.

Hay una cuarta propiedad, que no es estrictamente obligatoria, pero por ahora pretendemos que lo es. La propiedad es group.id y especifica el grupo de consumidores al que pertenece la instancia de KafkaConsumer. Si bien es posible crear consumidores que no pertenecen a ningún grupo de consumidores, esto es poco común, por lo que durante la mayor parte del capítulo asumiremos que el consumidor es parte de un grupo.

El siguiente fragmento de código muestra cómo crear un KafkaConsumer:

Properties props = new Properties();

props.put("bootstrap.servers", "broker1:9092,broker2:9092");

props.put("group.id", "CountryCounter");

props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");

KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(props);

La mayor parte de lo que ve aquí debería resultarle familiar sobre la creación de productores. Suponemos que los registros que consumimos tendrán objetos String como clave y valor del registro. La única propiedad nueva aquí es group.id, que es el nombre del grupo de consumidores al que pertenece este consumidor.

Microservicios con Spring


Spring se ha convertido en el framework de desarrollo de facto para crear aplicaciones basadas en Java. En esencia, Spring se basa en el concepto de inyección de dependencia. En una aplicación Java normal, la aplicación se descompone en clases en las que cada clase suele tener vínculos explícitos con otras clases de la aplicación. Los enlaces son la invocación de un constructor de clase directamente en el código. Una vez que se compila el código, estos puntos de enlace no se pueden cambiar.

Esto es problemático en un proyecto grande porque estos vínculos externos son frágiles y hacer un cambio puede resultar en múltiples impactos posteriores en otro código. Un marco de inyección de dependencia, como Spring, le permite administrar más fácilmente grandes proyectos de Java al externalizar la relación entre los objetos dentro de su aplicación a través de convenciones (y anotaciones) en lugar de aquellos objetos que tienen conocimientos codificados entre sí. Spring actúa como intermediario entre las diferentes clases de Java de su aplicación y administra sus dependencias. Spring esencialmente le permite ensamblar su código como un conjunto de ladrillos de Lego que se unen.

La rápida inclusión de funciones de Spring impulsó su utilidad, y el marco se convirtió rápidamente en una alternativa más liviana para los desarrolladores de aplicaciones empresariales de Java que buscaban una forma de crear aplicaciones utilizando la pila J2EE. El stack J2EE, aunque poderosa, fue considerada por muchos como bloatware, con muchas características que nunca fueron utilizadas por los equipos de desarrollo de aplicaciones. Además, una aplicación J2EE le obligó a utilizar un servidor de aplicaciones Java completo (y pesado) para implementar sus aplicaciones.

Lo sorprendente del marco de Spring y un testimonio de su comunidad de desarrollo es su capacidad para mantenerse relevante y reinventarse. El equipo de desarrollo de Spring vio rápidamente que muchos equipos de desarrollo se estaban alejando de las aplicaciones monolíticas donde la presentación de la aplicación, el negocio y la lógica de acceso a los datos estaban empaquetados y desplegados como un solo artefacto. En cambio, los equipos se estaban moviendo hacia modelos altamente distribuidos donde los servicios se construían como servicios pequeños y distribuidos que podían implementarse fácilmente en la nube. En respuesta a este cambio, el equipo de desarrollo de Spring lanzó dos proyectos: Spring Boot y Spring Cloud.

Spring Boot es una nueva visión del framework de Spring. Si bien abarca las características centrales de Spring, Spring Boot elimina muchas de las características "empresariales" que se encuentran en Spring y, en su lugar, ofrece un marco orientado a microservicios basados ​​en Java y orientados a REST (Transferencia de estado representacional). Con unas pocas anotaciones simples, un desarrollador de Java puede crear rápidamente un microservicio REST que se puede empaquetar e implementar sin la necesidad de un contenedor de aplicaciones externo.

Debido a que los microservicios se han convertido en uno de los patrones arquitectónicos más comunes para la creación de aplicaciones basadas en la nube, la comunidad de desarrollo de Spring nos ha proporcionado Spring Cloud. El framework de Spring Cloud simplifica la puesta en funcionamiento e implementación de microservicios en una nube pública o privada. Spring Cloud incluye varios frameworks de microservicios de gestión de la nube populares en un framework común y hace que el uso y la implementación de estas tecnologías sean tan fáciles de usar como anotar su código. 

viernes, 29 de octubre de 2021

Que son los Microservicios?


La única constante en el campo del desarrollo de software es que nosotros, como desarrolladores de software, nos sentamos en medio de un mar de caos y cambio. Todos sentimos la rotación cuando las nuevas tecnologías y enfoques aparecen repentinamente en escena, lo que nos hace reevaluar cómo construimos y entregamos soluciones para nuestros clientes. Un ejemplo de este abandono es la rápida adopción por parte de muchas organizaciones de crear aplicaciones utilizando microservicios. Los microservicios son servicios de software distribuidos, débilmente acoplados, que llevan a cabo una pequeña cantidad de tareas bien definidas.

Antes de que evolucionara el concepto de microservicios, la mayoría de las aplicaciones basadas en web se creaban con un estilo arquitectónico monolítico. En una arquitectura monolítica, una aplicación se entrega como un único artefacto de software implementable. Toda la IU (interfaz de usuario), el negocio y la lógica de acceso a la base de datos se empaquetan en un solo artefacto de aplicación y se implementan en un servidor de aplicaciones.

Si bien una aplicación puede implementarse como una sola unidad de trabajo, la mayoría de las veces habrá varios equipos de desarrollo trabajando en la aplicación. Cada equipo de desarrollo tendrá sus propias piezas discretas de la aplicación de las que son responsables y, a menudo, clientes específicos a los que atienden con su pieza funcional. Por ejemplo, cuando trabajaba en una gran empresa de servicios financieros, teníamos una aplicación interna de gestión de relaciones con el cliente (CRM) personalizada que implicaba la coordinación de varios equipos, incluidos la interfaz de usuario, el cliente maestro, el almacén de datos y el equipo de fondos mutuos. 

El problema aquí es que a medida que aumentaba el tamaño y la complejidad de la aplicación CRM monolítica, los costos de comunicación y coordinación de los equipos individuales que trabajaban en la aplicación no aumentaban. Cada vez que un equipo individual necesitaba hacer un cambio, toda la aplicación tenía que reconstruirse, volverse a probar y volver a implementar.

El concepto de microservicio se infiltró originalmente en la conciencia de la comunidad de desarrollo de software alrededor de 2014 y fue una respuesta directa a muchos de los desafíos de tratar de escalar aplicaciones monolíticas tanto técnica como organizativamente grandes. Recuerde, un microservicio es un servicio distribuido pequeño, débilmente acoplado.

Los microservicios le permiten tomar una aplicación grande y descomponerla en componentes fáciles de administrar con responsabilidades estrictamente definidas. Los microservicios ayudan a combatir los problemas tradicionales de complejidad en una base de código grande al descomponer la base de código grande en partes pequeñas y bien definidas. El concepto clave que debe adoptar al pensar en microservicios es descomponer y desagregar la funcionalidad de sus aplicaciones para que sean completamente independientes entre sí.

Si tomamos la aplicación CRM y la descomponemos en microservicios, podría verse como que cada equipo funcional es dueño por completo de su código de servicio y su infraestructura de servicio. Pueden compilar, implementar y probar de forma independiente entre sí porque su código, repositorio de control de fuente y la infraestructura (servidor de aplicaciones y base de datos) ahora son completamente independientes de las otras partes de la aplicación.

Una arquitectura de microservicio tiene las siguientes características:

  • La lógica de la aplicación se divide en componentes de grano pequeño con límites de responsabilidad bien definidos que se coordinan para ofrecer una solución.
  • Cada componente tiene un pequeño dominio de responsabilidad y se implementa de forma completamente independiente entre sí. Los microservicios deben tener la responsabilidad de una sola parte de un dominio empresarial. Además, un microservicio debe poder reutilizarse en varias aplicaciones.
  • Los microservicios se comunican basándose en algunos principios básicos (fíjese que dije principios, no estándares) y emplean protocolos de comunicación ligeros como HTTP y JSON (notación de objetos JavaScript) para intercambiar datos entre el consumidor y el proveedor de servicios.
  • La implementación técnica subyacente del servicio es irrelevante porque las aplicaciones siempre se comunican con un protocolo de tecnología neutral (JSON es el más común). Esto significa que una aplicación creada con una aplicación de microservicio podría crearse con varios lenguajes y tecnologías.
  • Los microservicios, por su naturaleza pequeña, independiente y distribuida, permiten a las organizaciones tener pequeños equipos de desarrollo con áreas de responsabilidad bien definidas. Estos equipos pueden trabajar hacia un único objetivo, como entregar una aplicación, pero cada equipo es responsable solo de los servicios en los que están trabajando.

A menudo bromeo con mis colegas diciendo que los microservicios son la droga de entrada para crear aplicaciones en la nube. Usted comienza a construir microservicios porque le brindan un alto grado de flexibilidad y autonomía con sus equipos de desarrollo, pero usted y su equipo descubren rápidamente que la naturaleza pequeña e independiente de los microservicios los hace fácilmente implementables en la nube. Una vez que los servicios están en la nube, su pequeño tamaño facilita la puesta en marcha de una gran cantidad de instancias del mismo servicio y, de repente, sus aplicaciones se vuelven más escalables y, con previsión, más resistentes.

miércoles, 27 de octubre de 2021

Welcome to AWS Skill Builder


Amazon lanzo una pagina llamada skill builder, la idea es que más gente aprenda y se certifique. Por lo tanto Amazon centralizo el training. 

Aquí puede encontrar formación digital para su función o intereses. Bueno sin más... 


Dejo link: https://explore.skillbuilder.aws/learn


domingo, 24 de octubre de 2021

Primeros pasos con Apache Kafka parte 17


Seguimos con Kafka

Los consumidores de un grupo de consumidores comparten las propiedades de las particiones en los temas a los que se suscriben. Cuando agregamos un nuevo consumidor al grupo, comienza a consumir mensajes de particiones previamente consumidas por otro consumidor. Lo mismo sucede cuando un consumidor se apaga o se bloquea; abandona el grupo, y las particiones que solía consumir serán consumidas por uno de los consumidores restantes. La reasignación de particiones a los consumidores también ocurre cuando los temas que consume el grupo de consumidores se modifican (por ejemplo, si un administrador agrega nuevas particiones). Mover la propiedad de una partición de un consumidor a otro se denomina reequilibrio.

Los reequilibrios son importantes porque brindan al grupo de consumidores una alta disponibilidad y escalabilidad (lo que nos permite agregar y eliminar consumidores de manera fácil y segura), pero en el curso normal de los eventos son bastante indeseables. Durante un reequilibrio, los consumidores no pueden consumir mensajes, por lo que un reequilibrio es básicamente una breve ventana de indisponibilidad de todo el grupo de consumidores. Además, cuando las particiones se mueven de un consumidor a otro, el consumidor pierde su estado actual; si estaba almacenando en caché algún dato, deberá actualizar sus cachés, lo que ralentizará la aplicación hasta que el consumidor configure su estado nuevamente. 

La forma en que los consumidores mantienen la membresía en un grupo de consumidores y la propiedad de las particiones que se les asignan es enviando latidos a un corredor de Kafka designado como coordinador del grupo (este corredor puede ser diferente para diferentes grupos de consumidores). Siempre que el consumidor envíe latidos a intervalos regulares, se asume que está vivo, bien y procesando mensajes de sus particiones. Los latidos se envían cuando el consumidor realiza una encuesta (es decir, recupera registros) y cuando confirma los registros que ha consumido.

Si el consumidor deja de enviar latidos durante el tiempo suficiente, su sesión expirará y el coordinador del grupo la considerará muerta y provocará un reequilibrio. Si un consumidor falla y deja de procesar mensajes, el coordinador del grupo tardará unos segundos sin latidos en decidir que está muerto y activar el reequilibrio. Durante esos segundos, no se procesarán mensajes de las particiones propiedad del consumidor muerto. Al cerrar un consumidor limpiamente, el consumidor notificará al coordinador del grupo que se va, y el coordinador del grupo activará un reequilibrio de inmediato, reduciendo la brecha en el procesamiento. 

Con las versiones más recientes de Kafka, puede configurar cuánto tiempo puede pasar la aplicación sin sondear antes de que abandone el grupo y active un reequilibrio. Esta configuración se utiliza para evitar un bloqueo en vivo, en el que la aplicación no se bloqueó pero no logró avanzar por alguna razón. Esta configuración es independiente de session.time out.ms, que controla el tiempo que se tarda en detectar un bloqueo del consumidor y dejar de enviar latidos.


viernes, 22 de octubre de 2021

Mutiny!

 



Si leen este blog, algo sabran de reactive programming y de quarkus, Mutiny! es el framework elegido por la gente de red hat para implementar reactive programming en quarkus.

Podemos usarlo en nuestros proyectos, sin necesidad de usar quarkus, es decir, de forma independiente. A la vez se acopla muy bien con vert.x. Y entre sus características, podemos nombrar que es un framework moderno, liviano y pequeño. 

Veamos un "hola mundo" : 

import io.smallrye.mutiny.Uni;


public class FirstProgram {


  public static void main(String[] args) {

    Uni.createFrom().item("hello")

      .onItem().transform(item -> item + " mutiny")

      .onItem().transform(String::toUpperCase)

      .subscribe().with(

        item -> System.out.println(">> " + item));

  }

}

Podemos ver como sigue los conceptos básicos de un framework reactive, es decir, tiene Observable, transformaciones y suscriptores.  Lo interesante es cómo se construye el mensaje. Describimos una tubería de procesamiento que toma un item, lo procesa y finalmente lo consume.

Primero, creamos un Uni, uno de los dos tipos con Multi que proporciona Mutiny. Un Uni es un flujo que emite un solo elemento o un error.

Aquí, creamos un Uni que emite el elemento "hello". Esta es la entrada de nuestro pipeline. Luego procesamos este item:

  • agregamos "mutiny", luego
  • lo convertimos en una cadena en mayúsculas.
  • Esto forma la parte de procesamiento de nuestra canalización, y luego finalmente nos suscribimos a la canalización.


Esta última parte es fundamental. Si no tiene un suscriptor final, no sucederá nada. Los tipos de mutiny son perezosos, lo que significa que debes suscribirte. Si no lo hace, el cálculo ni siquiera comenzará.

Si su programa no hace nada, tenemos que verificar que no se nos olvidó de suscribirnos.

Dejo link : https://smallrye.io/smallrye-mutiny/ 

martes, 19 de octubre de 2021

Componer y transformar observables en RxJava


Los observables son especialmente buenos para ser compuestos y transformados. Con el uso de algunos operadores definidos en RxJava, puede componer y transformar secuencias de datos de una manera fácil que requiere poca codificación, por lo que es menos propenso a errores. 

map: permite transformar cada elemento de la secuencia emitida con una función específica.

flatMap: realiza dos tipos de acciones: la acción de "map" que transforma los elementos emitidos en observables y una acción de "aplanar" que convierte esos observables en uno observable. 

concatMap: el operador concatMap se comporta como flatMap, excepto que asegura que los observables no estén intercalados sino concatenados, manteniendo su orden.

zip: el operador zip toma múltiples observables como entradas y combina cada emisión a través de una función específica y emite los resultados de esta función como una nueva secuencia.

concat: concatena dos o más emisiones, generando una emisión donde todos los elementos de la primera fuente de emisión aparecen antes que los elementos de la segunda fuente de emisión. Además, el operador de concat espera a que se complete cada secuencia antes de suscribirse al siguiente observable.

filter: utiliza una función específica para permitir que solo se emitan algunos elementos de la secuencia de origen.

distinct: Si un elemento se emite más de una vez, solo se emitirá la primera aparición.

first: emite solo el primer elemento de una secuencia. Si se especifica una función, se utilizará para filtrar los elementos, por lo que solo se emitirá el primer elemento de la secuencia que cumpla las condiciones.

last: si puede aplicar un filtro al comienzo de la secuencia con el operador primero, también puede filtrar el final de la secuencia con el operador al final .

take: Toma el elemento que se encuentra en la posición n, lo que permite que solo se emitan los primeros n elementos.

startWith: toma la secuencia de entrada y le agrega un elemento determinado. Puede ser útil si desea forzar que su secuencia comience con un valor predeterminado o con uno almacenado en caché.

scan: el escaneo del operador toma una secuencia y aplica una función a cada par de elementos emitidos secuencialmente.