SpringBoot: A first look at the RabbitMQ message queue

SpringBoot It is a product born to simplify  Spring a series of problems such as application creation, operation, debugging, and deployment. The feature of automatic assembly allows us to better focus on the business itself instead of external XML configuration. We only need to follow the specifications and introduce relevant Dependency can easily build a WEB project

The full name of MQ (Message Queue), also known as message queue, is a middleware for asynchronous communication . It can be understood as a post office. The sender delivers the message to the post office, and then the post office helps us send it to the specific message recipient (consumer). We don’t need to care about the specific sending process and time, and it will not interfere with me doing other things. . Common MQs include kafka, activemq, zeromq, rabbitmq, etc. The comparison and advantages and disadvantages of major MQs can be Googled by yourself

rabbitmq

RabbitMQ is a high-concurrency-oriented language that follows the AMQP protocolerlanng . It is used in real-time message delivery that requires high reliability and supports multiple language clients. Support 延迟队列(这是一个非常有用的功能)....

basic concepts

Broker: Simply put, it is the message queue server entity

Exchange: message exchange, which specifies the rules by which messages are routed to which queue

Queue: message queue carrier, each message will be put into one or more queues

Binding: Binding, its function is to bind exchangeand queuefollow the routing rules

Routing Key: Routing keyword, exchangebased on this keyword for message delivery

vhost: virtual host, brokermultiple can be opened in one vhost, used for the separation of permissions of different users

producer: The message producer is the program that delivers the message

consumer: message consumer, which is the program that accepts messages

channel: message channel, in each connection of the client, multiple can be established channel, each channelrepresenting a session task

For installation based on Centos7.x, please refer to:  http://blog.battcn.com/2017/08/20/linux/linux-centos7-ribbitmq/

Common application scenarios

  1. Mailbox sending: After the user registers, the message is delivered to the rabbitmqcenter, and the message consumer sends the message asynchronously to improve the system response speed.
  2. Traffic peak clipping: It is generally widely used in seckill activities. The seckill will cause the application to hang due to excessive traffic. To solve this problem, a message queue is generally added to the front end of the application. It is used to control the number of active people, and orders that exceed this certain threshold will be discarded directly. Relieve short-term high-flow overwhelming applications.
  3. Order timeout: rabbitmqThe delay queue is used to easily implement the function of order timeout . For example, the user cancels the order without paying 30 minutes after placing the order.
  4. There are many more application scenarios that are not listed one by one...

import dependencies

dependencies pom.xml added  in spring-boot-starter-amqp

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.46</version>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

property configuration

application.properties Configure the relevant content in the  file rabbitmq, it is worth noting that the switch for manual ACK is configured here

spring.rabbitmq.username=battcn
spring.rabbitmq.password=battcn
spring.rabbitmq.host=192.168.0.133
spring.rabbitmq.port=5672
spring.rabbitmq.virtual-host=/
# 手动ACK 不开启自动ACK模式,目的是防止报错后未正确处理消息丢失 默认 为 none
spring.rabbitmq.listener.simple.acknowledge-mode=manual

specific code

define queue

If the queue has been created manually or RabbitMQalready exists in the queue, the following code can also be omitted...

package com.battcn.config;

import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * RabbitMQ配置
 *
 * @author Levin
 * @since 2018/4/11 0011
 */
@Configuration
public class RabbitConfig {

    public static final String DEFAULT_BOOK_QUEUE = "dev.book.register.default.queue";
    public static final String MANUAL_BOOK_QUEUE = "dev.book.register.manual.queue";

    @Bean
    public Queue defaultBookQueue() {
        // 第一个是 QUEUE 的名字,第二个是消息是否需要持久化处理
        return new Queue(DEFAULT_BOOK_QUEUE, true);
    }

    @Bean
    public Queue manualBookQueue() {
        // 第一个是 QUEUE 的名字,第二个是消息是否需要持久化处理
        return new Queue(MANUAL_BOOK_QUEUE, true);
    }
}

entity class

create a Bookclass

public class Book implements java.io.Serializable {

    private static final long serialVersionUID = -2164058270260403154L;

    private String id;
    private String name;
	// 省略get set ...
}

controller

Write a Controllerclass for the message sending job

package com.battcn.controller;

import com.battcn.config.RabbitConfig;
import com.battcn.entity.Book;
import com.battcn.handler.BookHandler;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Levin
 * @since 2018/4/2 0002
 */
@RestController
@RequestMapping(value = "/books")
public class BookController {

    private final RabbitTemplate rabbitTemplate;

    @Autowired
    public BookController(RabbitTemplate rabbitTemplate) {
        this.rabbitTemplate = rabbitTemplate;
    }

    /**
     * this.rabbitTemplate.convertAndSend(RabbitConfig.DEFAULT_BOOK_QUEUE, book); 对应 {@link BookHandler#listenerAutoAck}
     * this.rabbitTemplate.convertAndSend(RabbitConfig.MANUAL_BOOK_QUEUE, book); 对应 {@link BookHandler#listenerManualAck}
     */
    @GetMapping
    public void defaultMessage() {
        Book book = new Book();
        book.setId("1");
        book.setName("一起来学Spring Boot");
        this.rabbitTemplate.convertAndSend(RabbitConfig.DEFAULT_BOOK_QUEUE, book);
        this.rabbitTemplate.convertAndSend(RabbitConfig.MANUAL_BOOK_QUEUE, book);
    }
}

message consumer

By default, it  spring-boot-data-amqp is an automatic ACKmechanism, which means that MQ will automatically help us to ACK after the message is consumed, so there is such a problem in dependencies: if an error is reported, the message will not be lost, and it will be consumed in an infinite loop. It is easy to use the disk. When the space is exhausted, although the number of consumptions can be configured, this approach is also inelegant. At present, it is recommended that we manually ACK and then transfer the message of consumption error to other message queues for compensation processing.

package com.battcn.handler;

import com.battcn.config.RabbitConfig;
import com.battcn.entity.Book;
import com.rabbitmq.client.Channel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.io.IOException;

/**
 * BOOK_QUEUE 消费者
 *
 * @author Levin
 * @since 2018/4/11 0011
 */
@Component
public class BookHandler {

    private static final Logger log = LoggerFactory.getLogger(BookHandler.class);

    /**
     * <p>TODO 该方案是 spring-boot-data-amqp 默认的方式,不太推荐。具体推荐使用  listenerManualAck()</p>
     * 默认情况下,如果没有配置手动ACK, 那么Spring Data AMQP 会在消息消费完毕后自动帮我们去ACK
     * 存在问题:如果报错了,消息不会丢失,但是会无限循环消费,一直报错,如果开启了错误日志很容易就吧磁盘空间耗完
     * 解决方案:手动ACK,或者try-catch 然后在 catch 里面讲错误的消息转移到其它的系列中去
     * spring.rabbitmq.listener.simple.acknowledge-mode=manual
     * <p>
     *
     * @param book 监听的内容
     */
    @RabbitListener(queues = {RabbitConfig.DEFAULT_BOOK_QUEUE})
    public void listenerAutoAck(Book book, Message message, Channel channel) {
        // TODO 如果手动ACK,消息会被监听消费,但是消息在队列中依旧存在,如果 未配置 acknowledge-mode 默认是会在消费完毕后自动ACK掉
        final long deliveryTag = message.getMessageProperties().getDeliveryTag();
        try {
            log.info("[listenerAutoAck 监听的消息] - [{}]", book.toString());
            // TODO 通知 MQ 消息已被成功消费,可以ACK了
            channel.basicAck(deliveryTag, false);
        } catch (IOException e) {
            try {
                // TODO 处理失败,重新压入MQ
                channel.basicRecover();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
    }

    @RabbitListener(queues = {RabbitConfig.MANUAL_BOOK_QUEUE})
    public void listenerManualAck(Book book, Message message, Channel channel) {
        log.info("[listenerManualAck 监听的消息] - [{}]", book.toString());
        try {
            // TODO 通知 MQ 消息已被成功消费,可以ACK了
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (IOException e) {
            // TODO 如果报错了,那么我们可以进行容错处理,比如转移当前消息进入其它队列
        }
    }
}

main function

package com.battcn;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author Levin
 */
@SpringBootApplication
public class Chapter11Application {

    public static void main(String[] args) {
        SpringApplication.run(Chapter11Application.class, args);
    }
}

test

After completing the preparations, start Chapter11Application accessing  http://localhost:8080/books  and you will see the following content, which means everything is normal....

2018-05-22 19:04:26.708  INFO 23752 --- [cTaskExecutor-1] com.battcn.handler.BookHandler           : [listenerAutoAck 监听的消息] - [com.battcn.entity.Book@77d8be18]
2018-05-22 19:04:26.709  INFO 23752 --- [cTaskExecutor-1] com.battcn.handler.BookHandler           : [listenerManualAck 监听的消息] - [com.battcn.entity.Book@8bb452]

Pay attention, don't get lost, this is a public account that programmers want to pay attention to

{{o.name}}
{{m.name}}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324142846&siteId=291194637