Introducción y ejemplo de procesar mensajes con Spring Cloud Stream
Escrito por
picodotdev el .
java
planeta-codigo
Enlace permanente
Comentarios
Las aplicaciones distribuidas emplean comunicación basada en mensajes para lograr un intercambio asíncrono y desacoplado entre servicios. Spring Kafka ofrece una integración directa con Apache Kafka mediante la anotación KafkaListener y KafkaTemplate, sin embargo, cuando los mensajes fluyen entre múltiples topics, esta aproximación de bajo nivel se vuelve compleja. Spring Cloud Stream resuelve este problema simplificando el modelo de desarrollo al usar las interfaces funcionales de Java, Consumer, Function y Supplier para modelar consumidores, procesadores y productores de forma agnística al broker de mensajes, declarativa y altamente configurable.
Las aplicaciones distribuidas suelen emplear mecanismos de comunicación basados en mensajes. La comunicación basada en mensajes tiene la particularidad deseable en algunos casos de ser una forma de comunicación asíncrona y desacoplada entre el productor del mensaje y el consumidor del mensaje. Esto hace a las aplicaciones procesadores de un flujo o stream constante de mensajes.
Entre las muchas librerías que ofrece el framework de Spring está la integración con el sistema de mensajería de Apache Kafka. Esta librería permite el consumo y producción de mensajes de los topics. Con la anotación KafkaListener se define el punto de entrada en el código de los mensaje de Kafka, con la clase KafkaTemplate permite hacer el envío de mensajes.
Algunas aplicaciones no solo escriben y leen de un topic de Kafka, los mensajes siguen un flujo de procesamiento entre varios topics. Por otro lado, la librería de Spring Kafka ofrece una integración a bajo nivel que se vuelve compleja en integraciones con varios consumidores y productores. Spring Cloud Stream simplifica el modelo de desarrollo de Spring Kafka, al mismo tiempo que lo hace más configurable.
Contenido del artículo
Spring Cloud Stream
Spring Cloud Stream permite en las aplicaciones de Spring utilizar las interfaces funcionales de Java como Consumer, Function y Supplier para modelar consumidores, procesadores y productores de mensajes.
Otra de sus propiedades es que permite la integración con diferentes tipos de sistemas de mensajería como Kafka o RabbitMQ con cambios mínimos en el código, ya que el modelo de programación está basado en interfaces estándar de Java agnósticas de los brokers de menesajes.
Conceptos
Binding
Las instancias de interfaces funcionales que procesan mensajes de Kafka se denominan bindings. No son más que un bean de Spring que implementa una de las interfaces funcionales.
Estas definiciones de bean junto con cierta configuración para definir de que topics leen los mensajes y en cual se escriben permiten el procesado de los mensajes. Las propiedades destination determinan de que topics se leen los mensajes y escriben los mensajes.
|
|
|
|
Binding names
El nombre del método de la interfaz funcional determina el nombre del binding. Con cierta convención en los nombres se establecen las propiedades de configuración específica en cada uno de los bindings. El nombre del binding está determinado por el nombre de la funció, in y out corresponding al tipo del binding y finalmente un índice que suele ser 0 para la función típica con un solo elemento de entrada y de salida.
|
|
|
|
Es posible dar un nombre personalizado al binding y establecer las propiedades de configuración usando ese nuevo nombre.
|
|
Binder
Los binder son los sistemas de mensajería con los que se integran los bindings. Hay varios, uno de ellos es Kafka pero también están RabbitMQ y Apache Pulsar.
Propiedades de configuración
Buena parte del uso de Spring Cloud Streams se realiza en las propiedades de configuración. Se pueden establecer propiedades de configuración que afectan a todos los consumidores y productores o un consumidor o productor específico. Y propiedades específicas del binder.
La lista completa de propiedades que permiten los consumidores y productores de Kafka son las siguientes.
Binder
Con la siguientes propiedades se especifica la configuración de conexión a los brokers de Kafka.
|
|
Consumer
En el consumidor es posible querer especificar el serializer y deserializer de los mensajes, la configuración de procesamiento en batches o el grupo del consumidor en caso de varias instancias.
|
|
Producer
En el productor también es posible especificar el serializer para la key y value del mensaje de Kafka, usando las propiedades de Kafka para los productores. Hay otras propiedades que definen Spring Cloud Stream.
Gestión de errores
Por defecto, la gestión de errores al procesar un mensaje es loggearlo y descartar. Es posible implementar handlers personalizados en caso de errores, basta con definir un consumer de ErrorMessage.
|
|
|
|
En caso de no querer descartar un mensaje cuando falla su procesamiento es posible enviarlo a un topic especial con el patrón dead-letter-queue para su revisión y posterior procesamiento. La siguiente configuración crea un topic automáticamente para el consumidor.
|
|
Con la siguiente propiedad se configura el número máximo de intentos de procesado antes de enviarlo al topic dead-letter-queue. En este ejemplo el procesado se realiza 3 veces.
|
|
Observabilidad
Para implementar métricas de observabilidad hay que añadir las siguientes dependencias y la aplicación se autoconfigura.
|
|
Pruebas unitarias
Spring Cloud Stream ofrece la posibilidad de probar de forma unitaria a los consumidores y productores. Ya sea la función directamente o como un binding de Spring Cloud Stream.
|
|
El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando siguiente comando:./gradlew run