当前位置: 首页 > news >正文

RabbitMQ学习笔记

1、什么是MQ?

MQ全称message queue(消息队列),本质是一个队列,FIFO先进先出,是消息传送过程中保存消息的容器,多 用于分布式系统之间进行通信。

在互联网架构中,MQ是一种非常常见的上下游“逻辑解耦+物理解耦”的消息通讯服务,使用了MQ后,消息发送上游只需要依赖MQ,不需要依赖其他的服务。

2、为什么使用MQ?
  1. 流量削峰
  2. 应用解耦
    1. 比如电商系统中分为订单系统,支付系统,库存系统,物流系统,如果订单系统直接调用三种系统,其中一个系统出现了短暂的故障,订单系统就属于不可用的状态,
    2. 如果使用mq,订单系统生成的订单直接存放在MQ中,即便其余某个系统短暂故障,订单系统不感知,系统可用性增强
  3. 异步处理
    1. 假设A调用B ,B是异步处理并且需要很长时间来处理,但是A需要知道B的处理结果,通常做法是
      1. A每隔一段时间去调用B的查询函数,
      2. 或者A提供一个回调函数让B调用完成之后通知A。
    2. MQ提供了一种新的处理思路,即B处理完之后,发送一条消息给MQ,MQ将消息给A进行处理。
3、实现MQ的两种主流方式?

两种,AMQP和JMS

  1. AMQP即 Advanced Message Queuing Protocol(高级消息队列协议),是一个网络协议,是应用层协议的一个开放标准,为面向消息的中间件设计的。
  2. JMS 即 Java 消息服务(Java Message Service)应用程序接口,是一个java平台中关于面向消息中间件的API。是javaEE规范的一种。

区别?

  • JMS定义了统一的接口,来对消息操作进行统一,而AMQP是通过协议规定了数据交互格式
  • JMS限制了必须使用java,AMQP只是协议,不规定实现方式,是跨语言的
  • JMS规定了两种消息模式,AMQP的消息模式更加丰富

4、MQ的选择?
  1. kafka:主要特点是基于pull的模式来处理消息消费,追求高吞吐量,一开始的目的就是用于日志收集和传输,适合产生大量数据的数据收集业务,如果有日志采集功能,首选kafka
  2. rocketMQ: 适用于金融互联网领域,对可靠性要求很高的场景适用(阿里双11),尤其是电商里面的订单扣款、业务削峰等,稳定性好,适用于并发场景。
  3. rabbitMQ:性能好,时效性微妙级别,社区活跃度高,功能完备,管理界面使用方便,适合数据量没有那么大的中小型公司。

5、rabbitMQ中的四大核心概念?
  1. 生产者:产生数据,发送消息的程序
  2. 交换机:rabbitMQ中非常重要的一个部件,一方面接收来自生产者的消息,另一方面将消息推送到队列中。(交换机必须要确切知道如何处理接收到的消息)
  3. 队列:存放消息的数据结构,本质是一个大的消息缓冲区
  4. 消费者:大多数情况是一个等待接收消息的程序

6、rabbitMQ的基本结构?

  • producer:消息生产者,即生产消息的客户端
  • consumer:消息消费者,即消费消息的客户端,接收MQ转发的消息
  • connection:producer/consumer 和broker之间的TCP连接
  • channel:如果每一次访问rabbitMQ都建立一个connection,在消息量大的时候建立TCP连接的开销是巨大的,效率也很低,channel是在connection内部建立的逻辑连接,一个连接内包含多个信道,每次发消息只占用一个信道,这样就极大的减少了建立connection的开销。
  • broker:接收和分法消息的应用,消息队列的服务进程,包括两个部分,exchange和queue
  • exchange:消息队列交换机,按照一定的规则将消息路由转发给到某个队列,对消息进行过滤
  • queue:消息队列,存储消息
  • binding:exchange和queue之间的虚拟连接

生产者生产消息的过程:

  1. producer先连接到broker,这个步骤需要先建立connection连接,并开启一个信道channel
  2. producer声明一个交换器,并设置相关属性 (交换器写空字符串,会使用默认的交换器)
  3. producer声明一个队列,并设置相关属性
  4. producer通过绑定将交换器和队列进行绑定
  5. producer发送消息到broker,其中包含路由键,交换器等信息
  6. 交换器根据收到的路由键查找对应的队列
  7. 如果找到,就会将消息存入相应的队列,如果没有找到,会根据producer的配置选择丢弃或者是退回给生产者
  8. 关闭信道

消费者接收消息的过程:

  1. consumer连接到broker,建立connection连接,开启一个信道
  2. consumer请求消费相应队列中的消息,可以设置响应的回调函数
  3. 等待broker回应并投递相应队列中的消息,接收消息
  4. consumer确认收到消息,ack响应
  5. rabbitMQ接收到ack,将队列中的消息删除
  6. 关闭信道。

7、rabbitMQ的消息应答机制ack?

rabbitMQ向消费者传递完消息后,会删除该条消息(kafka中是不删除的,这个是一点差异)

为了保证消息在发送过程中不丢失,rabbitMQ引入了消息应答机制:消费者在接收消息并处理该消息后,告诉rabbitMQ他已经处理了,此时,rabbitMQ就可以把该消息删除了

  1. 自动应答:消息一旦被消费者接收,自动发送ack
  2. 手动应答:消息接收后,不会发送ack,需要手动调用

如何选择应答方式呢?

  1. 如果消息不太重要,丢失也没有影响,那么选择自动ack会比较好--- 性能高,可能丢失数据
  2. 如果不允许消息丢失,那么需要选择在消费完成后手动ack --- 可靠性高,性能稍差
8、rabbitMQ消息的重新入列?

如果消费者由于某些原因失去连接,导致消费者未成功发送ACK确认应答,RabbitMQ将会对未完全处理完的消息重新入队,如果其他消费者可以处理,则该消息将被分配到另一个消费者,从而保证消息未丢失。

9、rabbitMQ的持久化?
  1. 队列持久化
  2. 消息持久化
  3. exchange持久化

持久化只是告诉rabbitMQ将消息保存到磁盘,但是并不能真正的保证数据不丢失(准备从内存往磁盘写的时候rabbitMQ挂掉了)

队列持久化是在定义队列的时候,由durable参数决定的,设置为true的时候,才会持久化队列。

Connection connection = connectionFactory.newConnection();
Channel channel = connection.createChannel();
//第二个餐胡设置为true,代表队列持久化
channel.queueDeclare("queue.persistent.name", true, false, false, null);

消息持久化是在发布消息的时候设置的,

//通过传入MessageProperties.PERSISTENT_PLAIN就可以实现消息持久化
channel.basicPublish("exchange.persistent", "persistent", MessageProperties.PERSISTENT_TEXT_PLAIN, "persistent_test_message".getBytes());

exchange的持久化:如果不设置exchange的持久化对消息的可靠性来说没有什么影响,**但是同样如果exchange不设置持久化,那么当broker服务重启之后,exchange将不复存在,那么既而发送方rabbitmq producer就无法正常发送消息。因此建议同样设置exchange的持久化。

一般只需要:``channel.exchangeDeclare(exchangeName, “direct/topic/header/fanout”, true); 就是在声明的时候讲durable字段设置为true就行了。

10、rabbitMQ的分发机制,以及如何修改?

rabbitMQ默认的分发机制是轮询模式,是公平的,但是实际场景中并不适用,比如consumerA处理消息很快,consumerB处理消息很满,那么轮询的机制就会导致consumerA有很多时间处于空闲,因此,需要修改成能者多劳的模式。

如何实现?

对信道进行设置,通过 BasicQos 方法设置prefetchCount = 1,需要注意的是,不公平分发只在手动ack的时候才会生效。

 

11、rabbitMQ中的预取值?

预取值是消费者信道最大传输信息数。上面说了如何设置rabbitMQ 的不公平分发,即设置prefetchCount = 1,其实这个值是可以设置更大的数字的,这个设置的值,就是预取值。

我们将慢的消费者preCount取值为5,快的消费者预取值为2,然后发送7条消息,实际慢的服务器会收到5条消息(第一条处理的时候,其余四条会堆积),快的服务器只会收到2条消息。

这是因为快的消费者信道满了,不能再发送消息,所以消息只能发送给慢的服务器,这就是basicQos用法。

12、rabbitMQ的发布确认机制?

发布确认机制有三种方式:

  1. 单个确认发布:一种简单的同步确认发布的方式,也即是只有前一个发布的消息确认发布之后,后续的消息才可以继续发布。 缺点就是发布速度慢,没有确认发布的消息会阻塞后续消息发布,适用于每秒数百条消息吞吐量的环境。
  2. 批量确认发布:也是同步确认的方式,一样会阻塞后续消息的发布,但是可以先发布一批消息,然后一起确认,提高吞吐量,缺点就是发生故障导致发布失败后,不知道那个消息有问题,必须将整个批处理保存在内存中,来记录重要的信息,然后重新发布消息
  3. 异步确认发布:效率和可靠性都比较高,利用回调函数来达到消息的可靠性传递(这种情况下,所有在该信道上发布的消息都会被指派一个唯一的ID ,一旦消息被投递到所有匹配的队列后,rabbitMQ就会发送一个确认给生产者(包含这个消息的唯一id),这样生产者就知道消息已经正确的到达目的队列了,如果rabbitMQ没能处理这个消息,也会发送一个NACK 的消息给producer,这时就可以进行重试操作。)
13、如何处理异步未确认的消息?

简陋版本:

将未确认的消息放到一个基于内存的,能够被发布线程访问的队列中,能够在confirm callbacks线程和发布线程之间进行消息传递。

比如使用ConcurrentSkipListMap,这个是基于并发的有序map集合。(ConcurrentHashMap是无序的)

1、RabbitMQ的消息确认机制确保了消息的可靠抵达,其中ConfirmCallback是其中一种实现方式
  1. ConfirmCallback是一个回调函数,用于在消息被确认时进行回调,以确保消息已经被正确地发送到RabbitMQ Broker并被处理。当生产者发送消息时,可以通过调用channel的confirmSelect()方法将channel设置为confirm模式,然后通过添加ConfirmCallback回调函数来处理消息确认。
  2. 当消息被发送到Broker后,如果Broker成功地将消息路由到目标队列,则会调用ConfirmCallback回调函数的handleAck()方法,表示消息已被确认。如果Broker无法将消息路由到目标队列,则会调用handleNack()方法,表示消息未被确认
  3. 使用ConfirmCallback可以确保消息已经被正确地发送到RabbitMQ Broker并被处理,从而避免了消息丢失或重复发送的情况同时,ConfirmCallback还可以在消息未被确认时进行重试或记录日志等操作,以确保消息的可靠性和稳定性
2、RabbitMQ的ReturnCallback机制是为了解决消息无法路由到指定队列的问题
  1. 当发送的消息无法被路由到指定队列时,RabbitMQ会将消息返回给生产者,这时候如果生产者设置了ReturnCallback回调函数,就可以在回调函数中处理这种情况
  2. ReturnCallback机制的使用场景一般是在消息发送时,指定了mandatory参数为true,表示如果消息无法被路由到指定队列,则将消息返回给生产者。如果mandatory参数为false,则消息会被直接丢弃。
  3. 当生产者设置了ReturnCallback回调函数后,RabbitMQ在将消息返回给生产者时,会触发该回调函数。在ReturnCallback回调函数中,可以处理消息无法路由的情况,例如重发消息、记录日志等。
  4. 需要注意的是,ReturnCallback机制只有在消息被发送到交换机后,才会触发。如果消息发送的交换机不存在,或者路由键不符合任何绑定规则,消息会被直接丢弃,不会触发ReturnCallback回调函数
3、备份交换机

通过mandatory参数和消息回退机制,可以处理交换机投递失败的消息,但是消息回退给生产者后,有时候并不知道如何处理这些消息,最多就是打印一个日志,存在缓存中,然后定时重试投递,还要考虑多次投递失败后的告警等等。如果生产者多了的话,每个生产者都要写这些逻辑代码,无疑大大增加了生产者的复杂性。

rabbitMQ中有死信队列可以处理消费失败的信息,但是当前所说的这些消息根本就没有进入队列,因此死信队列也没有用。在 RabbitMQ 中,有一种备份交换机的机制存在,可以很好的应对这个问题。

备份交换机可以理解为 RabbitMQ 中交换机的“备胎”,当我们为某一个交换机声明一个对应的备份交换机时,就是为它创建一个备胎,当交换机接收到一条不可路由消息时,将会把这条消息转发到备份交换机中,由备份交换机来进行转发和处理,通常备份交换机的类型为 Fanout ,这样就能把所有消息都投递到与其绑定的队列中,然后我们在备份交换机下绑定一个队列,这样所有那些原交换机无法被路由的消息,就会都进入这个队列了。 当然,还可以建立一个报警队列,用独立的消费者来进行监测和报警。

mandatory 参数与备份交换机可以一起使用的时候,如果两者同时开启,备份交换机的优先级更高。

在这里插入图片描述

 

14、rabbitMQ中的交换机exchange

rabbitMQ消息传递的模型核心思想是:生产者生产的消息不直接发送到队列,而是通过交换机。(事实上,生产者压根不知道发送到了哪些队列),交换机的功能十分简单,一方面接收来自生产者的消息,另一方面将消息推入队列。

交换机必须知道如何处理接收到的消息,是放入特定的队列,还是放入很多队列,还是丢弃,这些是由交换机的类型决定的。

bindings:binding其实就是exchange和queue之间的桥梁,即是绑定关系

交换机的类型:

  1. 无名exchange(默认exchange),声明的时候就是一个空字符串,但是通过routingkey绑定queue
  2. 扇出交换机 fanout: 就是将受到的所有消息广播到他知道的所有队列中,routingkey可以是空字符串
  3. 直接交换机 direct:消息只到交换机绑定的队列中,通过routingkey 来绑定,如果所有队列的routingkey都一样,那么就相当于是fanout 交换机了
  4. 主题交换机 topic:topic 交换机的消息的 routing_key 不能随意写,必须满足一定的要求,它必须是一个单词列表,以点号分隔开,类似于正则表达式,*(星号)可以代替一个单词 ;#(井号)可以替代零个或多个单词
  5. 头部交换机 header:不通过RoutingKey进行分发消息,而时通过消息中内容的headers的 key/value(键值对)匹配队列 (性能不高,用的少?)

15、死信和死信队列?

什么是死信?

在rabbitMQ中,消息可能有不同的表现,死信,顾名思义,就是dead message。死信消息通常包括以下几种:

  • 消息被拒绝,即rabbitMQ返回了一个nack信号
  • 消息的TTL过期了
  • 消息队列达到最大长度,后续消息无法入列
  • 消息不符合要求等。。

什么是死信队列?

死信队列就是用于存储死信的队列,死信队列中,有且只有死信构成,不会存在其余类型的消息。

死信队列在rabbitMQ中并不会单独存在,通常死信队列都会绑定一个普通的消息队列,当绑定的消息队列中有消息变成死信了,那么这个消息就会重新被交换机路由到指定的死信队列中,我们可以通过对这个死信队列进行监听,从而手动去对这些消息进行补偿。

如何使用死信队列?

在 RabbitMQ 中,死信队列的标识为 x-dead-letter-exchange ,通过观察死信队列的标识,我们不难发现,其标识最后为 exchange ,即 RabbitMQ 中的交换机,RabbitMQ 中的死信队列就是由死信交换机而得出的,要想使用死信队列,我们需要首先声明一个普通的消息队列,并将死信队列的标识绑定到这个普通的消息队列上。

16,rabbitMQ中处理消息失败了怎么办?

生产环境中,使用MQ的时候设计两个队列:一个是业务队列,专门用来处理消息,另外一个死信队列,用来处理异常情况。

比如,消费者消费消息时,数据库等发生了故障,无法将数据写入数据库,这时,消费者就可以将该条消息返回一个nack:

  • 一旦返回nack,MQ就会将这条消息转入提前设置好的死信队列中
  • 数据库故障期间,处理的所有失败消息都会转入死信队列
  • 消费者设置一个后台线程,监控数据库是否正常
  • 一旦发现数据库正常后,这个线程就把死信队列中的消息取出来,重新消费

在这里插入图片描述

 

17、rabbitMQ的延迟队列?

延迟队列的内部是有序的,最重要的特性就是体现在它的延迟属性上,延迟队列中的元素就是希望在指定的时间到了之后,将他取出来消费

延迟队列的使用场景(在某个事件发生之后或者之前的指定时间内要做的任务)

  • 订单在十分钟内未支付自动取消
  • 新用户注册后,三天没有登录短信提醒
  • 用户退款,三天内没有 处理通知相关运营人员
  • 预定会议后,提前十分钟通知与会人员

 18、rabbitMQ的延迟队列怎么实现?

18.1:死信队列 +TTL 过期时间

rabbitMQ并没有直接提供延迟队列功能,但是可以通过 死信队列 +TTL 过期时间进行实现:TTL就是消息或者队列的过期功能。当消息过期就会进到死信队列,死信队列和普通队列没啥区别,然后我们只需要配置一个消费者来消费死信队列里面的消息就可以了

注意: RabbitMQ只会对队列头部的消息进行过期淘汰,消息是否过期是在即将投递消息到消费者之前判定的,如果队列出现消息堆积情况,则已过期的消息还是会继续存活的,比如过期时间设置在消息内,由于消息队列是先进先出的,假设第一个消息过期时间是10s,第二个消息过期时间是1s,一前一后几乎同时发消息,1s的已经过期了,但是10s的还没有过期,那么第二个消息也不会从队列中剔除转到死信队列,从而导致消息不断积压。

 

18.2:基于插件实现延迟队列

rabbitMQ还可以通过安装插件来实现延迟队列,安装过程略。

使用延迟插件的情况下,延迟时间短的消息会被优先消费,解决了死信队列+TTL过期时间导致的消息积压问题。(通过交换机延迟消息的方式来实现消息的延迟)

 

上面介绍了rabbitMQ中的延迟队列实现方式,当然还有一些其他的选择,比如利用java自带的DelayQueue, 利用redis中的zset,利用kafka的时间轮等等,这些方式各有特点,可以根据不同的适用场景选择不同的实现方式。

1、DelayQueue

  • DelayQueue是java自带的一个BlockingQueue,用于放置实现了Delayed接口的对象。队列中的对象只能在其到期的时候才能从队列中取出。
  • 添加元素:触发Delayed接口中的compareTo方法按照时间进行排序,排在队列头部是最早到期的,越往后越晚到期
  • 查看元素:消费者线程查看元素,调用getDelay方法,如果方法返回值小于等于0,说明元素已经到期,则会取出,否则,返回wait的时间,wait时间之后,在从头部取出元素
  • 注意,不能将null放入DelayQueue中。

大数据必学Java基础(六十七):DelayQueue深入了解 - 知乎

2、redis中的zeset

  • redis 中,zset的存储结构是k-v,其中value包含了memmber和score,通过score可以进行排序
  • 生产者将需要延迟发送的数据存redis中的 zset
  • 消费者循环从redis的zset队列中获取数据,消费时间到了的数据,然后删除已经消费了的数据

3、kafka实现延迟队列

  • 创建一个专门的Topic用于存储延迟消息
  • 在消息的key中设置延迟时间戳。可以使用当前时间戳加上延迟时间作为key
  • 消费者进程不断检查消息的key中的时间戳是否已经过期。
    • 可以使用当前时间戳与消息的key中的时间戳进行比较。如果时间戳已经过期,则将消息重新发送到目标Topic中,例如"target-messages"
    • 如果时间戳还未过期,则将消息重新发送到"delayed-messages" Topic中,并设置一个新的延迟时间戳。

kafka实现延迟队列需要消费者定期从delayed-messages 中查看消息,消费者进程宕机就会影响延迟队列功能,轮询检查也会消耗资源,延迟精度只能达到毫秒级别。

需要注意的是,Kafka并不是专门为延迟队列设计的,因此在实现过程中需要考虑一些细节问题,比如消息的重复消费、消息的顺序等。

19、rabbitMQ的幂等性?

幂等性是指用户对统一操作发起的一次或者多次请求结果都是一致的,不会因为重复消费而导致结果不一样。

rabbitmq 把消息发给消费者进行消费,消费者消费成功后返回ack消息,但是这个时候网络中断等原因,rabbitMQ没有收到ack消息,让rabbitMQ误以为消息消费失败,然后rabbitMQ把消息重新发送给其他消费者,或者等网络重连后重新发给这个消费者,这个时候就会造成重复消费问题。

解决思路:

消费者解决幂等性的一般方法就是使用一个唯一标识ID,消费前先判断是否已经消费过。

  1. 唯一id,数据库主键去重
  2. redis原子性,利用setnx命令天然的幂等性。

20、优先级队列?

顾名思义,优先级队列可以对元素设置优先级,优先级高的消息具备优先消费的特权。

RabbitMQ支持优先级队列,在声明channel的时候添加 “x-max-priority”属性,RabbitMQ中优先级大小支持0-255,但是实际使用,我们可以根据需要设置最大的优先级值。

当然,在消费端速度大于生产端速度,且broker中没有消息堆积的话,对发送的消息设置优先级也没什么实际意义,因为发送端刚发送完一条消息就被消费端消费了,那么就相当于broker至多只有一条消息,那么对于单条消息来说优先级是没有什么意义的

21、惰性队列?

RabbitMQ从3.6版本引入了惰性队列这一概念,惰性队列会尽可能的将消息存入磁盘中,消费者消费到响应的消息时才会被加载到内存中,他的一个重要的目标是支持更多的消息存储。

  • 默认情况下,当生产者将消息发送到RabbitMQ的时候,队列中的消息会尽可能地存储在内存之中,这样可以更加快速地将消息发送给消费者。即使是持久化的消息,在被写入磁盘的同时也会在内存中驻留一份备份。当RabbitMQ需要释放内存的时候,会将内存中的消息换页至磁盘中,这个操作会耗费较长的时间,也会阻塞队列的操作,进而无法接收新的消息。虽然RabbitMQ的开发者们一直在升级相关的算法,但是效果始终不太理想,尤其是在 消息量特别大的时候。
  • 惰性队列会将接收到的消息直接存入文件系统,而不管是持久化的或者是非持久化的,这样可以减少内存的消耗,但是会增加I/O的使用,如果消息是持久化的,那么这样的I/O操作不可避免,惰性队列和持久化的消息可谓是“最佳拍档”。
  • 注意如果惰性队列中存储的是非持久化的消息,内存的使用率会一直很稳定,但是重启之后消息一样会丢失。
  • 使用:"x-queue-mode"设置为 "lazy"

22、RabbitMQ集群?

RabbitMQ集群有两种模式:普通集群和镜像集群。

1、普通集群:

  • 就是将RabbitMQ部署到多台服务器上,每台服务器启动一个RabbitMQ实例,多个实例之间进行消息通信。在普通集群上,我们创建的队列queue,他的元数据(queue的一些配置信息)会在所有的RabbitMQ实例中进行同步,但是队列中的消息只会存在于一个RabbitMQ实例上,不会同步到其他队列。
  • 当消费消息的时候,如果连接到了另外一个实例,那么实例会通过元数据定位到queue所在的位置,然后访问queue所在的实例,拉取数据过来发送给消费者
  • 这种集群可以提高RabbitMQ的消费吞吐能力,但是无法保证高可用,因为一旦存消息的RabbitMQ挂了,消息就没办法访问了。

在这里插入图片描述

 

2、镜像集群

  • 和普通集群的最大区别就是queue数据不在单独存在一台机器上,而是同时存储在多台机器上。也就是说,每个RabbitMQ都至少有一份镜像数据(副本数据)。
  • 每次写入消息的时候都会自动把数据同步到多台实例上去,这样即便一台机器宕机,其他机器上还有副本数据可以继续提供服务,继而实现了高可用。

在这里插入图片描述

 

23、rabbitMQ中的federation exchange,联邦交换机?

应用场景:

有时候为了容灾等原因,会将rabbitMQ部署在不同的城市,当跨距离传输的时候,会有网络延迟等原因。federation exchange 提供了一个能力:可以让原本发送给上游交换器的消息路由到本地的某个队列中,联邦队列则允许一个本地消费者接收到来自上游队列的消息

federation的原理:

  • 联邦交换机首先需要创建出下游队列(广州的broker3),
  • federation插件会在北京(broker1)上建立一个同名的交换器,同时内部创建一个内部交换机,并通过路由将两个交换机绑定起来。
  • federation插件还会在broker1 上简历一个队列,并和broker3中的交换机之间建立一条AMQP连接来实时地消费队列federation: exchangeA.broker3中的数据
  • 对外而言,客户端只能看到federation连接是建立在broker1 exchangeA 和brokr3 exchangeA 之间。

 

24、rabbitMQ中的shovel?
  • shovel插件同样是为了解决数据的转发问题。它能够可靠地从源端broker中的队列中拉取数据并转发到目的端broker的交换机中
  • 作为源端的队列和作为目的端的交换机可以位于一个broker中(没理解),也可以位于不同的broker上
  • shovel的优点:松耦合,解决不同Broker、集群、用户、vhost、MQ和Erlang版本移动消息,支持广域网,可以容忍糟糕的网络,能保证消息的可靠性,高度定制,当Shovel成功连接后,可以配置。

 

拓展,实现一个定时任务的方法:

  1. 遍历所有的任务,根据时间来判断是否需要执行
    1. 优点:逻辑简单
    2. 缺点:每秒都要遍历所有的任务,很多距离到期时间还远的任务做了很多无用功,数据量大的时候,会导致任务执行延迟,占用CPU
  2. 根据执行时间采用小顶堆算法,每次都取最小的时间进行判读
    1. 优点:相比较全部遍历,比较次数变少
    2. 缺点:数据量大的时候,每次插入新数据,时间复杂度为Ologn, 但是还有可能导致任务延迟,(java中的Timer,ScheduledThreadPoolExcutor 就是这种做法)
  3. jdk自带的DelayQueue,每次插入都要重新排队,时间复杂度Onlogn
  4. 时间轮
    1. kafka时间轮的原理:秒懂 Kafka 时间轮(TimingWheel) - 知乎
    2. 避免时间轮的空转:从带圈数的时间轮改为多层时间轮:
      1. 其实就是从单纯小圈转改成:先大圈转,转到一定位置后,然后在小圈转
      2. 【第一层的跨度为1ms,第二层的跨度为20ms,第三层的跨度为400ms。那么例如我们放入的任务为501ms,则将会放入第三层的第一个节点(501%400=101),冗余了101ms,当第三层的指针转到第一个节点时,则将101ms的任务转移到第二层,再将任务放入到第二层的第5个节点(101%20=1)。当第二层的指针转移到低5个节点的时候发现冗余时间,则将任务转移到第一层的第一个节点,第一层转移一次就执行了。这么做的好处是避免了单轮空转的情况。】

动图封面

 

img

 

相关文章:

RabbitMQ学习笔记

1、什么是MQ? MQ全称message queue(消息队列),本质是一个队列,FIFO先进先出,是消息传送过程中保存消息的容器,多 用于分布式系统之间进行通信。 在互联网架构中,MQ是一种非常常见的…...

【C# Programming】类、构造器、静态成员

一、类 1、类的概念 类是现实世界概念的抽象:封装、继承、多态数据成员: 类中存储数据的变量成员方法: 类中操纵数据成员的函数称为成员方法对象:类的实例类定义 class X {…} var instance new X(…); 2、实例字段 C#中…...

软件层面缓存基本概念与分类

缓存 缓存基本概念(百度百科) 缓存(cache),原始意义是指访问速度比一般随机存取存储器(RAM)快的一种高速存储器,通常它不像系统主存那样使用DRAM技术,而使用昂贵但较快…...

单片机有哪些分类?

单片机有哪些分类? 1.AVR单片机-----速度快,一个时钟周期执行一条指令,而普通的51单片机需要12个时钟周期执行一条指令。当然,Atmel公司出品的AT89LP系列单片机也是一个时钟执行一条指令,但目前还未普及。AVR单片机比51单片机多…...

高阶数据结构-----三种平衡树的实现以及原理(未完成)

TreeMap和TreeSet的底层实现原理就是红黑树 一)AVL树: 1)必须是一棵搜索树:前提是二叉树,任取一个节点,它的左孩子的Key小于父亲节点的Key小于右孩子节点的Key,中序遍历是有序的,按照Key的大小进行排列,高度平衡的二叉…...

北斗高精度组合导航终端

UWB(Ultra-Wideband)、卫星定位(GNSS),以及IMU(Inertial Measurement Unit)的组合定位系统结合了多种传感器和定位技术,以提供高精度、高可靠性的位置估计。这种组合定位系统在各种应…...

低代码平台是否能替代电子表格?

在计算机技术普及之前,会计、助理或者是销售人员,都需要用纸和笔来记录和维护每一笔交易。计算机技术兴起之后,一项技术发明——电子表格的出现改变了低效的状况。电子表格的第一个版本出现在1977年,一个名为“VisiCalc”的程序。…...

qt多个信号如何关联一并处理

主要方法&#xff1a; 首先&#xff0c;需要创建一个包含自定义信号和槽的Qt类。假设要创建一个名为MyObject的类&#xff0c;并在其中定义一个自定义信号和一个槽。这个类的头文件可能如下所示&#xff1a; #ifndef MYOBJECT_H #define MYOBJECT_H#include <QObject>c…...

【python爬虫】12.建立你的爬虫大军

文章目录 前言协程是什么多协程的用法gevent库queue模块 拓展复习复习 前言 照旧来回顾上一关的知识点&#xff01;上一关我们学习如何将爬虫的结果发送邮件&#xff0c;和定时执行爬虫。 关于邮件&#xff0c;它是这样一种流程&#xff1a; 我们要用到的模块是smtplib和emai…...

2023数学建模国赛C题思路--蔬菜类商品的自动定价与补货决策

C 题 蔬菜类商品的自动定价与补货决策 在生鲜商超中&#xff0c;一般蔬菜类商品的保鲜期都比较短&#xff0c;且品相随销售时间的增加而变差&#xff0c; 大部分品种如当日未售出&#xff0c;隔日就无法再售。因此&#xff0c;商超通常会根据各商品的历史销售和需 求情况每天进…...

vue2与vue3的使用区别

1. 脚手架创建项目的区别&#xff1a; vue2: vue init webpack “项目名称”vue3: vue create “项目名称” 或者vue3一般与vite结合使用: npm create vitelatest yarn create vite2. template中结构 vue2: template下只有一个元素节点 <template><div><div…...

Apache httpd漏洞复现

文章目录 未知后缀名解析漏洞多后缀名解析漏洞启动环境漏洞复现 换行解析漏洞启动环境漏洞复现 未知后缀名解析漏洞 该漏洞与Apache、php版本无关&#xff0c;属于用户配置不当造成的解析漏洞。在有多个后缀的情况下&#xff0c;只要一个文件含有.php后缀的文件即将被识别成PHP…...

【漏洞复现】时空智友企业流程化管控系统文件上传

漏洞描述 通过时空智友该系统,可让企业实现流程的自动化、协同上提升、数据得洞察及决策得优化,来提高工作效率、管理水平及企业的竞争力。时空智友企业流程化 formservice接口处存有任意文件上传漏洞,未经认证得攻击者可利用此接口上传后门程序,可导致服务器失陷。 免责…...

elasticsearch的DSL查询文档

DSL查询分类 查询所有&#xff1a;查询出所有数据&#xff0c;一般测试用。例如&#xff1a;match_all 全文检索&#xff08;full text&#xff09;查询&#xff1a;利用分词器对用户输入内容分词&#xff0c;然后去倒排索引库中匹配。例如&#xff1a; match_query multi_ma…...

IP地址、子网掩码、网络地址、广播地址、IP网段

文章目录 IP地址IP地址分类子网掩码网络地址广播地址IP网段 本文主要讨论iPv4地址。 IP地址 实际的 IP 地址是一串32 比特的数字&#xff0c;按照 8 比特&#xff08;1 字节&#xff09;为一组分成 4 组&#xff0c;分别用十进制表示然后再用圆点隔开&#xff0c;这就是我们平…...

ffmpeg-android studio创建jni项目

一、创建native项目 1.1、选择Native C 1.2、命名项目名称 1.3、选择C标准 1.4、项目结构 1.5、app的build.gradle plugins {id com.android.application }android {compileSdk 32defaultConfig {applicationId "com.anniljing.ffmpegnative"minSdk 25targetSdk 32…...

智慧公厕是将数据、技术、业务深度融合的公共厕所敏捷化“操作系统”

文明社会的进步离不开公共设施的不断创新和提升。而在这些公共设施中&#xff0c;公共厕所一直是一个备受关注和改善的领域。近年来&#xff0c;随着智慧城市建设的推进&#xff0c;智慧公厕成为了城市管理的重要一环。智慧公厕不仅仅是为公众提供方便和舒适的便利设施&#xf…...

JVM中JAVA对象和数组内存布局

对象 数组 在Java中&#xff0c;所有的对象都是一种特殊的数组&#xff0c;它们的元素可以是基本数据类型、其他对象引用或者其他任何类型。Java对象和数组的内存布局包含以下部分&#xff1a; 1.对象头&#xff08;Object Header&#xff09; 每个Java对象都有一个对象头&am…...

【2023年数学建模国赛】赛题发布

2023数学建模国赛赛题已经发布啦&#xff0c;距离赛题发布已经过去三个小时了&#xff0c;大家是否已经确定题目呢&#xff1f;学姐后续会持续更新赛题思路与代码~...

Java HashMap源码学习

Java HashMap源码学习 基本使用 包含创建&#xff0c;添加&#xff0c;删除&#xff0c;迭代&#xff0c;打印 val map java.util.HashMap<Int, Int>() map.put(1, 2) map.put(2, 2) map.put(3, 2) map.remove(1) map.forEach {println("it.key${it.key}, it.va…...

Gin中用于追踪用户的状态的方法?!!!

Gin中的Cookie和Session的用法 文章目录 Gin中的Cookie和Session的用法介绍Cookie代码演示 Session代码展示 介绍 cookie 和 session 是 Web 开发中常用的两种技术&#xff0c;主要用于跟踪用户的状态信息。 Cookie func (c *Context) Cookie(name string, value string, max…...

HTTP代理与HTTPS代理在工作流程上有哪些区别

HTTP代理和HTTPS代理都是常见的代理技术&#xff0c;可以实现隐藏客户端IP地址、突破网络封锁、加速网站访问、过滤网络内容等功能。本文将介绍HTTP代理和HTTPS代理在工作流程上的区别。 HTTP代理的工作流程 客户端向代理服务器发送HTTP请求 当客户端需要访问某个网站时&#x…...

Docker从认识到实践再到底层原理(二-2)|Namespace+cgroups

前言 那么这里博主先安利一些干货满满的专栏了&#xff01; 首先是博主的高质量博客的汇总&#xff0c;这个专栏里面的博客&#xff0c;都是博主最最用心写的一部分&#xff0c;干货满满&#xff0c;希望对大家有帮助。 高质量博客汇总 然后就是博主最近最花时间的一个专栏…...

算法的概述

算法分析&#xff1a; 解决同一问题的算法可以有多种。 我们希望从中选出最优的算法&#xff0c;效率高或者存储空间小。为此&#xff0c;需要对算法进行评估&#xff0c;分析。 通常考虑两个度量&#xff1a; 1、 时间复杂度&#xff1a;算法运行时需要的总步数&#xff0c…...

菜鸟教程《Python 3 教程》笔记(19):错误与异常

菜鸟教程《Python 3 教程》笔记&#xff08;19&#xff09; 19 错误和异常19.1 assert&#xff08;断言&#xff09;19.2 异常处理19.2.1 try/except19.2.2 try/except...else19.2.3 try-finally 语句 19.3 抛出异常19.4 用户自定义异常19.5 清理行为19.5.1 定义清理行为19.5.2…...

空气净化器上亚马逊美国站需要办理什么认证?空气净化器UL867测试报告如何办理?

空气净化器又称“空气清洁器”、空气清新机、净化器&#xff0c;是指能够吸附、分解或转化各种空气污染物&#xff08;一般包括PM2.5、粉尘、花粉、异味、甲醛之类的装修污染、细菌、过敏原等&#xff09;&#xff0c;有效提高空气清洁度的产品&#xff0c;主要分为家用 、商用…...

SpringBoot的测试方案

写完代码后&#xff0c;测试是必不可少的步骤&#xff0c;现在来介绍一下基于SpringBoot的测试方法。 基于SpringBoot框架写完相应功能的Controller之后&#xff0c;然后就可以测试功能是否正常&#xff0c;本博客列举MockMvc和RestTemplate两种方式来测试。 准备代码 实体类…...

华为OD机考算法题:字符串解密

目录 题目部分 解读与分析 代码实现 题目部分 题目字符串解密题目说明给定两个字符串string1和string2。 string1是一个被加扰的字符串。string1由小写英文字母&#xff08;a~z&#xff09;和数字字符&#xff08;0~9&#xff09;组成&#xff0c;而加扰字符串由0~9、a~f 组…...

unity 锚点设置

锚点聚合情况&#xff1a; 一个2d物体的位置 pos x pos y 是中心点相对于锚点的偏移量&#xff1a; 中心点就是位置。 按住shift 锚点和中心点都会被设置&#xff1a; 按住Alt&#xff1a; 同时按住shift和alt &#xff1a; 中心点 锚点 UI元素在对应的位置上。 锚点拉伸情况…...

Hadoop:HDFS--分布式文件存储系统

目录 HDFS的基础架构 VMware虚拟机部署HDFS集群 HDFS集群启停命令 HDFS Shell操作 hadoop 命令体系&#xff1a; 创建文件夹 -mkdir 查看目录内容 -ls 上传文件到hdfs -put 查看HDFS文件内容 -cat 下载HDFS文件 -get 复制HDFS文件 -cp 追加数据到HDFS文件中 -appendTo…...

建设网站需要哪些手续/下载百度网盘app

/***题目:旅店信息管理系统**小组成员&#xff1a;闫若琳 戴雨晨 马渊沐 张子飞 李闯王浩 崔以博 孙浩浩 李春普 温健成*/#include #include #include #include #define MIN 1#define MAX 30#define LEN sizeof(struct Hotel)//用LEN代替结构体的"长度"void regeist(…...

四川省建设建设监理协会网站/怎么打广告宣传自己的产品

Frontend Knowledge Structure https://github.com/JacksonTian/fks 图片的形式具有诸多的不便。缺失源图的我们&#xff0c;无法为此图贡献些什么&#xff0c;随着时间的迁移&#xff0c;或许有些技术点会发生改变&#xff0c;所以有了这个GitHub项目。我们可以通过协作的方式…...

长沙设计网站建设/岳阳网站建设推广

作者&#xff1a;陈诚 团队&#xff1a;腾讯移动品质中心TMQ 一、androidUI过度渲染概述 1、从android卡顿说起 通常我们可以从各种渠道听到用户反馈app卡顿&#xff0c;究竟是什么用户觉得卡顿呢&#xff1f;因为大多数手机的屏幕刷新频率是60hz&#xff0c;如果在1000/60…...

网站有几个后台/网站外包一般多少钱啊

更多编程教程请到&#xff1a;菜鸟教程 https://www.piaodoo.com/ 友情链接&#xff1a; 高州阳光论坛https://www.hnthzk.com/人人影视http://www.sfkyty.com/这两个函数主要提供&#xff0c;基于字典的访问局部和全局变量的方式。在理解这两个函数时&#xff0c;首先来理解…...

网站建设应该注意哪些/发帖子的网站

网络编程的调试手段netstat工具-a 列出系统中所有套接口的状态netstat -a | grep <target> : 只提取关注的信息ps -Al 查看进程的状态和关系Posix 信号处理信号是发生某事件时对进程的通知&#xff0c;有时称为软中断。它一般是一步的&#xff0c;这就是说&#xff0c;进…...

建筑设计网站 知乎/海淀区seo搜索引擎优化企业

想在centos6.9上安装docket&#xff0c;不过因为内核版本是2.6的故而想升级到最新的内核版本 晚上有编译升级的比较麻烦&#xff0c;不过有助于理解内核升级&#xff0c;我使用的直接升级到最新版方法 1. 导入public key rpm --import https://www.elrepo.org/RPM-GPG-KEY-elre…...