Aprendizaje de Spring Cloud Framework - Spring Cloud Stream

1. Introducción básica

Spring Cloud Stream es un marco para crear microservicios basados ​​en mensajes. En Spring Cloud Stream, se proporciona un enlace entre los microservicios y el middleware de mensajes.Este enlace se llama Binder, y Binder es responsable de interactuar con el middleware de mensajes. Y nuestros desarrolladores interactúan con Binder a través de canales de mensajes como entradas o salidas.

Spring Cloud Stream implementa mensajes controlados por eventos mediante el uso de Spring Integration para conectar el middleware del intermediario de mensajes, que es un producto de middleware de mensajes popular (Spring Cloud Stream es compatible de forma nativa con RabbitMQ, Kafka. Ali brinda soporte de RocketMQ de manera oficial) proporciona una implementación de configuración automatizada personalizada, citandopublicar-suscribir,grupo de consumidores,dividirtres conceptos básicos.

2. Pensamiento de diseño

Entonces, ¿cómo protege Spring Cloud Stream las diferencias subyacentes? Realiza el aislamiento entre la aplicación y los detalles del middleware del mensaje definiendo el aglutinante como la capa intermedia.

Descripción de Binder:
en ausencia del concepto de Binder, cuando las aplicaciones Spring Boot interactúan directamente con el middleware de mensajes, debido a las diferentes intenciones originales de cada middleware de mensajes, sus detalles de implementación serán diferentes. Esto se puede conseguir perfectamente definiendo los ligantes como capa intermediaAislamiento entre la aplicación y los detalles del middleware de mensajería. La encapsulación adicional del middleware de mensajes de Stream puede hacer que el nivel de código desconozca el middleware e incluso cambiar dinámicamente el middleware para realizar el desacoplamiento de microservicios y middleware de mensajes específicos, de modo que los microservicios puedan prestar más atención a su propio proceso comercial. Un diagrama esquemático de un marco para integrar programas Spring Cloud Stream, como se muestra en la siguiente figura:
inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
INPUT y OUTPUT en Binder Para Binder mismo,La ENTRADA corresponde al consumidor y la SALIDA corresponde al productor.. INPUT recibe mensajes enviados por productores de mensajes y OUTPUT envía mensajes a consumidores de mensajes para su consumo.

El diagrama de flujo comercial de los mensajes de procesamiento de Spring Cloud Stream es el siguiente:
inserte la descripción de la imagen aquí

  • Fuente y sumidero: se puede entender que el objeto de referencia es Spring Cloud Stream en sí mismo, la publicación de mensajes de Stream es la salida y la recepción de mensajes es la entrada. La fuente se usa para obtener datos (datos que se enviarán a MQ), el receptor se usa para proporcionar datos (para recibir datos enviados por MQ, proporcionar datos a los consumidores de mensajes)
  • Channel: Channel es una abstracción de Queue, que es el medio para realizar el almacenamiento y reenvío en el sistema de comunicación de mensajes. Se utiliza para almacenar los datos recibidos por la fuente o para almacenar los datos extraídos por el archivador.

3. Notas comunes

inserte la descripción de la imagen aquí

4. Primeros pasos sencillos

Cree un proyecto Maven y agregue tres dependencias a pom.xml: Web, Rabbitmq, Spring Cloud Stream. Las dependencias específicas que se introducirán:

   <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-amqp</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream-binder-rabbit</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.amqp</groupId>
            <artifactId>spring-rabbit-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-stream</artifactId>
            <scope>test</scope>
            <classifier>test-binder</classifier>
            <type>test-jar</type>
        </dependency>
    </dependencies>

Una vez que el proyecto se haya creado correctamente, agregue la información de configuración de RabbitMQ al archivo de configuración.

spring.rabbitmq.host=101.43.30.128
spring.rabbitmq.port=5672
spring.rabbitmq.username=
spring.rabbitmq.password=
spring.rabbitmq.virtual-host=/learn

Cree una clase MsgReceiver de receptor de mensajes simple:

//@EnableBinding 表示绑定 Sink 消息通道
@EnableBinding(Sink.class)
public class MsgReceiver {
    
    
    public final static Logger LOGGER = LoggerFactory.getLogger(MsgReceiver.class);

    @StreamListener(Sink.INPUT)
    public void receive(Object payload) {
    
    
        LOGGER.info(" MsgReceiver Received:" + payload.toString());
    }
}

Inicie el proyecto y luego cree una cola anónima en la página de administración en segundo plano de RabbitMQ para intentar enviar un mensaje.

inserte la descripción de la imagen aquí
inserte la descripción de la imagen aquí
Haga clic en el botón Publicar mensaje y vea la salida en segundo plano para comprobar que el mensaje se puede recibir con normalidad y consumir correctamente.

5. Canal de mensajes personalizado

Primero cree una interfaz llamada MyChannel y defina el canal del canal:

public interface MyChannel {
    
    
    String HELLO_INPUT = "hello-input";
    String HELLO_OUTPUT = "hello-output";

    @Output(HELLO_OUTPUT)
    MessageChannel output();

    @Input(HELLO_INPUT)
    SubscribableChannel input();
}
  1. Tenga en cuenta que los nombres de los dos canales de mensajes son diferentes
  2. A partir de la versión F, el nombre del canal se usa como comando de instancia por defecto, por lo que los nombres de los canales aquí no pueden ser los mismos (las versiones anteriores pueden ser
    las mismas), en este caso, para enviar y recibir mensajes normalmente , necesitamos hacer alguna
    configuración adicional en application.properties .
#消息绑定
spring.cloud.stream.bindings.hello-input.destination=hello-topic
spring.cloud.stream.bindings.hello-output.destination=hello-topic

A continuación, personalice un receptor de mensajes para recibir mensajes en su propio canal de mensajes:

@EnableBinding(MyChannel.class)
public class MsgReceiver2 {
    
    
    public final static Logger LOGGER = LoggerFactory.getLogger(MsgReceiver2.class);

    @StreamListener(MyChannel.HELLO_INPUT)
    public void receive(Object payload) {
    
    
        LOGGER.info("MsgReceiver receive2:" + payload);
    }
}

Crear una interfaz para probar el envío de mensajes.

@RestController
public class HelloController {
    
    

    @Autowired
    MyChannel myChannel;

    @GetMapping("/hello")
    public void hello(){
    
    
        myChannel.output().send(MessageBuilder.withPayload("hello spring cloud stream!").build());
    }
}

6. Agrupación de mensajes: tratamiento del consumo repetido de mensajes

De forma predeterminada, si el consumidor es un clúster, un mensaje se consumirá varias veces. Un ejemplo se muestra en la figura:
inserte la descripción de la imagen aquí

Podemos resolver este problema con la agrupación de mensajes. Agregue la siguiente configuración al proyecto Spring:

#消息分组
spring.cloud.stream.bindings.hello-input.group=g1
spring.cloud.stream.bindings.hello-output.group=g1

7. Partición de mensajes

La partición de mensajes permite que los mensajes con las mismas características siempre sean procesados ​​por la misma instancia. Agregar ejemplo de configuración:

#开启消息分区(消费者上配置)
spring.cloud.stream.bindings.hello-input.consumer.partitioned=true
# 消费者实例个数(消费者上配置)
spring.cloud.stream.instance-count=2
# 当前实例的下标(消费者上配置)
spring.cloud.stream.instance-index=0
# (生产者上配置)
spring.cloud.stream.bindings.hello-output.producer.partition-key-expression=1
# 消费端的节点数量(生产者上配置)
spring.cloud.stream.bindings.hello-output.producer.partition-count=2

Luego, use Maven para empaquetar el proyecto como un paquete jar

inserte la descripción de la imagen aquí

Inicie dos instancias en la consola. Tenga en cuenta que spring.cloud.stream.instance-index debe modificarse dinámicamente al iniciar.
inserte la descripción de la imagen aquí

java -jar stream-0.0.1-SNAPSHOT.jar --server.port=8080 --
spring.cloud.stream.instance-index=0
java -jar stream-0.0.1-SNAPSHOT.jar --server.port=8081 --
spring.cloud.stream.instance-index=1

Al llamar a la prueba de interfaz/hola, puede ver que el mismo mensaje se envía varias veces y que el mensaje lo procesa un solo consumidor.

8. Mensajes retrasados

RabbitMQ necesita instalar el complemento rabbitmq_delayed_message_exchange para enviar mensajes retrasados, dirección de descarga: https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/v3.8.0/rabbitmq_delayed_message_exchange-3.8.0.ez

8.1 Instalar el complemento

Tome la instalación de Docker como ejemplo:
Descargue el complemento

wget https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/releases/download/v3.8.0/rabbitmq_delayed_message_exchange-3.8.0.ez

Copie el archivo en el contenedor de Docker

docker cp rabbitmq_delayed_message_exchange-3.8.0.ez 900822f303cd:/opt/rabbitmq/plugins

Ingrese al contenedor RabbitMQ

docker exec -it 900822f303cd /bin/sh

Habilitar complemento

rabbitmq-plugins enable rabbitmq_delayed_message_exchange

Compruebe si el complemento se inició correctamente

rabbitmq-plugins list

Reinicie el contenedor RabbitMQ

8.2 Implementación Concreta

1. Configuración del archivo de configuración
Configure la función de retraso del mensaje de apertura del canal en el archivo de configuración

##开启消息延迟功能
spring.cloud.stream.rabbit.bindings.hello-input.consumer.delayed-exchange=true
spring.cloud.stream.rabbit.bindings.hello-output.producer.delayed-exchange=true

Modificar la definición de destino de los canales de entrada y salida de mensajes:

spring.cloud.stream.bindings.hello-input.destination=delay_msg
spring.cloud.stream.bindings.hello-output.destination=delay_msg

2. Crear una prueba de interfaz

@RestController
public class HelloController {
    
    

    public final static Logger LOGGER = LoggerFactory.getLogger(HelloController.class);


    @Autowired
    MyChannel myChannel;

    @GetMapping("/hello")
    public void hello(){
    
    
        myChannel.output().send(MessageBuilder.withPayload("hello spring cloud stream!").build());
    }


    @GetMapping("/delay-hello")
    public void delayHello(){
    
    
        LOGGER.info("send msg:" + new Date());
        myChannel.output().send(MessageBuilder.withPayload("hello spring cloud stream!").setHeader("x-delay", 5000).build());
    }
}

La prueba puede encontrar que el mensaje se retrasa durante 5 segundos antes del consumo.

inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/huangjhai/article/details/122762502
Recomendado
Clasificación