RabbitMQ.基本使用

本文介绍了消息队列在服务间通信中的作用,如解耦和缓冲,并以淘宝订单流程为例说明。接着,讲解了AMQP协议和几种常见消息队列技术选型,如ActiveMQ、RabbitMQ、Kafka和RocketMQ的特性。然后,通过Docker详细演示了如何安装部署RabbitMQ,包括创建镜像、配置环境变量和启动服务。最后,展示了使用SpringBoot构建生产者和消费者应用,实现消息发送和接收功能。
摘要由CSDN通过智能技术生成

一、消息队列

1、Message queue 释义

服务之间最常见的通信方式是直接调用彼此来通信,消息从一端发出后立即就可以达到另一端,称为即时消息通讯(同步通信)

消息从某一端发出后,首先进入一个容器进行临时存储,当达到某种条件后,再由这个容器发送给另一端,称为延迟消息通讯(异步通信)

①、问题思考

假设我们在淘宝下了一笔订单后,淘宝后台需要做这些事情:

  1. 消息通知系统:通知商家,你有一笔新的订单,请及时发货
  2. 推荐系统:更新用户画像,重新给用户推荐他可能感兴趣的商品
  3. 会员系统:更新用户的积分和等级信息

createOrder(...) {

// 完成订单服务

doCreateOrder(...);

// 调用其他服务接口

sendMsg(...); updateUserInterestedGoods(...); updateMemberCreditInfo(...);

}

②、存在问题 

过度耦合:如果后面创建订单时,需要触发新的动作,那就得去改代码,在原有的创建订单函数末尾,再追加一行代码

缺少缓冲:如果创建订单时,会员系统恰好处于非常忙碌或者宕机的状态,那这时更新会员信息就会失败,我们需要一个地方,来暂时存放无法被消费的消息

③、优化方案

我们需要一个消息中间件,来实现解耦和缓冲的功能.

Email邮件案例分析:

有大量用户注册你的软件,再高并发情况下注册请求开始出现一些问题.

例如邮件接口承受不住,或是分析信息时的大量计算使cpu满载,这将会出现虽然用户数据记录很快的添加到数据库中了,但是却卡在发邮件或分析信息时的情况.

导致请求的响应时间大幅增长,甚至出现超时,这就有点不划算了.面对这种情况一般也是将这些操作放入消息队列(生产者消费者模型),消息队列慢慢的进行处理,同时可以很快的完成注册请     ,不会影响用户使用其他功能.

2、 消息队列相关

①、AMQP

一个提供统一消息服务的应用层标准高级消息队列协议,是一个通用的应用层协议

消息发送与接受的双方遵守这个协议可以实现异步通讯.这个协议约定了消息的格式和工作方式.

②、 技术选型

特性

ActiveMQ

RabbitMQ

Kafka

RocketMQ

PRODUCER-COMSUMER

支持

支持

支持

支持

PUBLISH-SUBSCRIBE

支持

支持

支持

支持

REQUEST-REPLY

支持

支持

-

支持

API完备性

低(静态配置)

多语言支持

支持,JAVA优先

语言无关

支持,JAVA优先

支持

单机呑吐量

万级

万级

十万级

单机万级

消息延迟

-

微秒级

毫秒级

-

可用性

高(主从)

高(主从)

非常高(分布式)

消息丢失

-

理论上不会丢失

-

消息重复

-

可控制

理论上会有重复

-

文档的完备性

提供快速入门

首次部署难度

-

③、 RabbitMq

RabbitMQ是一个实现了AMQP(Advanced Message Queuing Protocol)高级消息队列协议的消息队列服务,Erlang语言.

Server(Broker):接收客户端连接,实现AMQP协议的消息队列和路由功能的进程.

Virtual Host:虚拟主机的概念,类似权限控制组,一个Virtual Host里可以有多个ExchangeQueue. Exchange:交换机,接收生产者发送的消息,并根据Routing Key将消息路由到服务器中的队列Queue.

ExchangeType:交换机类型决定了路由消息行为,RabbitMQ中有三种类型Exchange,分别是fanoutdirecttopic. Message Queue:消息队列,用于存储还未被消费者消费的消息.

Message:由Headerbody组成,Header是由生产者添加的各种属性的集合,包括Message是否被持久化、优先级是多少、由哪个Message   Queue接收等.body是真正需要发送的数据内容.

BindingKey:绑定关键字,将一个特定的Exchange和一个特定的Queue绑定起来.

二、Docker安装部署RabbitMQ

1、拉取镜像

注意获取镜像的时候要获取management版本的,不要获取last版本的,management版本的才带有管理界面

docker pull rabbitmq:management

2、新建rabbitmq文件夹

mkdir rabbitmq

运行: 

docker run -d \

--name my-rabbitmq \

-p 5672:5672 -p 15672:15672 \

-v /home/rabbitmq:/var/lib/rabbitmq \

--hostname my-rabbitmq-host \

-e RABBITMQ_DEFAULT_VHOST=my_vhost \

-e RABBITMQ_DEFAULT_USER=admin \

-e RABBITMQ_DEFAULT_PASS=admin \

--restart=always \

rabbitmq:management

--hostname:主机名(RabbitMQ的一个重要注意事项是它根据所谓的 节点名称存储数据,默认为主机名)

-e: 指 定 环 境 变 量 :

RABBITMQ_DEFAULT_VHOST:默认虚拟机名

RABBITMQ_DEFAULT_USER:默认的用户名 

RABBITMQ_DEFAULT_PASS:默认用户名的密码

3、进入管理后台 

账号密码:admin

新建用户,设为管理员,

 给用户分配访问虚拟主机权限

三、搭建RabbitMQ项目

1、springboot项目搭建

(1)、新建空的Maven父项目,删掉src,

pom.xml中新增,意味不打包,只提供依赖

<packaging>pom</packaging>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>rabbitMQ</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <modules>
        <module>provider</module>
        <module>consumer</module>
    </modules>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.4.1</spring-boot.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    
</project>

(2)、新建子项目

①、新建provider子项目

pom.xml:继承父项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>rabbitMQ</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mwy</groupId>
    <artifactId>provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>provider</name>
    <description>provider</description>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <mainClass>com.mwy.provider.ProviderApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

 ②、新建consumer子项目

pom.xml:继承父项目

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">

    <parent>
        <artifactId>rabbitMQ</artifactId>
        <groupId>org.example</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mwy</groupId>
    <artifactId>consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>consumer</name>
    <description>consumer</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.4.1</version>
                <configuration>
                    <mainClass>com.mwy.consumer.ConsumerApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

(3)、相关依赖

①、rabbitMQ父项目中增加pom依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>

(4)yml文件配置

server:
    port: 8080
spring:
    application:
        name: xx
    rabbitmq:
        host: 192.168.42.148
        password: 123456
        port: 5672
        username: springboot
        virtual-host: my_vhost

2、生产者 provider

①、新建RabbitConfig类

package com.mwy.provider;
import org.springframework.amqp.core.Queue;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class RabbitConfig {
    @Bean
    public Queue firstQueue() {
        return new Queue("firstQueue");
    }
}

②、新建Sender 类

package com.mwy.provider;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@SuppressWarnings("all")
public class Sender {
    @Autowired
    private AmqpTemplate rabbitTemplate;
    public void sendFirst() {
        rabbitTemplate.convertAndSend("firstQueue", "Hello World");
    }
}

③、测试类ProviderApplicationTests

package com.example.provider;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ProviderApplicationTests {
    @Autowired
    private Sender sender;
    @Test
    void contextLoads() {
        sender.sendFirst();
    }
}

此时,RabbitMQ Management 中会增加一个队列 

3、消费者 Consumer

①、yml文件配置

server:
    port: 8081
spring:
    application:
        name: consumer
    rabbitmq:
        host: 192.168.42.148
        password: 123456
        port: 5672
        username: springboot
        virtual-host: my_vhost

②、Receiver

package com.example.consumer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component 
@Slf4j
@RabbitListener(queues = "firstQueue") 
public class Receiver {
    @RabbitHandler
    public void process(String msg) {
        log.warn("接收到:" + msg);
    }
}

4、自定义数据发送

(1)生产者 provider

①、Uset

package com.example.provider;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private String username;
    private String userpwd;
}

②、Sender

package com.example.provider;

import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class Sender {
    @Autowired
    private AmqpTemplate amqpTemplate;

    public void sendFirst() {
        amqpTemplate.convertAndSend("firstQueue", "Hello World");
    }

    public void sendFirst(User user) {
        amqpTemplate.convertAndSend("firstQueue", user);
    }

    public void sendFirst(String json) {
        amqpTemplate.convertAndSend("firstQueue", json);
    }

}

③、测试

package com.example.provider;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ProviderApplicationTests {
    @Autowired
    private Sender sender;

    @Test
    @SneakyThrows
    void contextLoads() {
//        sender.sendFirst();
//        sender.sendFirst(new User("aa","123"));
        User u=new User("aa","123");
        ObjectMapper objectMapper=new ObjectMapper();
        sender.sendFirst(objectMapper.writeValueAsString(u));
    }
}

(2)消费者 Consumer

①、Uset

package com.example.consumer;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {
    private String username;
    private String userpwd;
}

②、Receiver

package com.example.consumer;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@RabbitListener(queues = "firstQueue")
public class Receiver {
//    @RabbitHandler
//    public void process(String msg) {
//        log.warn("接收到:" + msg);
//    }

//    @RabbitHandler
//    public void process(User user) {
        log.warn("接收到:" + user);
//    }

@RabbitHandler
@SneakyThrows
public void process(String json) {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.readValue(json,User.class);
    log.warn("接收:" + json);
}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值