RabbitMQ延时消息实现方案(岳小均)

合集下载

rabbitmq的延迟消息队列实现

rabbitmq的延迟消息队列实现

rabbitmq的延迟消息队列实现第⼀部分:延迟消息的实现原理和知识点使⽤RabbitMQ来实现延迟任务必须先了解RabbitMQ的两个概念:消息的TTL和死信Exchange,通过这两者的组合来实现上述需求。

消息的TTL(Time To Live)消息的TTL就是消息的存活时间。

RabbitMQ可以对队列和消息分别设置TTL。

对队列设置就是队列没有消费者连着的保留时间,也可以对每⼀个单独的消息做单独的设置。

超过了这个时间,我们认为这个消息就死了,称之为死信。

如果队列设置了,消息也设置了,那么会取⼩的。

所以⼀个消息如果被路由到不同的队列中,这个消息死亡的时间有可能不⼀样(不同的队列设置)。

这⾥单讲单个消息的TTL,因为它才是实现延迟任务的关键。

可以通过设置消息的expiration字段或者x-message-ttl属性来设置时间,两者是⼀样的效果。

只是expiration字段是字符串参数,所以要写个int类型的字符串:当上⾯的消息扔到队列中后,过了3分钟,如果没有被消费,它就死了。

不会被消费者消费到。

这个消息后⾯的,没有“死掉”的消息对顶上来,被消费者消费。

死信在队列中并不会被删除和释放,它会被统计到队列的消息数中去。

单靠死信还不能实现延迟任务,还要靠Dead Letter Exchange。

Dead Letter ExchangesExchage的概念在这⾥就不在赘述。

⼀个消息在满⾜如下条件下,会进死信路由,记住这⾥是路由⽽不是队列,⼀个路由可以对应很多队列。

1. ⼀个消息被Consumer拒收了,并且reject⽅法的参数⾥requeue是false。

也就是说不会被再次放在队列⾥,被其他消费者使⽤。

2. 上⾯的消息的TTL到了,消息过期了。

3. 队列的长度限制满了。

排在前⾯的消息会被丢弃或者扔到死信路由上。

Dead Letter Exchange其实就是⼀种普通的exchange,和创建其他exchange没有两样。

RabbitMQ设置消息的TTL(过期时间)

RabbitMQ设置消息的TTL(过期时间)

RabbitMQ设置消息的TTL(过期时间)我们在RabbitMQ中发布消息时,在代码中有两种⽅法设置某个队列的消息过期时间:1、针对队列来说,可以使⽤x-message-ttl参数设置当前队列中所有消息的过期时间,即当前队列中所有的消息过期时间都⼀样;2、针对单个消息来说,在发布消息时,可以使⽤Expiration参数来设置单个消息的过期时间。

以上两个参数的单位都是毫秒,即1000毫秒为1秒。

如果以上两个都设置,则以当前消息最短的那个过期时间为准。

接下来让我们在在代码中相见!针对队列来说://⾸先创建⼀个连接⼯⼚对象var factory = new ConnectionFactory() { HostName = "localhost", UserName = "yyt", Password = "yyt888888",VirtualHost="log" };//然后使⽤⼯⼚对象创建⼀个TCP连接using (var connection = factory.CreateConnection()){//在当前连接上创建⼀根通信的虚拟管道using (var channel = connection.CreateModel()) {//声明⼀个交换机channel.ExchangeDeclare("e.log", "direct");//声明⼀个队列,设置arguments的参数x-message-ttl为10000毫秒channel.QueueDeclare(queue: "q.log.error",durable: false,exclusive: false,autoDelete: false,arguments: new Dictionary<string, object> {{ "x-message-ttl",10000}//x-message-ttl即设置当前队列消息的过期时间。

rabbitmq的使用方法

rabbitmq的使用方法

rabbitmq的使用方法RabbitMQ是一个开源的消息代理软件,用于实现异步消息传递。

以下是使用RabbitMQ的一些基本方法:1. 安装和配置:首先,你需要从RabbitMQ的官网下载并安装RabbitMQ 服务器。

安装完成后,你可以通过浏览器访问RabbitMQ的管理界面,进行基本的配置。

2. 创建队列:在RabbitMQ中,消息被存储在队列中。

你可以使用RabbitMQ的管理界面或者通过编程的方式创建队列。

例如,使用Python 的pika库,你可以这样创建一个队列:```pythonimport pikaconnection = (('localhost'))channel = ()_declare(queue='hello')()```3. 发送消息:一旦你创建了队列,你就可以开始发送消息到这个队列。

同样使用pika库,你可以这样发送消息:```pythonimport pikaconnection = (('localhost'))channel = ()_publish(exchange='', routing_key='hello', body='Hello World!') ()```4. 接收消息:要接收消息,你需要创建一个消费者来从队列中获取消息。

消费者可以是任何能够处理RabbitMQ消息的应用程序。

例如,你可以创建一个Python消费者来接收消息:```pythonimport pikaconnection = (('localhost'))channel = ()_declare(queue='hello')def callback(ch, method, properties, body):print(f" [x] Received {body}")_consume(queue='hello', on_message_callback=callback,auto_ack=True)print(' [] Waiting for messages. To exit press CTRL+C')_consuming()```5. 确认消息处理:在RabbitMQ中,你可以选择自动确认(auto_ack)或手动确认(manual_ack)消息处理。

rabbitmq延时队列实现原理

rabbitmq延时队列实现原理

rabbitmq延时队列实现原理以rabbitmq延时队列实现原理为题,本文将对rabbitmq延时队列的实现原理进行详细介绍。

一、什么是延时队列延时队列是一种特殊的消息队列,用于延迟处理消息。

在实际应用中,我们经常会遇到需要在一定时间后执行某个操作的场景,比如订单超时未支付自动取消等。

延时队列就是为了解决这类问题而设计的。

二、rabbitmq延时队列的基本原理rabbitmq延时队列的实现原理其实并不复杂,主要涉及到以下几个组件:1. 生产者:负责产生需要延迟处理的消息,并将消息发送到延时队列中。

2. 延时队列:用于存储需要延时处理的消息,一般是一个普通的消息队列。

3. 消息消费者:负责从延时队列中取出消息,并进行相应的处理。

具体的实现步骤如下:1. 创建一个普通的消息队列,用于存储需要延时处理的消息。

2. 设置消息的过期时间为需要延时的时间,即消息在队列中的存活时间。

3. 创建一个消费者来监听延时队列,当消息过期后,消费者会从队列中取出消息并进行处理。

三、延时队列的实现方法在rabbitmq中,可以通过两种方式来实现延时队列。

1. 使用TTL(Time to Live)和DLX(Dead Letter Exchanges)机制TTL是消息的生存时间,即消息存活在队列中的时间。

DLX则是一种特殊的交换机,用于接收过期消息并转发到指定的队列中。

具体实现步骤如下:1. 创建一个普通的消息队列,并设置队列的TTL。

2. 创建一个DLX交换机,并将该队列绑定到DLX交换机上。

3. 设置DLX交换机的路由规则,将过期消息转发到指定的队列中。

4. 创建一个消费者来监听指定的队列,当消息过期后,消费者会从队列中取出消息并进行处理。

2. 使用rabbitmq-delayed-message-exchange插件rabbitmq-delayed-message-exchange是rabbitmq的一个插件,可以在rabbitmq中直接使用该插件来实现延时队列,而不需要像方式一那样手动配置。

延迟任务的实现总结

延迟任务的实现总结

延迟任务的实现总结上一篇写了使用RabbitMQ来实现延迟任务的实现,其实实现延迟任务的方式有很多,各有利弊,有单机和分布式的。

在这里做一个总结,在遇到这类问题的时候希望给大家一个参考和思路。

延迟任务有别于定式任务,定式任务往往是固定周期的,有明确的触发时间。

而延迟任务一般没有固定的开始时间,它常常是由一个事件触发的,而在这个事件触发之后的一段时间内触发另一个事件。

延迟任务相关的业务场景如下:场景一:物联网系统经常会遇到向终端下发命令,如果命令一段时间没有应答,就需要设置成超时。

场景二:订单下单之后30分钟后,如果用户没有付钱,则系统自动取消订单。

下面我们来探讨一些方案,其实这些方案没有好坏之分,和系统架构一样,只有最适合。

对于数据量较小的情况下,任意一种方案都可行,考虑的是简单明了和开发速度,尽量避免把系统搞复杂了。

而对于数据量较大的情况下,就需要有一些选择,并不是所有的方案都适合了。

1. 数据库轮询这是比较常见的一种方式,所有的订单或者所有的命令一般都会存储在数据库中。

我们会起一个线程去扫数据库或者一个数据库定时Job,找到那些超时的数据,直接更新状态,或者拿出来执行一些操作。

这种方式很简单,不会引入其他的技术,开发周期短。

如果数据量比较大,千万级甚至更多,插入频率很高的话,上面的方式在性能上会出现一些问题,查找和更新对会占用很多时间,轮询频率高的话甚至会影响数据入库。

一种可以尝试的方式就是使用类似TBSchedule或Elastic-Job这样的分布式的任务调度加上数据分片功能,把需要判断的数据分到不同的机器上执行。

如果数据量进一步增大,那扫数据库肯定就不行了。

另一方面,对于订单这类数据,我们也许会遇到分库分表,那上述方案就会变得过于复杂,得不偿失。

2. JDK 延迟队列Java中的DelayQueue位于java.util.concurrent 包下,作为单机实现,它很好的实现了延迟一段时间后触发事件的需求。

Java实现RabbitMq延时队列和死信队列

Java实现RabbitMq延时队列和死信队列

Java实现RabbitMq延时队列和死信队列延时队列:实际是不存在直接可⽤的延时队列,可通过死信消息和死信队列来实现延时队列的功能。

死信交换机: DLX 全称(Dead-Letter-Exchange)。

其实它是个普通的交换机,但它是设置在队列上某个参数的值对应的交换机。

死信队列:如果某个队列上存在参数:x-dead-letter-exchange,当这个队列⾥的消息变成死信消息(dead message)后会被重新Pushlish到 x-dead-letter-exchange 所对应参数值的交换机上,跟这个交换机所绑定的队列就是死信队列。

死信消息:消息被拒绝(basic.reject / basic.nack),并且requeue = false消息TTL过期队列达到了最⼤的长度时过期消息:RabbitMq 有两种设置消息过期的⽅式:创建队列时通过 x-message-ttl 参数指定该队列消息的过期时间,这种队列⾥的消息过期时间全部相同。

⽣产者Pushlish消息时,通过设置消息的 expiration 参数指定过期时间,每个消息的过期时间都不⼀样。

如果两者同时使⽤,过期时间按照⼩的⼀⽅为准,两种⽅式设置的时间都是毫秒。

应⽤场景:延时队列的应⽤场景很多,在我的项⽬开发中也涉及到很多,例如:订单五分钟未⽀付⾃动取消、订单准备超时30分钟推送提醒给门店、订单完成后两⼩时推送评价邀请给⽤户等等,这些间隔指定时间后的操作都可以使⽤延时队列。

上⼀篇⽂章:介绍了RabbitMq的基本操作,要引⼊的包和配置可以参考上⼀篇⽂章。

这⾥就利⽤RabbitMq的死信队列直接来实现延时队列的功能。

⾸先创建⼀个⾃动加载类利⽤Bean在项⽬启动时,⾃动创建延时和死信交换机/延时和死信队列,并将创建好的队列绑定在对应的交换机上。

如果交换机和队列存在的情况下,则不会创建或更新。

这⼀步可减少⼿动或忘记创建队列带来的⿇烦:package com.demo.www.rabbitmq.config;import mon.collect.Maps;import lombok.extern.slf4j.Slf4j;import org.springframework.amqp.core.*;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import java.util.Map;/*** RabbitMq 延时队列实现* @author AnYuan*/@Slf4j@Configurationpublic class DelayQueueConfig {/*** 延迟队列*/public static final String DELAY_EXCHANGE = "delay.queue.business.exchange";public static final String DELAY_QUEUE = "delay.queue.business.queue";public static final String DELAY_QUEUE_ROUTING_KEY = "delay.queue.business.queue.routingKey";/*** 死信队列*/public static final String DEAD_LETTER_EXCHANGE = "delay.queue.deadLetter.exchange";public static final String DEAD_LETTER_QUEUE_ROUTING_KEY = "delay.queue.deadLetter.delay_10s.routingKey";public static final String DEAD_LETTER_QUEUE = "delay.queue.deadLetter.queue";/*** 声明死信交换机* @return deadLetterExchange*/@Beanpublic DirectExchange deadLetterExchange() {return new DirectExchange(DEAD_LETTER_EXCHANGE);}/*** 声明死信队列⽤于接收死信消息* @return deadLetterQueueA*/@Beanpublic Queue deadLetterQueueA() {return new Queue(DEAD_LETTER_QUEUE);}/*** 将死信队列绑定到死信交换机上* @return deadLetterBindingA*/@Beanpublic Binding deadLetterBindingA() {return BindingBuilder.bind(deadLetterQueueA()).to(deadLetterExchange()).with(DEAD_LETTER_QUEUE_ROUTING_KEY);}/*** 声明延时交换机* @return delayExchange*/@Beanpublic DirectExchange directExchange() {return new DirectExchange(DELAY_EXCHANGE);}/*** 将延时队列绑定参数* @return Queue*/@Beanpublic Queue delayQueueA() {Map<String, Object> maps = Maps.newHashMapWithExpectedSize(3);// 队列绑定DLX参数(关键⼀步)maps.put("x-dead-letter-exchange", DEAD_LETTER_EXCHANGE);// 队列绑定死信RoutingKey参数maps.put("x-dead-letter-routing-key", DEAD_LETTER_QUEUE_ROUTING_KEY);// 消息过期采⽤第⼀种设置队列的 ttl 时间,消息过期时间全部相同。

RabbitMQ延时消息实现方案(岳小均)

RabbitMQ延时消息实现方案(岳小均)

最终选择了方案一1.4. 操作步骤4.1. 建立 delay.exchange注意事项:不要设置为Internal,否则将无法接受dead letter4.2. 建立延时队列(delay queue)1. 2. 3. 4. 5. 6.7. 注意事项:按照延期时间配置queue的名字,建议命名规则为delay.{time}.queue,使用delay前缀方便排序和做一些权限控制cos线上集群默认配置了delay.1m.queue、delay.5m.queue、delay.15m.queue三个队列通过TTL设置队列的延期时间,对应不同的QueueMAX length为最大的积压的消息个数,推荐设置为100w~500w之间,推测方法见积压测试结果,超过MAX length限制以后,队列头部的消息会立即转到delay.exchange进行投递,不会造成消息丢失设置dead letter exchange为刚才配置的 delay.exchange注意不要配置"dead letter routing key"否则会覆盖掉消息发送时携带的routingkey,导致后面无法路由4.3. 配置延时路由规则4.3.1. 需要延时的消息到exchange后先路由到指定的延时队列4.3.2. delay.exchange 再重新把消息路由到正常的queue或exchang中4.3.3. 消费者和以前一样从正常queue中接收消费消息5. 积压消息测试结果5.1. 积压测试结论从实现原理上看,对于持久化消息,内存主要保存的是消息的索引数据,从测试结果也可以验证,可以得出以下数据:1. a. i. ii. b. c.2. a. b.3. 1. 从实现原理上看,对于持久化消息,内存主要保存的是消息的索引数据,从测试结果也可以验证,可以得出以下数据:内存占用方面估算消息占用内存的大小确实和消息体本身大小无关,和消息个数直接相关。

RabbitMQ延迟队列

RabbitMQ延迟队列

RabbitMQ延迟队列延迟队列延迟队列⼜被称为延时队列、死信队列,它也是 RabbitMQ 队列中的⼀种,指进⼊该队列中的消息会被延迟消费的队列。

顾名思义,延迟队列和普通队列的区别在于:进⼊普通队列的消息将会⽴即『⾛向』下⼀个环节,⽽下⼀个环节就是消费者;⽽进⼊延迟队列的消息将会被延迟队列『持有』若⼲时间,⽽后才『⾛向』下⼀个环节,⽽且下⼀个环节是另⼀个交换机。

这个『另⼀个交换机』也被称为死信交换机。

RabbitMQ 引⼊延迟队列主要是⽤于『延迟』⼀定时间再处理特定的业务逻辑,⽽这种『延迟』在 RabbitMQ 看来是『⾃动化』的,⽆须⼈为进⾏⼲预。

延迟队列的使⽤价值在于:1. 某些业务需要这种机制。

例如,订单 30 分钟内未⽀付则需要取消订单。

2. 在某种程度上,它可以替代定时任务。

1. 专有词汇与普通的队列⼀样,延迟队列也具有消息、交换机、路由和队列等名词。

不过,它还增加了 3 个专有名词:DLXDead Letter Exchange,死信队列交换机,是⼀种特殊类型的交换机。

DLKDead Letter Routing-Key,死信路由,同样也是⼀种特殊类型的路由。

主要是和 DLX 组合在⼀起构成死信队列。

TTLTime To Live,指进⼊延迟队列中的消息可以存活的时间。

当 TTL ⼀到,将意味着该消息『死了』,从⽽进⼊下⼀个『中转站』,等待被真正的消息队列监听消费。

普通队列 + 三个特殊设置 = 延迟队列/死信队列Dead letter exchange:x-dead-letter-exchange 。

指定延迟队列的『下家』交换机。

Dead letter routing key:x-dead-letter-routing-key 。

延迟队列⾃动向『下家』交换机投递消息时所使⽤的消息的 routing-key。

Message TTL:x-message-ttl 。

延迟队列要持有消息的时长。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

最终选择了方案一
1.
4. 操作步骤
4.1. 建立 delay.exchange
注意事项:
不要设置为Internal,否则将无法接受dead letter
4.2. 建立延时队列(delay queue)
1. 2. 3. 4. 5. 6.
7. 注意事项:
按照延期时间配置queue的名字,建议命名规则为delay.{time}.queue,使用delay前缀方便排序和做一些权限控制cos线上集群默认配置了delay.1m.queue、delay.5m.queue、delay.15m.queue三个队列通过TTL设置队列的延期时间,对应不同的Queue
MAX length为最大的积压的消息个数,推荐设置为100w~500w之间,推测方法见积压测试结果,超过MAX length限制以后,队列头部的消息会立即转到delay.exchange进行投递,不会造成消息丢失设置dead letter exchange为刚才配置的 delay.exchange
注意不要配置"dead letter routing key"否则会覆盖掉消息发送时携带的routingkey,导致后面无法路由
4.3. 配置延时路由规则
4.3.1. 需要延时的消息到exchange后先路由到指定的延时队列
4.3.2. delay.exchange 再重新把消息路由到正常的queue或exchang中
4.3.3. 消费者和以前一样从正常queue中接收消费消息
5. 积压消息测试结果
5.1. 积压测试结论
从实现原理上看,对于持久化消息,内存主要保存的是消息的索引数据,从测试结果也可以验证,可以得出以下数据:
1. a. i. ii. b. c.
2. a. b.
3. 1. 从实现原理上看,对于持久化消息,内存主要保存的是消息的索引数据,从测试结果也可以验证,可以得出以下数据:
内存占用方面估算
消息占用内存的大小确实和消息体本身大小无关,和消息个数直接相关。

消息体为40字节的字符串,积压10万消息,占用101MB内存,23万消息,占用230MB内存消息体为一个整数,积压7万消息,占用64MB内存,24万消息,占用240MB内存
一个消息约占1KB的内存,以10GB内存,留一半余量:5GB/1K=500 0000
线上单个queue推荐线上的max length不要超过500万,根据延迟时间和消息量来调整此值的大小。

消息量估算
以30分钟延迟,每秒发送1000个消息为例,则最大值为:30*60*1000=180 0000
倒推:以500万,30分钟延迟为例,则每秒最多发送的消息个数为:5000000/30/60=2777
消息积压数超过max length以后,消息不会丢失,只。

会导致消息会被提前消费结论:
MAX length推荐这个值设置为,既可以满足业务需求,又不超过内存限制。

100万~500万5.2. 40字节消息积压26万
5.3. 4字节消息积压7万
5.4. 4字节消息积压24万
5.5. 4字节消息积压31万
5.6. 4字节消息积压64万
todo。

相关文档
最新文档