【2023】 Introducción básica e implementación de código de RabbitMQ (1)

1. Conceptos relacionados de MQ

1.1 ¿Qué es MQ?

MQ (cola de mensajes), literalmente, es una cola, FIFO primero en entrar, primero en salir, pero el contenido almacenado en la cola son solo mensajes, y también es un mecanismo de comunicación entre procesos para la transmisión de mensajes ascendentes y descendentes. En la arquitectura de Internet, MQ es un servicio de comunicación de mensajes de "desacoplamiento lógico + desacoplamiento físico" ascendente y descendente muy común. Después de usar MQ, el envío de mensajes ascendentes solo debe depender de MQ, no de otros servicios.

1.2 ¿Por qué utilizar MQ?

1. Eliminación de picos de tráfico

Por ejemplo, si el sistema de pedidos puede manejar hasta 10,000 pedidos, esta capacidad de procesamiento es más que suficiente para manejar pedidos durante períodos normales. Durante períodos normales, podemos devolver resultados en un segundo después de realizar el pedido. Sin embargo, durante el período pico, si se realizan 20.000 pedidos, el sistema operativo no puede manejarlos y solo puede limitar el número de pedidos que superan los 10.000 y evitar que los usuarios realicen pedidos. Usando la cola de mensajes como buffer, podemos cancelar esta restricción y distribuir los pedidos realizados dentro de un segundo en un período de tiempo para su procesamiento. En este momento, es posible que algunos usuarios no reciban la operación de pedido exitosa más de diez segundos después de realizar el pedido. pero es mejor que no poder realizar el pedido, la experiencia única es mejor.

2. Desacoplamiento de aplicaciones

Tomando como ejemplo las aplicaciones de comercio electrónico, existen sistemas de pedidos, sistemas de inventario, sistemas de logística y sistemas de pago en las aplicaciones. Después de que el usuario crea un pedido, si el sistema de inventario, el sistema de logística y el sistema de pago están acoplados y llamados, si algún subsistema falla, la operación del pedido será anormal. Cuando se convierte a un enfoque basado en colas de mensajes, los problemas de las llamadas entre sistemas se reducirán considerablemente. Por ejemplo, un sistema logístico tardará unos minutos en repararse debido a una falla. Durante estos pocos minutos, la memoria que será procesada por el sistema logístico se almacena en caché en la cola de mensajes y la operación del pedido del usuario se puede completar normalmente. Cuando se restablezca el sistema logístico, simplemente continúe procesando la información del pedido y los usuarios a mitad del pedido no sentirán la falla del sistema logístico, lo que mejora la disponibilidad del sistema.
Insertar descripción de la imagen aquí

3. Procesamiento asincrónico

Algunas llamadas entre servicios son asincrónicas. Por ejemplo, A llama a B y B tarda mucho en ejecutarse, pero A necesita saber cuándo se puede completar B. En el pasado, generalmente había dos formas: A llamaría a la API de consulta de B. consulta después de un período de tiempo. O A proporciona una API de devolución de llamada y B llama a la API para notificar al servicio A después de la ejecución. Ambos métodos no son muy elegantes. El uso del bus de mensajes puede resolver fácilmente este problema. Después de que A llama al servicio B, solo necesita monitorear el mensaje que B ha completado. Cuando B completa el procesamiento, enviará un mensaje a MQ y MQ reenviarán este mensaje al servicio A. De esta manera, el servicio A no necesita llamar a la API de consulta de B en un bucle, ni necesita proporcionar una API de devolución de llamada. De manera similar, el servicio B no necesita realizar estas operaciones. Un servicio también puede recibir a tiempo el mensaje de éxito del procesamiento asincrónico.
Insertar descripción de la imagen aquí

Productos MQ comunes
ActiveMQ: basado en JMS RabbitMQ: basado en el protocolo AMQP, desarrollado en lenguaje erlang, buena estabilidad
RocketMQ: basado en JMS, producto de Alibaba, actualmente entregado a la Fundación Apache
Kafka: sistema de mensajería distribuida, alto rendimiento
Inicio rápido de RabbitMQ
RabbitMQ es una cola de mensajes desarrollada en lenguaje Erlang e implementada en base al protocolo AMQP (Protocolo avanzado de cola de mensajes avanzada). Es un método de comunicación entre aplicaciones. La cola de mensajes se usa ampliamente en el desarrollo de sistemas distribuidos. Dirección oficial de RabbitMQ: http://www.rabbitmq.com

Descargar e instalar

RabbitMQ está desarrollado en lenguaje Erlang. Debe instalar el entorno de lenguaje Erlang correspondiente a la versión RabbitMQ. No explicaré los detalles. Busque tutoriales usted mismo. Dirección de descarga del sitio web oficial de RabbitMQ: http://www.rabbitmq.com/download.html

1.3 Principio de funcionamiento de RabbitMQ

La siguiente figura es la estructura básica de RabbitMQ:
Insertar descripción de la imagen aquí
1.
Mensaje de mensaje, el mensaje no es específico, consta de un encabezado de mensaje y un cuerpo de mensaje. El cuerpo del mensaje es opaco y el encabezado del mensaje consta de una serie de atributos opcionales,
que incluyen clave de enrutamiento (clave de enrutamiento), prioridad (prioridad relativa a otros mensajes), modo de entrega (que indica que el mensaje puede requerir almacenamiento persistente), etc.
2.
El productor del mensaje del publicador también es una aplicación cliente que publica mensajes en el intercambio.
3.
Intercambiador de intercambio, utilizado para recibir mensajes enviados por los productores y enrutarlos a la cola en el servidor. .4 Enlace
vinculante
, utilizado para la asociación entre la cola de mensajes y el intercambiador. Un enlace es una regla de enrutamiento que conecta un intercambiador y una cola de mensajes en función de una clave de enrutamiento, por lo que
el intercambiador puede entenderse como una tabla de enrutamiento compuesta de enlaces.
5.
Cola de mensajes en cola, que se utiliza para guardar mensajes hasta que se envían a los consumidores. Es el contenedor de mensajes y el punto final de los mensajes. Un mensaje se puede poner en una o más colas.
El mensaje ha estado en la cola, esperando que el consumidor se conecte a la cola para recogerlo.

Si hay varios consumidores escuchando la misma cola al mismo tiempo, utilizarán el sondeo para consumir los mensajes de la cola. Si alguien sale en el medio, los consumidores restantes consumirán los mensajes de la cola.

Crear fábrica de conexiones

public static ConnectionFactory getFactory(){
    
    
    //        创建连接工厂
    ConnectionFactory factory = new ConnectionFactory();
    factory.setUsername("root");
    //tcp连接端口
    factory.setPort(5672);
    factory.setPassword("root");
    factory.setHost("192.168.204.129");
    return factory;
}
  • Crear una conexión (enviar directamente sin usar un conmutador)

    Productor:

    private static void getConnectionFactory(){
          
          
            ConnectionFactory factory = FactoryUtil.getFactory();
            try {
          
          
    //            创建连接
                Connection conn = factory.newConnection();
    //            获得信道
                 Channel channel = conn.createChannel();
    //            声明队列
                channel.queueDeclare("myQueue",true,false,false,null);
                String message = "hello,rabbitmq....."+new Date();
    //          发送消息到指定队列(交换机,路由键(队列名),属性,消息内容字节流)
                channel.basicPublish("","myQueue",null,message.getBytes());
                System.out.println("消息已经发送"+new Date());
                channel.close();
                conn.close();
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
    
        }
    

    consumidor

    public static void getReciver(){
          
          
    //        连接工厂对象
            ConnectionFactory factory = FactoryUtil.getFactory();
            //创建连接
            try {
          
          
                Connection conn = factory.newConnection();
    //            通道
                Channel channel = conn.createChannel();
    //            声明队列
                channel.queueDeclare("myQueue",true,false,false,null);
    //            消费消息--队列名,自动确认,消费者
                channel.basicConsume("myQueue", true, new DefaultConsumer(channel) {
          
          
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
          
          
                        System.out.println("接受到消息:"+new String(body,"utf-8"));
                    }
                });
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
        }
    

Exchange: cree una conexión mediante un conmutador

Insertar descripción de la imagen aquí

Tambien puede utilizar esta constante para declarar el modo de envio:BuiltinExchangeType

  • Modo directo

    • ** Maneja claves de enrutamiento. **Requiere que una cola esté vinculada a un intercambio** requiere que el mensaje coincida exactamente con una clave de enrutamiento específica. **Esta es una coincidencia completa. Si una cola está vinculada al conmutador y requiere la clave de enrutamiento "perro", solo se reenviarán los mensajes marcados como "perro". No se reenviará Dog.puppy, ni se reenviará dog.guard, solo se reenviará dog. reenviado.

    Productor:

    /**
         *@Description//TODO Direct模型
    *@Date2022/8/8 16:29
         **/
    private static void getSender(){
          
          
            ConnectionFactory factory = FactoryUtil.getFactory();
            try {
          
          
                Connection conn = factory.newConnection();
                Channel channel = conn.createChannel();
                //声明交换机--交换机名称,类型,持久化
                channel.exchangeDeclare("directExchange","direct",true);
    //           发送消息
                String message = "hello...direct exchagne..."+new Date();
    //            交换机,指定的路由键,属性,消息内容字节流
                channel.basicPublish("directExchange",**"green"**,null,message.getBytes());
                System.out.println("消息发送成功....");
                channel.close();
                conn.close();
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
        }
    

    consumidor:

     public static void getReciver(){
          
               
      //        连接工厂对象
            ConnectionFactory factory = FactoryUtil.getFactory();
            //创建连接
            try {
          
          
                Connection conn = factory.newConnection();
    //            通道
                Channel channel = conn.createChannel();
    //            声明队列
                channel.queueDeclare("direqueue1",true,false,false,null);
    //            声明交换机(交换机名,交换类型(需要全小写),是否声明为持久层)
                channel.exchangeDeclare("directExchange",***"direct"***,true);
    //            绑定交接机(队列,交换机,用于绑定的路由键(子会接收路由键相同的消息))
                channel.queueBind("direqueue1","directExchange",**"green"**);
    //            消费消息--队列名,自动确认,消费者
                channel.basicConsume("direqueue1", true, new DefaultConsumer(channel) {
          
          
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
          
          
                        System.out.println("DirectReciver1接收到消息:"+new String(body,"utf-8"));
                    }
                });
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
        }
    
  • Modo de transmisión en abanico

    • Las claves de enrutamiento no se procesan . Simplemente vincula la cola al conmutador. Un mensaje enviado a un conmutador se reenviará a todas las colas vinculadas al conmutador . Al igual que una transmisión de subred, cada host de la subred recibe una copia del mensaje. El conmutador Fanout reenvía los mensajes más rápido

      Productor:

    /**
         *@Description//TODO Fanout模型-会发送给交换机中的所以队列
    *@Date2022/8/8 16:29
         **/
    private static void getSender(){
          
          
            ConnectionFactory factory = FactoryUtil.getFactory();
            try {
          
          
                Connection conn = factory.newConnection();
                Channel channel = conn.createChannel();
                //声明交换机--交换机名称,类型,持久化
                channel.exchangeDeclare("fanoutExchange","fanout",true);
    //           发送消息
                String message = "hello...fanout exchagne..."+new Date();
    //            交换机,不用指定路由键,属性,消息内容字节流
                channel.basicPublish("fanoutExchange","",null,message.getBytes());
                System.out.println("fanoutExchange消息发送成功....");
                channel.close();
                conn.close();
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
        }
    

    consumidor:

       public static void getReciver(){
          
               
    //        连接工厂对象
            ConnectionFactory factory = FactoryUtil.getFactory();
            //创建连接
            try {
          
          
                Connection conn = factory.newConnection();
    //            通道
                Channel channel = conn.createChannel();
    //            声明队列
                channel.queueDeclare("fanout1",true,false,false,null);
    //            声明交换机
                channel.exchangeDeclare("fanoutExchange","fanout",true);
    //            绑定交接机(队列,交换机,用于绑定的路由键)
                channel.queueBind("fanout1","fanoutExchange","green");
    //            消费消息--队列名,自动确认,消费者
                channel.basicConsume("fanout1", true, new DefaultConsumer(channel) {
          
          
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
          
          
                        System.out.println("FanoutReciver1接收到消息:"+new String(body,"utf-8"));
                    }
                });
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
        }
    
  • modo tema

    • El productor envía los datos al conmutador y establece una clave de enrutamiento específica; el consumidor recibe los mensajes en la cola que cumplen las condiciones según el comodín de la cola.

      • : representa 1 palabra

      #: representa de 0 a más

    Productor:

    /**
         *@Description//TODO Topic模型-
    *@Date2022/8/8 16:29
         **/
    private static void getSender(){
          
          
            ConnectionFactory factory = FactoryUtil.getFactory();
            try {
          
          
                Connection conn = factory.newConnection();
                Channel channel = conn.createChannel();
                //声明交换机--交换机名称,类型,持久化
                channel.exchangeDeclare("topicExchange", BuiltinExchangeType.TOPIC,true);
    //           发送消息
                String message = "hello...fanout exchagne..."+new Date();
    //            交换机,不用指定路由键,属性,消息内容字节流
                channel.basicPublish("topicExchange","aa.bb.zez",null,message.getBytes());
                System.out.println("fanoutExchange消息发送成功....");
                channel.close();
                conn.close();
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
        }
    

    consumidor:

       
     public static void getReciver(){
          
           
            //        连接工厂对象
            ConnectionFactory factory = FactoryUtil.getFactory();
            //创建连接
            try {
          
          
                Connection conn = factory.newConnection();
    //            通道
                Channel channel = conn.createChannel();
    //            声明队列
                channel.queueDeclare("topic3",true,false,false,null);
    //            声明交换机
                channel.exchangeDeclare("topicExchange", BuiltinExchangeType.TOPIC,true);
    //            绑定交接机(队列,交换机,用于绑定的路由键)
                channel.queueBind("topic3","topicExchange","*.bb.#");
    //            消费消息--队列名,自动确认,消费者
                channel.basicConsume("topic3", true, new DefaultConsumer(channel) {
          
          
                    @Override
                    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
          
          
                        System.out.println("topicExchange3接收到消息:"+new String(body,"utf-8"));
                    }
                });
            } catch (IOException e) {
          
          
                e.printStackTrace();
            } catch (TimeoutException e) {
          
          
                e.printStackTrace();
            }
    

Transacción:

Cuando un productor envía un mensaje, se puede utilizar una transacción para garantizar la atomicidad del envío.

  • Iniciar una transacción:channel.txSelect();
  • Enviar transacción:channel.txCommit();

Habilitar confirmación de escucha:

Modo de sincronización:

  • Active el modo de confirmación de monitoreo:channel.confirmSelect();
  • Ejecutar confirmación de monitoreo:channel.waitForConfirmsOrDie();

Modo asíncrono:

Este modo realizará el monitoreo de manera asincrónica para determinar cuáles tienen éxito y cuáles fallan, si fallan se volverán a ejecutar y enviar.

/**
     *@Description//TODO currentTimeMillis启用发布者确认使用异步执行,该
*@Date2022/8/8 16:29
     **/
private static void getSender(){
    
    
        ConnectionFactory factory = FactoryUtil.getFactory();
        try {
    
    
            Connection conn = factory.newConnection();
            Channel channel = conn.createChannel();
            //声明交换机--交换机名称,类型,持久化
            channel.exchangeDeclare("transExchange", BuiltinExchangeType.DIRECT,true);
//              启用发布者确认模式
            channel.confirmSelect();
            long l = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
    
    
//           发送消息
            String message1 = "hello...direct exchagne1..."+i;
//            交换机,指定的路由键,属性,消息内容字节流
            channel.basicPublish("transExchange","trans",null,message1.getBytes());
            }
//            执行监听确认
            channel.addConfirmListener(new ConfirmListener() {
    
    
//                确认消息
                @Override
                public void handleAck(long deliveryTag, boolean multiple) throws IOException {
    
    
                    System.out.println("确认消息****:"+deliveryTag+",状态:"+multiple);
                }
//              未确认
                @Override
                public void handleNack(long deliveryTag, boolean multiple) throws IOException {
    
    
                    System.err.println("未消息####:"+deliveryTag+",状态:"+multiple);
                }
            });
            long j = System.currentTimeMillis();
            System.out.println("消息使用时间---"+(j-l));
//            channel.close();
//            conn.close();
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

Supongo que te gusta

Origin blog.csdn.net/weixin_52315708/article/details/131725030
Recomendado
Clasificación