先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7
深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年最新Golang全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Go语言开发知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
如果你需要这些资料,可以添加V获取:vip1024b (备注go)
正文
什么是延时队列
延时队列:顾名思义,是一个用于做消息延时消费的队列。但是它也是一个普通队列,所以它具备普通队列的特性,相比之下,延时的特性就是它最大的特点。所谓的延时就是将我们需要的消息,延迟多久之后被消费。普通队列是即时消费的,延时队列是根据延时时间,多久之后才能消费的。
延时队列使用场景
- 订单在十分钟之内未支付则自动取消。
- 会员续费的定时推送
- 用户注册成功后,如果三天内没有登陆则进行短信提醒。
- 预定会议后,需要在预定的时间点前十分钟通知各个与会人员参加会议。
- 优惠券过期提醒
核心的应用内容基本都是基于需要设定过期时间的
RabbitMQ如何实现延时队列
- 方式1、通过RabbitMQ的高级特性TTL和配合死信队列
- 方式2、安装rabbitmq_delayed_message_exchange插件
RabbitMQ中的高级特性TTL
TTL是什么呢?TTL是RabbitMQ中一个消息或者队列的属性,表明一条消息或者该队列中的所有消息的最大存活时间,单位是毫秒,为什么延时队列要介绍它?TTL就是一种消息过期策略。给我们的消息做过期处理,当消息在队列中存活了指定时候之后,改队列就会将这个消息直接丢弃。在RabbitMQ中并没有直接实现好的延时队列,我们可以使用TTL这种高级特性,然后配合死信队列,即可实现延时队列的功能。
那么,如何设置这个TTL值呢?有两种方式,第一种是在创建队列的时候设置队列的“x-message-ttl”属性,如下:
方式一:
Map<String, Object> args = new HashMap<String, Object>();
args.put(“x-message-ttl”, 6000);
channel.queueDeclare(queueName, durable, exclusive, autoDelete, args);
使用这种方式,消息被设定TTL,一旦消息过期,就会被队列丢弃
方式二:
AMQP.BasicProperties.Builder builder = new AMQP.BasicProperties.Builder();
builder.expiration(“6000”);
AMQP.BasicProperties properties = builder.build();
channel.basicPublish(exchangeName, routingKey, mandatory, properties, “msg body”.getBytes());
使用这种方式,消息即使过期,也不一定会被马上丢弃,因为消息是否过期是在即将投递到消费者之前判定的,如果当前队列有严重的消息积压情况,则已过期的消息也许还能存活较长时间。
另外,还需要注意的一点是,如果不设置TTL,表示消息永远不会过期,如果将TTL设置为0,则表示除非此时可以直接投递该消息到消费者,否则该消息将会被丢弃。
RabbitMQ到底怎么实现延时队列
- 步骤一:创建一个正常的队列,指定消息过期时间,并且指定消息过期后需要投递的死信交换器和死信交换队列。
- 步骤二:创建死信队列和死信交换器
RabbitMQ实现延时队列实例
package com.example.demo;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
/**
* @author echo
* @date 2021-01-14 14:35
*/
public class TopicDealProductTest {
/**
* 延时队列交换机
*/
private static final String DIRECT_EXCHANGE_DELAY = “dir_exchange_delay”;
/**
* 死信队列交换机
*/
private static final String DIRECT_EXCHANGE_DEAD = “dir_exchange_dead”;
/**
* 延时队列
*/
private static final String DIRECT_QUEUE_DELAY = “dir.queue.delay”;
/**
* 死信队列
*/
private static final String DIRECT_QUEUE_DEAD = “dir.queue.dead”;
/**
* 延时队列ROUTING_KEY
*/
private static final String DIRECT_DELAY_ROUTING_KEY = “delay.queue.routingKey”;
/**
* 延时队列ROUTING_KEY
*/
private static final String DIRECT_DEAD_ROUTING_KEY = “dead.queue.routingKey”;
private static final String IP_ADDRESS = “192.168.230.131”;
private static final int PORT = 5672;
public static void main(String[] args) throws IOException, TimeoutException, InterruptedException {
Connection connection = createConnection();
// 创建一个频道
Channel channel = connection.createChannel();
sendMsg(channel);
Thread.sleep(10000);
closeConnection(connection, channel);
}
private static void sendMsg(Channel channel) throws IOException {
// 创建延时队列和延时交换器
channel.exchangeDeclare(DIRECT_EXCHANGE_DELAY, BuiltinExchangeType.DIRECT);
Map<String, Object> map = new HashMap<>(16);
// 在延时交换器上指定死信交换器
map.put(“x-dead-letter-exchange”, DIRECT_EXCHANGE_DEAD);
// 在延时交换器上指定死信队列的routing-key
map.put(“x-dead-letter-routing-key”, DIRECT_DEAD_ROUTING_KEY);
// 设定延时队列的延长时长 10s
map.put(“x-message-ttl”, 10000);
// 创建延时队列
channel.queueDeclare(DIRECT_QUEUE_DELAY, true, false, false, map);
// 在延时交换器上绑定延时队列
channel.queueBind(DIRECT_QUEUE_DELAY, DIRECT_EXCHANGE_DELAY, DIRECT_DELAY_ROUTING_KEY);
// 创建死信队列和死信交换器
channel.exchangeDeclare(DIRECT_EXCHANGE_DEAD, BuiltinExchangeType.TOPIC, true, false, null);
// 创建死信队列
channel.queueDeclare(DIRECT_QUEUE_DEAD, true, false, false, null);
// 在死信交换器上绑定死信队列
channel.queueBind(DIRECT_QUEUE_DEAD, DIRECT_EXCHANGE_DEAD, DIRECT_DEAD_ROUTING_KEY);
channel.basicPublish(DIRECT_EXCHANGE_DELAY, DIRECT_DELAY_ROUTING_KEY, null, “hello world”.getBytes());
}
private static void closeConnection(Connection connection, Channel channel) throws IOException, TimeoutException {
// 关闭资源
channel.close();
connection.close();
}
private static Connection createConnection() throws IOException, TimeoutException {
// 创建连接工厂
ConnectionFactory factory = new ConnectionFactory();
// 设置RabbitMQ的链接参数
factory.setHost(IP_ADDRESS);
factory.setPort(PORT);
factory.setUsername(“echo”);
factory.setPassword(“123456”);
// 和RabbitMQ建立一个链接
return factory.newConnection();
}
}
到这里,其实我们不难发现,我们无非是利用了TTL这个特性,让消息在过期的时候丢弃到指定队列,死信队列其实也是一个普通队列。
执行之后,我们来看看结果,在Exchange里面,我们创建了两个交换器和两个队列,但是两个队列和交换器还是有区别的,我们来看图片
我们可以看到两个队列的Features标志是不一样的
- TTL: 消息在队列中的过期时间
- DLX: 该队列绑定了死信交换器
- DLK: 该队列绑定的死信队列的ROUTING_KEY
在我们执行完成只有,我们可以看到,消息先被投递到了delay,该队列里面的消息,到达过期时间之后就被投递到了dead队列中去了。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
需要这份系统化的资料的朋友,可以添加V获取:vip1024b (备注Go)
[外链图片转存中…(img-cb5ViGV8-1713357641504)]
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!