工作中这样用MQ,很香!

向量数据库大模型数据库

大家好,我是苏三,又跟大家见面了。

前言

消息队列(MQ)是分布式系统中不可或缺的技术之一。

对很多小伙伴来说,刚接触MQ时,可能觉得它只是个“传话工具”,但用着用着,你会发现它简直是系统的“润滑剂”。

无论是解耦、削峰,还是异步任务处理,都离不开MQ的身影。

下面我结合实际场景,从简单到复杂,逐一拆解MQ的10种经典使用方式,希望对你会有所帮助。picture.image

  1. 异步处理:让系统轻松一点

场景

小伙伴们是不是经常遇到这样的情况:用户提交一个操作,比如下单,然后要发送短信通知。

如果直接在主流程里调用短信接口,一旦短信服务响应慢,就会拖累整个操作。

用户等得不耐烦,心态直接崩了。

解决方案

用MQ,把非关键流程抽出来异步处理。下单时,直接把“发短信”这件事丢给MQ,订单服务就能立刻响应用户,而短信的事情让MQ和消费者去搞定。

示例代码


        
          
// 订单服务:生产者  
Order order = createOrder(); // 订单生成逻辑  
rabbitTemplate.convertAndSend("order\_exchange", "order\_key", order);  
System.out.println("订单已生成,发短信任务交给MQ");  
  
// 短信服务:消费者  
@RabbitListener(queues = "sms\_queue")  
public void sendSms(Order order) {  
    System.out.println("发送短信,订单ID:" + order.getId());  
    // 调用短信服务接口  
}  

      

深度解析

这种方式的好处是:主流程解耦,不受慢服务的拖累 。订单服务只管自己的事,短信服务挂了也没关系,MQ会把消息暂存,等短信服务恢复后继续处理。

  1. 流量削峰:稳住系统别崩

场景

每年的“双十一”电商大促,用户秒杀商品时一窝蜂冲进来。

突然涌入的高并发请求,不仅会压垮应用服务,还会直接让数据库“趴窝”。

解决方案

秒杀请求先写入MQ,后端服务以稳定的速度从MQ中消费消息,处理订单。

这样既能避免系统被瞬时流量压垮,还能提升处理的平稳性。

示例代码


        
          
// 用户提交秒杀请求:生产者  
rabbitTemplate.convertAndSend("seckill\_exchange", "seckill\_key", userRequest);  
System.out.println("用户秒杀请求已进入队列");  
  
// 秒杀服务:消费者  
@RabbitListener(queues = "seckill\_queue")  
public void processSeckill(UserRequest request) {  
    System.out.println("处理秒杀请求,用户ID:" + request.getUserId());  
    // 执行秒杀逻辑  
}  

      

深度解析

MQ在这里相当于一个缓冲池,把瞬时流量均匀分布到一段时间内处理。系统稳定性提升,用户体验更好

  1. 服务解耦:减少相互牵制

场景

比如一个订单系统需要通知库存系统扣减库存,还要通知支付系统完成扣款。

如果直接用同步接口调用,服务间的依赖性很强,一个服务挂了,整个链条都会被拖垮。

解决方案

订单服务只负责把消息丢到MQ里,库存服务和支付服务各自从MQ中消费消息。

这样订单服务不需要直接依赖它们。

示例代码


        
          
// 订单服务:生产者  
rabbitTemplate.convertAndSend("order\_exchange", "order\_key", order);  
System.out.println("订单生成消息已发送");  
  
// 库存服务:消费者  
@RabbitListener(queues = "stock\_queue")  
public void updateStock(Order order) {  
    System.out.println("扣减库存,订单ID:" + order.getId());  
}  
  
// 支付服务:消费者  
@RabbitListener(queues = "payment\_queue")  
public void processPayment(Order order) {  
    System.out.println("处理支付,订单ID:" + order.getId());  
}  

      

深度解析

通过MQ,各个服务之间可以实现松耦合。

即使库存服务挂了,也不会影响订单生成的流程,大幅提升系统的容错能力

  1. 分布式事务:保证数据一致性

场景

订单服务需要同时生成订单和扣减库存,这涉及两个不同的数据库操作。

如果一个成功一个失败,就会导致数据不一致。

解决方案

通过MQ实现分布式事务。

订单服务生成订单后,将扣减库存的任务交给MQ,最终实现数据的一致性。

示例代码


        
          
// 订单服务:生产者  
rabbitTemplate.convertAndSend("order\_exchange", "order\_key", order);  
System.out.println("订单创建消息已发送");  
  
// 库存服务:消费者  
@RabbitListener(queues = "stock\_queue")  
public void updateStock(Order order) {  
    System.out.println("更新库存,订单ID:" + order.getId());  
    // 执行扣减库存逻辑  
}  

      

深度解析

通过“最终一致性”解决了分布式事务的难题,虽然短时间内可能有数据不一致,但最终状态一定是正确的。

  1. 广播通知:一条消息,通知多个服务

场景

比如商品价格调整,库存、搜索、推荐服务都需要同步更新。

如果每个服务都要单独通知,工作量会很大。

解决方案

MQ的广播模式(Fanout)可以让多个消费者订阅同一条消息,实现消息的“一发多收”。

示例代码


        
          
// 生产者:广播消息  
rabbitTemplate.convertAndSend("price\_update\_exchange", "", priceUpdate);  
System.out.println("商品价格更新消息已广播");  
  
// 消费者1:库存服务  
@RabbitListener(queues = "stock\_queue")  
public void updateStockPrice(PriceUpdate priceUpdate) {  
    System.out.println("库存价格更新:" + priceUpdate.getProductId());  
}  
  
// 消费者2:搜索服务  
@RabbitListener(queues = "search\_queue")  
public void updateSearchPrice(PriceUpdate priceUpdate) {  
    System.out.println("搜索价格更新:" + priceUpdate.getProductId());  
}  

      

深度解析

这种模式让多个服务都能接收到同一条消息,扩展性非常强

  1. 日志收集:分布式日志集中化

场景

多个服务产生的日志需要统一存储和分析。

如果直接写数据库,可能导致性能瓶颈。

解决方案

各服务将日志写入MQ,日志分析系统从MQ中消费消息并统一处理。

示例代码


        
          
// 服务端:生产者  
rabbitTemplate.convertAndSend("log\_exchange", "log\_key", logEntry);  
System.out.println("日志已发送");  
  
// 日志分析服务:消费者  
@RabbitListener(queues = "log\_queue")  
public void processLog(LogEntry log) {  
    System.out.println("日志处理:" + log.getMessage());  
    // 存储或分析逻辑  
}  

      
  1. 延迟任务:定时触发操作

场景

用户下单后,如果30分钟内未支付,需要自动取消订单。

解决方案

使用MQ的延迟队列功能,设置消息延迟消费的时间。

示例代码


        
          
// 生产者:发送延迟消息  
rabbitTemplate.convertAndSend("delay\_exchange", "delay\_key", order, message -> {  
    message.getMessageProperties().setDelay(30 * 60 * 1000); // 延迟30分钟  
    return message;  
});  
System.out.println("订单取消任务已设置");  
  
// 消费者:处理延迟消息  
@RabbitListener(queues = "delay\_queue")  
public void cancelOrder(Order order) {  
    System.out.println("取消订单:" + order.getId());  
    // 取消订单逻辑  
}  

      
  1. 数据同步:跨系统保持数据一致

场景

在一个分布式系统中,多个服务依赖同一份数据源。

例如,电商平台的订单状态更新后,需要同步到缓存系统和推荐系统。

如果让每个服务直接从数据库拉取数据,会增加数据库压力,还可能出现延迟或不一致的问题。

解决方案

利用MQ进行数据同步。订单服务更新订单状态后,将更新信息发送到MQ,缓存服务和推荐服务从MQ中消费消息并同步数据。

示例代码

订单服务:生产者


        
          
// 更新订单状态后,将消息发送到MQ  
Order order = updateOrderStatus(orderId, "PAID"); // 更新订单状态为已支付  
rabbitTemplate.convertAndSend("order\_exchange", "order\_status\_key", order);  
System.out.println("订单状态更新消息已发送:" + order.getId());  

      

缓存服务:消费者


        
          
@RabbitListener(queues = "cache\_update\_queue")  
public void updateCache(Order order) {  
    System.out.println("更新缓存,订单ID:" + order.getId() + " 状态:" + order.getStatus());  
    // 更新缓存逻辑  
    cacheService.update(order.getId(), order.getStatus());  
}  

      

推荐服务:消费者


        
          
@RabbitListener(queues = "recommendation\_queue")  
public void updateRecommendation(Order order) {  
    System.out.println("更新推荐系统,订单ID:" + order.getId() + " 状态:" + order.getStatus());  
    // 更新推荐服务逻辑  
    recommendationService.updateOrderStatus(order);  
}  

      

深度解析

通过MQ实现数据同步的好处是:

  1. 减轻数据库压力 :避免多个服务同时查询数据库。

  2. 最终一致性 :即使某个服务处理延迟,MQ也能保障消息不丢失,最终所有服务的数据状态一致。

  3. 分布式任务调度


场景

有些任务需要定时执行,比如每天凌晨清理过期订单。

这些订单可能分布在多个服务中,如果每个服务独立运行定时任务,可能会出现重复处理或任务遗漏的问题。

解决方案

使用MQ统一分发调度任务,每个服务根据自身的业务需求,从MQ中消费任务并执行。

示例代码

任务调度服务:生产者


        
          
// 定时任务生成器  
@Scheduled(cron = "0 0 0 * * ?") // 每天凌晨触发  
public void generateTasks() {  
    List<Task> expiredTasks = taskService.getExpiredTasks();  
    for (Task task : expiredTasks) {  
        rabbitTemplate.convertAndSend("task\_exchange", "task\_routing\_key", task);  
        System.out.println("任务已发送:" + task.getId());  
    }  
}  

      

订单服务:消费者


        
          
@RabbitListener(queues = "order\_task\_queue")  
public void processOrderTask(Task task) {  
    System.out.println("处理订单任务:" + task.getId());  
    // 执行订单清理逻辑  
    orderService.cleanExpiredOrder(task);  
}  

      

库存服务:消费者


        
          
@RabbitListener(queues = "stock\_task\_queue")  
public void processStockTask(Task task) {  
    System.out.println("处理库存任务:" + task.getId());  
    // 执行库存释放逻辑  
    stockService.releaseStock(task);  
}  

      

深度解析

分布式任务调度可以解决:

  1. 重复执行 :每个服务只处理自己队列中的任务。

  2. 任务遗漏 :MQ确保任务可靠传递,防止任务丢失。

  3. 文件处理:异步执行大文件任务


场景

用户上传一个大文件后,需要对文件进行处理(如格式转换、压缩等)并存储。

如果同步执行这些任务,前端页面可能会一直加载,导致用户体验差。

解决方案

用户上传文件后,立即将任务写入MQ,后台异步处理文件,处理完成后通知用户或更新状态。

示例代码

上传服务:生产者


        
          
// 上传文件后,将任务写入MQ  
FileTask fileTask = new FileTask();  
fileTask.setFileId(fileId);  
fileTask.setOperation("COMPRESS");  
rabbitTemplate.convertAndSend("file\_task\_exchange", "file\_task\_key", fileTask);  
System.out.println("文件处理任务已发送,文件ID:" + fileId);  

      

文件处理服务:消费者


        
          
@RabbitListener(queues = "file\_task\_queue")  
public void processFileTask(FileTask fileTask) {  
    System.out.println("处理文件任务:" + fileTask.getFileId() + " 操作:" + fileTask.getOperation());  
    // 模拟文件处理逻辑  
    if ("COMPRESS".equals(fileTask.getOperation())) {  
        fileService.compressFile(fileTask.getFileId());  
    } else if ("CONVERT".equals(fileTask.getOperation())) {  
        fileService.convertFileFormat(fileTask.getFileId());  
    }  
    // 更新任务状态  
    taskService.updateTaskStatus(fileTask.getFileId(), "COMPLETED");  
}  

      

前端轮询或回调通知


        
          
// 前端轮询文件处理状态  
setInterval(() => {  
    fetch(`/file/status?fileId=${fileId}`)  
        .then(response => response.json())  
        .then(status => {  
            if (status === "COMPLETED") {  
                alert("文件处理完成!");  
            }  
        });  
}, 5000);  

      

深度解析

异步文件处理的优势:

  1. 提升用户体验 :主线程迅速返回,减少用户等待时间。
  2. 后台任务灵活扩展 :支持多种操作逻辑,适应复杂文件处理需求。

总结

消息队列不只是传递消息的工具,更是系统解耦、提升稳定性和扩展性的利器。

在这10种经典场景中,每一种都能解决特定的业务痛点。

希望这篇文章对你理解MQ的应用场景有帮助!

最后欢迎加入苏三的星球,你将获得:商城系统实战、秒杀系统实战、代码生成工具、系统设计、性能优化、技术选型、高频面试题、底层原理、Spring源码解读、工作经验分享、痛点问题等多个优质专栏。

还有1V1答疑、修改简历、职业规划、送书活动、技术交流。

目前星球已经更新了4500+篇优质内容,还在持续爆肝中.....

星球已经被官方推荐了3次,收到了小伙伴们的一致好评。戳我加入学习,已有1500+小伙伴加入学习。

此外,推荐一下我的技术专栏《程序员最常见的100个问题》,目前已经更新了80多篇干货文章,里面收录了很多踩坑经历,对你的职业生涯或许有些帮助,最近收到的好评挺多的。

这个专栏总结了我10年工作中,遇到过的100个非常有代表性的技术问题,非常有参考和学习价值。

Java、Spring、分布式、高并发、数据库、海量数据、线上问题什么都有。

每篇文章从发现问题、分析问题、解决问题和问题总结等多个维度,深入浅出,分享了很多技术细节,定位和排查问题思路,解决问题技巧,以及实际工作经验。

你能从中学到很多有用知识,帮你少走很多弯路。

扫描下方二维码即可订阅:

picture.image

最后说一句(求关注,别白嫖我)

如果这篇文章对您有所帮助,或者有所启发的话,帮忙扫描下发二维码关注一下,您的支持是我坚持写作最大的动力。

求一键三连:点赞、转发、在看。

关注公众号:【苏三说技术】,在公众号中回复:面试、代码神器、开发手册、时间管理有超赞的粉丝福利,另外回复:加群,可以跟很多BAT大厂的前辈交流和学习。

picture.image

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论