超详细的RabbitMQ入门,看这篇就够了!

思维导图

图片[1]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

一、什么是消息队列

消息指的是两个应用间传递的数据。数据的类型有很多种形式,可能只包含文本字符串,也可能包含嵌入对象。

“消息队列(Message Queue)”是在消息的传输过程中保存消息的容器。在消息队列中,通常有生产者和消费者两个角色。生产者只负责发送数据到消息队列,谁从消息队列中取出数据处理,他不管。消费者只负责从消息队列中取出数据处理,他不管这是谁发送的数据。

图片[2]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

二、为什么使用消息队列

主要有三个作用:

  • 解耦。如图所示。假设有系统B、C、D都需要系统A的数据,于是系统A调用三个方法发送数据到B、C、D。这时,系统D不需要了,那就需要在系统A把相关的代码删掉。假设这时有个新的系统E需要数据,这时系统A又要增加调用系统E的代码。为了降低这种强耦合,就可以使用MQ,系统A只需要把数据发送到MQ,其他系统如果需要数据,则从MQ中获取即可
图片[3]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站
  • 异步。如图所示。一个客户端请求发送进来,系统A会调用系统B、C、D三个系统,同步请求的话,响应时间就是系统A、B、C、D的总和,也就是800ms。如果使用MQ,系统A发送数据到MQ,然后就可以返回响应给客户端,不需要再等待系统B、C、D的响应,可以大大地提高性能。对于一些非必要的业务,比如发送短信,发送邮件等等,就可以采用MQ。
图片[4]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站
  • 削峰。如图所示。这其实是MQ一个很重要的应用。假设系统A在某一段时间请求数暴增,有5000个请求发送过来,系统A这时就会发送5000条SQL进入MySQL进行执行,MySQL对于如此庞大的请求当然处理不过来,MySQL就会崩溃,导致系统瘫痪。如果使用MQ,系统A不再是直接发送SQL到数据库,而是把数据发送到MQ,MQ短时间积压数据是可以接受的,然后由消费者每次拉取2000条进行处理,防止在请求峰值时期大量的请求直接发送到MySQL导致系统崩溃
图片[5]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

三、RabbitMQ的特点

RabbitMQ是一款使用Erlang语言开发的,实现AMQP(高级消息队列协议)的开源消息中间件。首先要知道一些RabbitMQ的特点,官网可查:

  • 可靠性。支持持久化,传输确认,发布确认等保证了MQ的可靠性。
  • 灵活的分发消息策略。这应该是RabbitMQ的一大特点。在消息进入MQ前由Exchange(交换机)进行路由消息。分发消息策略有:简单模式、工作队列模式、发布订阅模式、路由模式、通配符模式。
  • 支持集群。多台RabbitMQ服务器可以组成一个集群,形成一个逻辑Broker。
  • 多种协议。RabbitMQ支持多种消息队列协议,比如 STOMP、MQTT 等等。
  • 支持多种语言客户端。RabbitMQ几乎支持所有常用编程语言,包括 Java、.NET、Ruby 等等。
  • 可视化管理界面。RabbitMQ提供了一个易用的用户界面,使得用户可以监控和管理消息 Broker。
  • 插件机制。RabbitMQ提供了许多插件,可以通过插件进行扩展,也可以编写自己的插件。

四、RabbitMQ初の体验

4.1 安装RabbitMQ (Win10系统)

由于只是学习需要,所以安装在win10系统,就懒得开虚拟机。如果用Linux系统安装的话,我建议用Docker拉一个RabbitMQ的镜像下来,这样会方便一点。

4.1.1 安装erLang语言,配置环境变量

首先到erlang官网下载win10版安装包。

图片[6]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

下载完之后,就得到这个东西:

图片[7]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

接着双击安装,一直点next(下一步)就行了,安装完之后,配置环境变量。

图片[8]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站
图片[9]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

使用cmd命令,输入 erl -version 验证:

图片[10]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

4.1.2 安装RabbitMQ服务端

在RabbitMQ的gitHub项目中,下载window版本的服务端安装包。

图片[11]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

下载后,就得到这个东西:

图片[12]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

接着到双击安装,一直点下一步安装即可,安装完成后,找到安装目录:

图片[13]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

在此目录下打开cmd命令,输入rabbitmq-plugins enable rabbitmq_management命令安装管理页面的插件:

图片[14]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

然后双击rabbitmq-server.bat启动脚本,然后打开服务管理可以看到RabbitMQ正在运行:

图片[15]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

这时,打开浏览器输入http://localhost:15672,账号密码默认是:guest/guest

图片[16]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

到这一步,安装就大功告成了!

图片[17]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

4.2 永远的Hello Word

服务端搭建好了之后肯定要用客户端去操作,接下来就用Java做一个简单的HelloWord演示。

因为我用的是SpringBoot,所以在生产者这边加入对应的starter依赖即可:

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

一般需要创建一个公共项目common,共享一些配置,比如队列主题,交换机名称,路由匹配键名称等等。

图片[18]-超详细的RabbitMQ入门,看这篇就够了!-梦境学习站

首先在application.yml文件加上RabbitMQ的配置信息:

spring:
    rabbitmq:
        host: 127.0.0.1
        port: 5672
        username: guest
        password: guest

然后再生产者这边,加上common包的maven依赖,然后创建一个Direct交换机以及队列的配置类:

@Configuration
public class DirectRabbitConfig {
    @Bean
    public Queue rabbitmqDemoDirectQueue() {
        /**
         * 1、name:    队列名称
         * 2、durable: 是否持久化
         * 3、exclusive: 是否独享、排外的。如果设置为true,定义为排他队列。则只有创建者可以使用此队列。也就是private私有的。
         * 4、autoDelete: 是否自动删除。也就是临时队列。当最后一个消费者断开连接后,会自动删除。
         * */
        return new Queue(RabbitMQConfig.RABBITMQ_DEMO_TOPIC, true, false, false);
    }

    @Bean
    public DirectExchange rabbitmqDemoDirectExchange() {
        //Direct交换机
        return new DirectExchange(RabbitMQConfig.RABBITMQ_DEMO_DIRECT_EXCHANGE, true, false);
    }

    @Bean
    public Binding bindDirect() {
        //链式写法,绑定交换机和队列,并设置匹配键
        return BindingBuilder
                //绑定队列
                .bind(rabbitmqDemoDirectQueue())
                //到交换机
                .to(rabbitmqDemoDirectExchange())
                //并设置匹配键
                .with(RabbitMQConfig.RABBITMQ_DEMO_DIRECT_ROUTING);
    }
}

然后再创建一个发送消息的Service类:

@Service
public class RabbitMQServiceImpl implements RabbitMQService {
    //日期格式化
    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Resource
    private RabbitTemplate rabbitTemplate;

    @Override
    public String sendMsg(String msg) throws Exception {
        try {
            String msgId = UUID.randomUUID().toString().replace("-", "").substring(0, 32);
            String sendTime = sdf.format(new Date());
            Map<String, Object> map = new HashMap<>();
            map.put("msgId", msgId);
            map.put("sendTime", sendTime);
            map.put("msg", msg);
            rabbitTemplate.convertAndSend(RabbitMQConfig.RABBITMQ_DEMO_DIRECT_EXCHANGE, RabbitMQConfig.RABBITMQ_DEMO_DIRECT_