学会Rabbitmq,这一篇就够了

RabbitMQ学习笔记

Docker安装

一、获取镜像

# 镜像未配有控制台
docker pull rabbitmq
# 镜像配有控制台
docker pull rabbitmq:management

二、运行镜像

#方式一:默认guest 用户,密码也是 guest
docker run -d --hostname my-rabbit --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq:management

#方式二:设置用户名和密码
docker run -d --hostname my-rabbit --name rabbit -e RABBITMQ_DEFAULT_USER=user -e RABBITMQ_DEFAULT_PASS=password -p 15672:15672 -p 5672:5672 rabbitmq:management

三、访问ui页面

http://localhost:15672/

在这里插入图片描述

消息队列

一、什么是消息队列

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

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

在这里插入图片描述

二、为什么使用消息队列

主要有三个作用:

  • 解耦。如图所示。假设有系统B、C、D都需要系统A的数据,于是系统A调用三个方法发送数据到B、C、D。这时,系统D不需要了,那就需要在系统A把相关的代码删掉。假设这时有个新的系统E需要数据,这时系统A又要增加调用系统E的代码。为了降低这种强耦合,就可以使用MQ,系统A只需要把数据发送到MQ,其他系统如果需要数据,则从MQ中获取即可

在这里插入图片描述

  • 异步。如图所示。一个客户端请求发送进来,系统A会调用系统B、C、D三个系统,同步请求的话,响应时间就是系统A、B、C、D的总和,也就是800ms。如果使用MQ,系统A发送数据到MQ,然后就可以返回响应给客户端,不需要再等待系统B、C、D的响应,可以大大地提高性能。对于一些非必要的业务,比如发送短信,发送邮件等等,就可以采用MQ。

在这里插入图片描述

  • 削峰。如图所示。这其实是MQ一个很重要的应用。假设系统A在某一段时间请求数暴增,有5000个请求发送过来,系统A这时就会发送5000条SQL进入MySQL进行执行,MySQL对于如此庞大的请求当然处理不过来,MySQL就会崩溃,导致系统瘫痪。如果使用MQ,系统A不再是直接发送SQL到数据库,而是把数据发送到MQ,MQ短时间积压数据是可以接受的,然后由消费者每次拉取2000条进行处理,防止在请求峰值时期大量的请求直接发送到MySQL导致系统崩溃

在这里插入图片描述

三、RabbitMQ的特点

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

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

五种模式

概念解释

一、 channel 信道:

概念:信道是生产消费者与rabbit通信的渠道,生产者publish或是消费者subscribe一个队列都是通过信道来通信的。信道是建立在TCP连接上的虚拟连接,什么意思呢?就是说rabbitmq在一条TCP上建立成百上千个信道来达到多个线程处理,这个TCP被多个线程共享,每个线程对应一个信道,信道在rabbit都有唯一的ID ,保证了信道私有性,对应上唯一的线程使用。

疑问:为什么不建立多个TCP连接呢?原因是rabbit保证性能,系统为每个线程开辟一个TCP是非常消耗性能,
每秒成百上千的建立销毁TCP会严重消耗系统。所以rabbitmq选择建立多个信道(建立在tcp的虚拟连接)
连接到rabbit上。

类似概念:TCP是电缆,信道就是里面的光纤,每个光纤都是独立的,互不影响。
复制代码

二、exchange 交换机和绑定routing key(这和后面的工作模式有关)

exchange的作用就是类似路由器,routing key 就是路由键,服务器会根据路由键将消息从交换器路由到队列上去。

exchange有多个种类,常用的有direct,fanout,topic。前三种类似集合对应关系那样,(direct)1:1,(fanout)1:N,(topic)N:1

direct: 1:1类似完全匹配

fanout:1:N 可以把一个消息并行发布到多个队列上去,简单的说就是,当多个队列绑定到fanout的交换器,那么交换器一次性拷贝多个消息分别发送到绑定的队列上,每个队列有这个消息的副本。

ps:这个可以在业务上实现并行处理多个任务,比如,用户上传图片功能,当消息到达交换器上,它可以同时路由到积分
增加队列和其它队列上,达到并行处理的目的,并且易扩展,以后有什么并行任务的时候,直接绑定到fanout交换器
不需求改动之前的代码。

topic N:1 ,多个交换器可以路由消息到同一个队列。根据模糊匹配,比如一个队列的routing key 为*.test ,那么凡是到达交换器的消息中的routing key 后缀.test都被路由到这个队列上。

三、队列(queue)

1、推模式:通过AMQP的basic.consume命令订阅,有消息会自动接收,吞吐量高

2、拉模式:通过AMQP的bsaic.get命令

注:当队列拥有多个消费者时,队列收到的消息将以循环的方式发送给消费者。每条消息只会发送给一个订阅的消费者

四、持久化(duration)

开启持久化功能,需同时满足:消息投递模式选择持久化、交换器开启持久化、队列开启持久化

五、确认机制(ack)

1、发送方确认模式:消息发送到交换器–发送完毕–>消息投递到队列或持久化到磁盘异步回调通知生产者

2、消费者确认机制:消息投递消费者-ack-删除该条消息-投递下一条

注:收到ACK前,不会把消息再次发送给该消费者,但是会把下一条消息发送给其他消费者

工作模式

  • 简单模式

在这里插入图片描述

在上图的模型中,有以下概念:

  1. 生产者,也就是要发送消息的程序
  2. 消费者:消息的接受者,会一直等待消息到来。
  3. 消息队列:图中红色部分。类似一个邮箱,可以缓存消息;生产者向其中投递消息,消费者从其中取出消息。
  • 工作队列模式
    在这里插入图片描述

消息产生者将消息放入队列消费者可以有多个,消费者1,消费者2同时监听同一个队列,消息被消费。C1 C2共同争抢当前的消息队列内容,谁先拿到谁负责消费消息(隐患:高并发情况下,默认会产生某一个消息被多个消费者共同使用,可以设置一个开关(syncronize) 保证一条消息只能被一个消费者使用)。

  • 发布订阅模式

在这里插入图片描述

1、每个消费者监听自己的队列;

2、生产者将消息发给broker,由交换机将消息转发到绑定此交换机的每个队列,每个绑定交换机的队列都将接收到消息;

  • 路由模式
    在这里插入图片描述

1.消息生产者将消息发送给交换机按照路由判断,路由是字符串(info) 当前产生的消息携带路由字符(对象的方法),交换机根据路由的key,只能匹配上路由key对应的消息队列,对应的消费者才能消费消息;

2.根据业务功能定义路由字符串

3.从系统的代码逻辑中获取对应的功能字符串,将消息任务扔到对应的队列中。

4.业务场景:error 通知;EXCEPTION;错误通知的功能;传统意义的错误通知;客户通知;利用key路由,可以将程序中的错误封装成消息传入到消息队列中,开发者可以自定义消费者,实时接收错误。

  • topic 主题模式(通配符模式)

在这里插入图片描述

1.星号井号代表通配符

2.星号代表一个单词(.后一级有且必须是一个单词),井号代表可有可无(即0或1或多个节点匹配)

3.路由功能添加模糊匹配

4.消息产生者产生消息,把消息交给交换机

5.交换机根据key的规则模糊匹配到对应的队列,由队列的监听消费者接收消息消费

java测试参考代码参考文档:https://blog.csdn.net/qq_44858230/article/details/114905896

整合SpringBoot

  1. 导入依赖
<!--Spring AMQP依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
  1. 配置yaml文件

publisher-confirm-type

  • none值是禁用发布确认模式,是默认值
  • correlated值是发布消息成功到交换器后会触发回调方法,如示例
/**
 * 设置生产者消息publish-confirm回调函数
*/
rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {
 if(!ack){
     LoggerUtil.error(RabbitConfig.class, StringUtils.join("publishConfirm消息发送到交换器被退回,Id:", correlationData.getId(), ";退回原因是:", cause));
 } else {
     LoggerUtil.info(RabbitConfig.class, "发送消息到交换器成功,MessageId:"+correlationData.getId());
 }
});
  • simple值经测试有两种效果,其一效果和correlated值一样会触发回调方法,其二在发布消息成功后使用rabbitTemplate调用waitForConfirmswaitForConfirmsOrDie方法等待broker节点返回发送结果,根据返回结果来判定下一步的逻辑,要注意的点是waitForConfirmsOrDie方法如果返回false则会关闭channel,则接下来无法发送消息到broker
spring:
  rabbitmq:
  	# 主机
    host: 119.3.212.23
    # 端口号
    port: 5672
    # 虚拟主机路径
    virtual-host: /
    username: root
    password: 111111
    publisher-confirm-type: correlated
    #可以确保消息在未被队列接收时返回
	publisher-returns: true  
  1. 配置类
/**
 * 配置产生的交换机,队列以及绑定
 */
@Configuration
public class DirectRabbitConfig {

    interface Config{
        //指定队列
        String name= "direct.queue";
        //指定交换机
        String exchange = "direct.exchange";
        //是否持久化
        boolean durable = true;
        //路由键
        String routingKey = "nanfeng";
    }

    //创建对列
    @Bean
    public Queue directQueue(){
        return new Queue(Config.name,Config.durable);
    }

    //创建交换机
    //简单模式和work模式只需要注册队列即可,交换机不是没有而是服务器有默认交换机
    //路由模式的交换机如本例
    //统配模式的交换机TopicExchange topic() {return new TopicExchange("topic.exchange")
    //发布模式的交换机FanoutExchange direct() {return new FanoutExchange("fanout.exchange")
    @Bean
    public DirectExchange directExchange(){
        return new DirectExchange(Config.exchange);
    }

    //绑定对列和交换机 并指定 routingKey
    @Bean
    public Binding binding(){
        return BindingBuilder.bind(directQueue()).to(directExchange()).with(Config.routingKey);
    }

}	

  1. 消息实体类
@Data
@Builder
public class Mymessage implements Serializable {

    private static final long serialVersionUID = 1L;

    public String messageId;

    public String createTime;

    public String body;
}

  1. 生产者
@RestController
public class SendMsgController {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @RequestMapping("/sndDirectMsg")
    public String sendDirectMsg(){

        //消息构造
        Mymessage msg = Mymessage.builder().
                messageId(String.valueOf(UUID.randomUUID())).
                createTime(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))).
                body("hello world")
                .build();
        //发送消息:参数一:交换机名,参数二:路由键,参数三:消息
        rabbitTemplate.convertAndSend("direct.exchange","nanfeng", msg);
        return "OK";
    }
}

  1. 消费者
@Component
//监听的队列名
//@RabbitListener放在方法上可多队列监听,在类上需要实现一个默认的@RabbitHandler标记的处理方法
public class DirectReceiver {

    @RabbitListener(queues = "direct.queue")
    public void process(Mymessage msg){
        System.out.println("receive msg : " +msg.toString());
    }  
}

结果

receive msg : Mymessage(messageId=7e6611a6-132b-4d41-a6bf-68ee6cb4b844, createTime=2021-04-06 10:58:50, body=hello world)

过期时间TTL

过期时间 TTl表示可以对消息设置预期的时间,在这个时间内都可以被消费者接收获取;过了之后消息将自动被删除。RabbitMQ可以对消息和队列设置 TTL,目前有两种方法可以设置

第一种方法是通过队列属性设置,队列中所有消息都有相同的过期时间

第二种方法是对消息进行单独设置,每条消息 TTL可以不同

如果上述两种方法同时使用,则消息的过期时间以两者 TTL较小的那个数值为准。消息在队列的生存时间一旦超过设置的 TTL值,就称为 dead message被投递到死信队列,消费者将无法再收到该消息

java测试代码参考:https://blog.csdn.net/qq_44858230/article/details/114906087

死信队列

DLX,全称 Dead-Letter-Exchange,可以称之为死信交换机,也有人称之为死信邮箱。当消息再一个队列中变成死信之后,它能被重新发送到另一个交换机中,这个交换机就是 DLX,绑定 DLX的队列就称之为死信队列。消息变成死信,可能是由于以下原因:

  • 消息被拒绝
  • 消息过期
  • 队列达到最大长度(队列中最多容纳五条消息)

DLX也是一个正常的交换机,和一般的交换机没有区别,它能在任何的队列上被指定,实际上就是设置某一个队列的属性,当这个队列中存在死信时,Rabbitmq就会自动地将这个消息重新发布到设置的 DLX上去,进而被路由到另一个队列,即死信队列。

要想使用死信队列,只需要在定义队列的时候设置队列参数x-dead-letter-exchange指定交换机即可

在这里插入图片描述

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nan feng

打赏一杯咖啡吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值