Quick start of MQ and five working modes of RabbitMQ

Table of contents

Basic knowledge of MQ

Basic concepts of MQ

MQ overview

Advantages and Disadvantages of MQ

Advantage

disadvantage

Introduction to RabbitMQ

infrastructure

Related concepts

JMS

RabbitMQ installation

Pull the image online

Install MQ

Access the console (http://ip address: 15672)

Operating mode

Simple mode (producer consumer mode)

Work Queues work queue mode

Pub/Sub subscription model

Routing routing mode

Topics wildcard pattern

Springboot integrates RabbitMQ


Basic knowledge of MQ

Basic concepts of MQ

The full name of MQ is Message Queue (message queue), which is a container for storing messages during message transmission. It is mostly used for communication between distributed systems.

MQ overview

  • MQ, message queue, middleware for storing messages

  • There are two ways of distributed system communication: direct remote call and indirect communication with the help of a third party

  • The sender is called the producer and the receiver is called the consumer

Advantages and Disadvantages of MQ

Advantage

  • Application decoupling

    When we place an order directly through the order system, we will perform a series of operations, such as consulting the inventory system to check whether the corresponding product has sufficient inventory. If the inventory system is down at this time, the entire system will be paralyzed

  • Use MQ to decouple applications, improve fault tolerance and maintainability. The order system is directly connected to the middleware MQ at this time, even if the subsequent system is paralyzed, the order system will not be paralyzed

  • Asynchronous speed up

Time-consuming for an order: 20 + 300 + 300 + 300 = 920ms. After the user clicks the order button, they need to wait 920ms to get the order response, which is too slow!

After using MQ, after the user clicks the order button, he only needs to wait 25ms to get the order response (20 + 5 = 25ms). Improve user experience and system throughput (the number of requests processed per unit time).

  • Shaving peaks and filling valleys

When faced with a large number of concurrent requests in an instant, the system may crash directly

After the introduction of MQ, a large number of requests can be buffered into MQ first, and then slowly send requests to the system through MQ, so as to achieve the effect of peak shaving and valley filling

disadvantage

  • reduced system availability,

    The more external dependencies the system introduces , the worse the system stability will be . Once MQ goes down, it will affect the business. How to ensure the high availability of MQ?

  • Increased system complexity

    The addition of MQ has greatly increased the complexity of the system . In the past, there were synchronous remote calls between systems, but now asynchronous calls are made through MQ. How to ensure that messages are not consumed repeatedly? How to deal with message loss? So to ensure the order of message delivery?

  • consistency problem

    System A finishes processing the business, and sends message data to the three systems B, C, and D through MQ. If the processing is successful in the systems B and C, the processing in the system D fails. How to ensure the consistency of message data processing ?

Introduction to RabbitMQ

In 2007, RabbitMQ 1.0 developed by Rabbit Technology Company based on the AMQP standard was released. RabbitMQ is developed in Erlang language. The Erlang language was designed by Ericson, a language specially developed for the development of highly concurrent and distributed systems, and is widely used in the telecommunications field.

infrastructure

Related concepts

  • Broker : The application for receiving and distributing messages, RabbitMQ Server is Message Broker

  • Virtual host : Designed for multi-tenancy and security factors, the basic components of AMQP are divided into a virtual group, similar to the namespace concept in the network. When multiple different users use the services provided by the same RabbitMQ server, multiple vhosts can be divided, and each user creates an exchange/queue in his own vhost, etc.

  • Connection : TCP connection between publisher/consumer and broker

  • Channel : If a Connection is established every time RabbitMQ is accessed, the overhead of establishing a TCP Connection when the message volume is large will be huge and the efficiency will be low. Channel is a logical connection established inside the connection. If the application supports multi-threading, usually each thread creates a separate channel for communication. AMQP method includes the channel id to help the client and message broker identify the channel, so the channels are completely isolated of. As a lightweight Connection, Channel greatly reduces the overhead of the operating system to establish a TCP connection

  • Exchange : The message arrives at the first stop of the broker, according to the distribution rules, matches the routing key in the query table, and distributes the message to the queue. Commonly used types are: direct (point-to-point), topic (publish-subscribe) and fanout (multicast)

  • Queue : The message is finally sent here and waits for the consumer to pick it up

  • Binding : virtual connection between exchange and queue, binding can contain routing key. Binding information is stored in the query table in the exchange for the basis of message distribution

    JMS

    1. JMS is the Java Message Service (JavaMessage Service) application programming interface, which is an API for message-oriented middleware in the Java platform

    2. JMS is one of the JavaEE specifications, analogous to JDBC

    3. Many message middleware implement the JMS specification, for example: ActiveMQ. RabbitMQ does not officially provide JMS implementation packages, but the open source community has

RabbitMQ installation

Pull the image online

docker pull rabbitmq:3-management

Install MQ

Execute the following command to run the MQ container:

docker run \
 -e RABBITMQ_DEFAULT_USER=itcast \
 -e RABBITMQ_DEFAULT_PASS=123321 \
 --name mq \
 --hostname mq1 \
 -p 15672:15672 \
 -p 5672:5672 \
 -d \
 rabbitmq:3-management

Access the console ( http://ip address:15672 )

Operating mode

There are five working modes: simple mode, work queues, Publish/Subscribe publishing and subscription mode, Routing routing mode, Topics theme mode

Strictly speaking, RPC does not belong to the working mode of RabbitMq, and no induction is made here ( RabbitMQ: easy to use, flexible messaging and streaming — RabbitMQ )

Simple mode (producer consumer mode)

  • P: Producer, that is, the program to send the message

  • C: Consumer: The receiver of the message will always wait for the message to arrive

  • queue: message queue, the red part in the figure. Similar to a mailbox, messages can be cached; producers post messages to it, and consumers take messages from it

producer

ConnectionFactory connectionFactory = new ConnectionFactory();
   //rabbitmq服务的ip地址
   connectionFactory.setHost("192.168.101.133");
   connectionFactory.setPort(5672);
   //连接的虚拟机
   connectionFactory.setVirtualHost("/itcast");
   //用户名
   connectionFactory.setUsername("heima");
   //密码
   connectionFactory.setPassword("heima");
   //建立连接
   Connection connection = connectionFactory.newConnection();
   //再从连接中创建channel建立真正的连接
   Channel channel = connection.createChannel();
​
/**   
队列声明
AMQP.Queue.DeclareOk queueDeclare(String queue, boolean durable, boolean exclusive, boolean autoDelete,
   Map<String, Object> arguments)
 1. queue: 队列名称
 2.durable:是否持久化,如果不持久化,mq重启之后队列就不存在了
 3. exclusive:是否独占。只能有一个消费者监听这队列
 当Connection关闭时,是否删除队列
 4.autoDelete:是否自动删除。当没有Consumer时,自动删除掉
 5.arguments: 参数。
 */
 channel.queueDeclare("hello_world",true,false,false,null);
//发送的消息
 String body="hello rabbitmq~~~~";
/**
 void basicPublish(String exchange, String routingKey, BasicProperties props, byte[] body)
 1.exchange:交换机名称。简单模式下交换机会使用默认的""
 2.routingKev: 路由名称,简单模式下就是队列名称
 3.props: 配置信息
 4.body: 发送消息数据
 */
   channel.basicPublish("","hello_world",null,body.getBytes());
   //释放资源
   channel.close();
   connection.close();

consumer

ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.101.133");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/itcast");
connectionFactory.setUsername("heima");
connectionFactory.setPassword("heima");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("hello_world",true,false,false,null);
Consumer consumer =new DefaultConsumer(channel){
/**
            回调方法,当收到消息后,会自动执行该方法
          1.consumerTag:标识
          2.envelope: 获取一些信息,交换机,路由key...2.
          3.properties:配置信息
          4.body: 数据
          */
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("consumerTag:"+consumerTag);
        System.out.println("Exchange:"+envelope.getExchange());
        System.out.println("consumerTag:"+consumerTag);
        System.out.println("bodys:"+new String(body));
    }
};
 /**
        basicConsume(string queue, boolean autoAck, Consumer callback)参数:
        1. queue:队列名称
        2.autoAck: 是否自动确认
        calLback: 回调对象,对获取到的消息进行处理
         */
channel.basicConsume("hello_world",true,consumer);

Work Queues work queue mode

  • Work Queues : Compared with the simple mode of the starter program, there are one or more consumers, and multiple consumers consume messages in the same queue together. Multiple consumers are in a competitive relationship, because the same message can only be consumed by one consumer

  • Application scenario: Using the work queue can improve the speed of task processing when the task is too heavy or there are many tasks. For example: multiple SMS service deployments only need one node to send successfully

producer

ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.101.133");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/itcast");
connectionFactory.setUsername("heima");
connectionFactory.setPassword("heima");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
channel.queueDeclare("work_queues",true,false,false,null);
for (int i = 0; i < 10; i++) {
    String body="hello rabbitmq~~~~"+i;
    channel.basicPublish("","work_queues",null,body.getBytes());
}
​
//释放资源
channel.close();
connection.close();

The code of the consumer is the same as that of the simple mode, and will not be displayed repeatedly. We can see that the same message will only be consumed once by the consumer, and the two consumers are in a competitive relationship. The polling consumption method is adopted

Pub/Sub subscription model

In the subscription model, there is an additional Exchange role, and the process changes slightly: that is, the producer forwards the message to the switch, and the switch distributes the message route to different queues, and the consumer listens to different queues to obtain messages

  • Exchange : Exchange (X). On the one hand, receive messages sent by producers. On the other hand, knowing how to process the message, such as delivering it to a particular queue, delivering it to all queues, or discarding the message. How it works depends on the type of Exchange.

    There are three common types of Exchange:

    Fanout : Broadcast, deliver the message to all queues bound to the exchange

    Direct : directional, deliver the message to the queue matching the specified routing key

    Topic : wildcard, send the message to the queue that matches the routing pattern (routing pattern)

    Exchange (exchange) is only responsible for forwarding messages, and does not have the ability to store messages , so if there is no queue bound to Exchange, or there is no queue that meets the routing rules, then the message will be lost!

    producer

     ConnectionFactory connectionFactory = new ConnectionFactory();
            //rabbitmq服务的ip地址
            connectionFactory.setHost("192.168.101.134");
            connectionFactory.setPort(5672);
            //连接的虚拟机
            connectionFactory.setVirtualHost("/itcast");
            //用户名
            connectionFactory.setUsername("heima");
            //密码
            connectionFactory.setPassword("heima");
            //建立连接
            Connection connection = connectionFactory.newConnection();
            //再从连接中创建channel建立真正的连接
            Channel channel = connection.createChannel();
            /**
             Exchange.DeclareOk exchangeDeclare(String exchange,
             BuiltinExchangeType type,
             boolean durable,
             boolean autoDelete,
             boolean internal,
             Map<String, Object> arguments) throws IOException;
             exchange:交换机名称
             type:交换机类型
             DIRECT("direct"),:定向
             FANOUT(“fanout"),:广播,发送消息到每一个与之绑定队列。
             TOPIC(“topic"),通配符的方式
             HEADERS(“headers");参数匹配
             3.durable:是否持久化
             4. autoDelete:是否自动删除
             5.参数列表
             */
            //创建交换机
            String  exchangeName="test_fanout";
            channel.exchangeDeclare(exchangeName, BuiltinExchangeType.FANOUT,true,false,false,null);
            //创建队列
            String queue1Name="test_fanout_queue1";
            String queue2Name="test_fanout_queue2";
            channel.queueDeclare(queue1Name,true,false,false,null);
            channel.queueDeclare(queue2Name,true,false,false,null);
            channel.queueBind(queue1Name,exchangeName,"");
            channel.queueBind(queue2Name,exchangeName,"");
    String body="日志信息,rabbitmq瘫痪了!!!";
    channel.basicPublish(exchangeName,"",null,body.getBytes());
            //释放资源
            channel.close();
            connection.close();

    Two consumers only need to change the listening queue

    ConnectionFactory connectionFactory = new ConnectionFactory();
    connectionFactory.setHost("192.168.101.134");
    connectionFactory.setPort(5672);
    connectionFactory.setVirtualHost("/itcast");
    connectionFactory.setUsername("heima");
    connectionFactory.setPassword("heima");
    Connection connection = connectionFactory.newConnection();
    Channel channel = connection.createChannel();
    ​
    Consumer consumer =new DefaultConsumer(channel){
     /**
        回调方法
      */
        @Override
        public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
            System.out.println("bodys:"+new String(body));
            System.out.println("将日志打印在控制台");
        }
    };
    String queue1Name="test_fanout_queue1";
    ​
    channel.basicConsume(queue1Name,true,consumer);

    We will find the subscription mode. The same message will be distributed to two queues so that different microservices can perform different business processing on the same message. For example, after the same message in the figure is obtained by different consumers, the operations are different. of

 

Routing routing mode

In the routing mode, the binding between the queue and the switch cannot be arbitrarily bound , but a RoutingKey must be specified . Exchange judges based on the Routing Key of the message. Only when the RoutingKey of the queue is exactly the same as the Routing Key of the message will it receive the message. message, and the consumer must first specify the Routing Key of the message when sending the message. We can specify the Routing Key to determine that this message allows different microservices to perform specified operations.

producer

ConnectionFactory connectionFactory = new ConnectionFactory();
        //rabbitmq服务的ip地址
        connectionFactory.setHost("192.168.101.134");
        connectionFactory.setPort(5672);
        //连接的虚拟机
        connectionFactory.setVirtualHost("/itcast");
        //用户名
        connectionFactory.setUsername("heima");
        //密码
        connectionFactory.setPassword("heima");
        //建立连接
        Connection connection = connectionFactory.newConnection();
        //再从连接中创建channel建立真正的连接
        Channel channel = connection.createChannel();
​
        //创建交换机
        String  exchangeName="test_direct";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.DIRECT,true,false,false,null);
        //创建队列
        String queue1Name="test_direct_queue1";
        String queue2Name="test_direct_queue2";
        channel.queueDeclare(queue1Name,true,false,false,null);
        channel.queueDeclare(queue2Name,true,false,false,null);
        //队列绑定交换机,并指定Routing key
        channel.queueBind(queue1Name,exchangeName,"error");
        channel.queueBind(queue2Name,exchangeName,"info");
        channel.queueBind(queue2Name,exchangeName,"error");
        channel.queueBind(queue2Name,exchangeName,"warning");
String body="日志信息,rabbitmq瘫痪了!!!";
channel.basicPublish(exchangeName,"info",null,body.getBytes());
        //释放资源
        channel.close();
        connection.close();

consumer

ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("192.168.101.134");
connectionFactory.setPort(5672);
connectionFactory.setVirtualHost("/itcast");
connectionFactory.setUsername("heima");
connectionFactory.setPassword("heima");
Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
​
Consumer consumer =new DefaultConsumer(channel){
 /**
    回调方法
  */
    @Override
    public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
        System.out.println("bodys:"+new String(body));
        System.out.println("将日志保存到数据库");
    }
};
String queue2Name="test_direct_queue2";
channel.basicConsume(queue2Name,true,consumer);

Topics wildcard pattern

  • Compared with Direct, Topic type can route messages to different queues according to RoutingKey. It's just that the Topic type Exchange allows the queue to use wildcards when binding the Routing key!

  • Routingkey generally consists of one or more words, separated by ".", for example: item.insert

  • Wildcard rules: # matches one or more words, * matches exactly one word , for example: item.# can match item.insert.abc or item.insert, item.* can only match item.insert

producer

Queue 1 uses the wildcards of error and order for key matching, and queue 2 can do all-purpose matching. When the key is goods.info, queue 1 cannot match successfully.

ConnectionFactory connectionFactory = new ConnectionFactory();
        //rabbitmq服务的ip地址
        connectionFactory.setHost("192.168.101.134");
        connectionFactory.setPort(5672);
        //连接的虚拟机
        connectionFactory.setVirtualHost("/itcast");
        //用户名
        connectionFactory.setUsername("heima");
        //密码
        connectionFactory.setPassword("heima");
        //建立连接
        Connection connection = connectionFactory.newConnection();
        //再从连接中创建channel建立真正的连接
        Channel channel = connection.createChannel();
​
        //创建交换机
        String  exchangeName="test_topic";
        channel.exchangeDeclare(exchangeName, BuiltinExchangeType.TOPIC,true,false,false,null);
        //创建队列
        String queue1Name="test_topic_queue1";
        String queue2Name="test_topic_queue2";
        channel.queueDeclare(queue1Name,true,false,false,null);
        channel.queueDeclare(queue2Name,true,false,false,null);
//绑定key时,采用*或#进行模糊化
        channel.queueBind(queue1Name,exchangeName,"#.error");
        channel.queueBind(queue1Name,exchangeName,"order.*");
        channel.queueBind(queue2Name,exchangeName,"*.*");
String body="日志信息,rabbitmq瘫痪了!!!";
channel.basicPublish(exchangeName,"goods.info",null,body.getBytes());
        //释放资源
        channel.close();
        connection.close();

Springboot integrates RabbitMQ

Import AMQP dependencies

<!--AMQP依赖,包含RabbitMQ-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

Write yml configuration

spring:
  rabbitmq:
    host: 192.168.101.134 #rabbitMQ的ip地址
    port: 5672 #端口
    username: itcast
    password: 123321
    virtual-host: "/"
    listener:
      simple:
        prefetch: 1

RabbitMQ configuration class

It is mainly used to declare queues and switches, complete the binding of queues and switches, and specify the Routing Key.

@Configuration
public class RabbitMQConfig {
    public static final String EXCHANGE_NAME="boot_topic_exchange";
    public static final String QUEUE_NAME="boot_QUEUE";
    //交换机
    @Bean("bootExchange")
    public Exchange bootExchange(){
        return ExchangeBuilder.topicExchange(EXCHANGE_NAME).durable(true).build();
    }
    //队列
    @Bean("bootQueue")
    public Queue bootQueue(){
        return QueueBuilder.durable(QUEUE_NAME).build();
    }
    //队列和交换机绑定
    @Bean
    public Binding bindQueueExchange(
            @Qualifier("bootQueue") Queue queue,@Qualifier("bootExchange") Exchange exchange
    ){
        return BindingBuilder.bind(queue).to(exchange).with("boot.*").noargs();
    }

producer

Directly inject RabbitTemplate to send messages conveniently and quickly

@SpringBootTest
public class PublishTest {
    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Test
    public void test(){
        rabbitTemplate.convertAndSend(RabbitMQConfig.EXCHANGE_NAME,"boot.haha","helloword,mq");
    }
}

consumer

@Component
public class RabbitMQListener {
    @RabbitListener(queues = "boot_QUEUE")
    public void ListenerQueue(Message message){
        System.out.println(message);
    }
}

Guess you like

Origin blog.csdn.net/weixin_64133130/article/details/132237511