消息队列的七种经典应用场景

在笔者心中,消息队列缓存分库分表是高并发解决方案三剑客。

在职业生涯中,笔者曾经使用过 ActiveMQ 、RabbitMQ 、Kafka 、RocketMQ 这些知名的消息队列 。

这篇文章,笔者结合自己的真实经历,和大家分享消息队列的七种经典应用场景。

1 异步&解耦

笔者曾经负责某电商公司的用户服务,该服务提供用户注册,查询,修改等基础功能。用户注册成功之后,需要给用户发送短信。

图中,新增用户发送短信都揉在用户中心服务里,这种方式缺点非常明显:

  1. 短信渠道不够稳定,发送短信会达到 5 秒左右,这样用户注册接口耗时很大,影响前端用户体验;

  2. 短信渠道接口发生变化,用户中心代码就必须修改了。但用户中心是核心系统。每次上线都必要谨小慎微。这种感觉很别扭,非核心功能影响到核心系统了。

为了解决这个问题,笔者采用了消息队列进行了重构。

  • 异步

    用户中心服务保存用户信息成功后,发送一条消息到消息队列 ,立即将结果返回给前端,这样能避免总耗时比较长,从而影响用户的体验的问题。

  • 解耦

    任务服务收到消息调用短信服务发送短信,将核心服务与非核心功能剥离,显著的降低了系统间的耦合度。

2 消峰

高并发场景下,面对突然出现的请求峰值,非常容易导致系统变得不稳定,比如大量请求访问数据库,会对数据库造成极大的压力,或者系统的资源 CPU 、IO 出现瓶颈。

笔者曾服务于神州专车订单团队,在订单的载客生命周期里,订单的修改操作先修改订单缓存,然后发送消息到 MetaQ ,订单落盘服务消费消息,并判断订单信息是否正常(比如有无乱序),若订单数据无误,则存储到数据库中。

当面对请求峰值时,由于消费者的并发度在一个阈值范围内,同时消费速度相对均匀,因此不会对数据库造成太大的影响,同时真正面对前端的订单系统生产者也会变得更稳定。

3 消息总线

所谓总线,就是像主板里的数据总线一样, 具有数据的传递和交互能力,各方不直接通信,使用总线作为标准通信接口

笔者曾经服务于某彩票公司订单团队,在彩票订单的生命周期里,经过创建,拆分子订单,出票,算奖等诸多环节。每一个环节都需要不同的服务处理,每个系统都有自己独立的表,业务功能也相对独立。假如每个应用都去修改订单主表的信息,那就会相当混乱了。

因此,公司的架构师设计了调度中心的服务,调度中心维护订单的信息,但它不与子服务通讯,而是通过消息队列和出票网关,算奖服务等系统传递和交换信息。

消息总线这种架构设计,可以让系统更加解耦,同时也可以让每个系统各司其职。

4 延时任务

用户在美团 APP 下单,假如没有立即支付,进入订单详情会显示倒计时,如果超过支付时间,订单就会被自动取消。

非常优雅的方式是:使用消息队列的延时消息

订单服务生成订单后,发送一条延时消息到消息队列。消息队列在消息到达支付过期时间时,将消息投递给消费者,消费者收到消息之后,判断订单状态是否为已支付,假如未支付,则执行取消订单的逻辑。

RocketMQ 4.X 生产者发送延迟消息代码如下:

Message msg = new Message();
msg.setTopic("TopicA");
msg.setTags("Tag");
msg.setBody("this is a delay message".getBytes());
//设置延迟level为5,对应延迟1分钟
msg.setDelayTimeLevel(5);
producer.send(msg);

RocketMQ 4.X 版本默认支持 18 个 level 的延迟消息, 通过 broker 端的 messageDelayLevel 配置项确定的。

RocketMQ 5.X 版本支持任意时刻延迟消息,客户端在构造消息时提供了 3 个 API 来指定延迟时间或定时时间。

5 广播消费

广播消费:当使用广播消费模式时,每条消息推送给集群内所有的消费者,保证消息至少被每个消费者消费一次。

广播消费主要用于两种场景:消息推送缓存同步

01 消息推送

下图是专车的司机端推送机制,用户下单之后,订单系统生成专车订单,派单系统会根据相关算法将订单派给某司机,司机端就会收到派单推送消息。

推送服务是一个 TCP 服务(自定义协议),同时也是一个消费者服务,消息模式是广播消费。

司机打开司机端 APP 后,APP 会通过负载均衡和推送服务创建长连接,推送服务会保存 TCP 连接引用 (比如司机编号和 TCP channel 的引用)。

派单服务是生产者,将派单数据发送到 MetaQ , 每个推送服务都会消费到该消息,推送服务判断本地内存中是否存在该司机的 TCP channel , 若存在,则通过 TCP 连接将数据推送给司机端。

02 缓存同步

高并发场景下,很多应用使用本地缓存,提升系统性能 。

本地缓存可以是 HashMap 、ConcurrentHashMap ,也可以是缓存框架 Guava Cache 或者 Caffeine cache 。

如上图,应用A启动后,作为一个 RocketMQ 消费者,消息模式设置为广播消费。为了提升接口性能,每个应用节点都会将字典表加载到本地缓存里。

当字典表数据变更时,可以通过业务系统发送一条消息到 RocketMQ ,每个应用节点都会消费消息,刷新本地缓存。

6 分布式事务

以电商交易场景为例,用户支付订单这一核心操作的同时会涉及到下游物流发货、积分变更、购物车状态清空等多个子系统的变更。

1、传统XA事务方案:性能不足

为了保证上述四个分支的执行结果一致性,典型方案是基于 XA 协议的分布式事务系统来实现。将四个调用分支封装成包含四个独立事务分支的大事务。基于 XA 分布式事务的方案可以满足业务处理结果的正确性,但最大的缺点是多分支环境下资源锁定范围大,并发度低,随着下游分支的增加,系统性能会越来越差。

2、基于普通消息方案:一致性保障困难

该方案中消息下游分支和订单系统变更的主分支很容易出现不一致的现象,例如:

  • 消息发送成功,订单没有执行成功,需要回滚整个事务。

  • 订单执行成功,消息没有发送成功,需要额外补偿才能发现不一致。

  • 消息发送超时未知,此时无法判断需要回滚订单还是提交订单变更。

3、基于 RocketMQ 分布式事务消息:支持最终一致性

上述普通消息方案中,普通消息和订单事务无法保证一致的原因,本质上是由于普通消息无法像单机数据库事务一样,具备提交、回滚和统一协调的能力。

而基于 RocketMQ 实现的分布式事务消息功能,在普通消息基础上,支持二阶段的提交能力。将二阶段提交和本地事务绑定,实现全局提交结果的一致性。

RocketMQ 事务消息是支持在分布式场景下保障消息生产和本地事务的最终一致性。交互流程如下图所示:

1、生产者将消息发送至 Broker 。

2、Broker 将消息持久化成功之后,向生产者返回 Ack 确认消息已经发送成功,此时消息被标记为"暂不能投递",这种状态下的消息即为半事务消息

3、生产者开始执行本地事务逻辑

4、生产者根据本地事务执行结果向服务端提交二次确认结果( Commit 或是 Rollback ),Broker 收到确认结果后处理逻辑如下:

  • 二次确认结果为 Commit :Broker 将半事务消息标记为可投递,并投递给消费者。

  • 二次确认结果为 Rollback :Broker 将回滚事务,不会将半事务消息投递给消费者。

5、在断网或者是生产者应用重启的特殊情况下,若 Broker 未收到发送者提交的二次确认结果,或 Broker 收到的二次确认结果为 Unknown 未知状态,经过固定时间后,服务端将对消息生产者即生产者集群中任一生产者实例发起消息回查

  • 生产者收到消息回查后,需要检查对应消息的本地事务执行的最终结果。

  • 生产者根据检查到的本地事务的最终状态再次提交二次确认,服务端仍按照步骤4对半事务消息进行处理。

7 数据中转枢纽

近10多年来,诸如 KV 存储(HBase)、搜索(ElasticSearch)、流式处理(Storm、Spark、Samza)、时序数据库(OpenTSDB)等专用系统应运而生。这些系统是为单一的目标而产生的,因其简单性使得在商业硬件上构建分布式系统变得更加容易且性价比更高。

通常,同一份数据集需要被注入到多个专用系统内。

例如,当应用日志用于离线日志分析时,搜索单个日志记录同样不可或缺,而构建各自独立的工作流来采集每种类型的数据再导入到各自的专用系统显然不切实际,利用消息队列 Kafka 作为数据中转枢纽,同份数据可以被导入到不同专用系统中。

日志同步主要有三个关键部分:日志采集客户端,Kafka 消息队列以及后端的日志处理应用。

  1. 日志采集客户端,负责用户各类应用服务的日志数据采集,以消息方式将日志“批量”“异步”发送Kafka客户端。

    Kafka客户端批量提交和压缩消息,对应用服务的性能影响非常小。

  2. Kafka 将日志存储在消息文件中,提供持久化。

  3. 日志处理应用,如 Logstash,订阅并消费Kafka中的日志消息,最终供文件搜索服务检索日志,或者由 Kafka 将消息传递给 Hadoop 等其他大数据应用系统化存储与分析。

文章转载自:勇哥编程游记

原文链接:https://www.cnblogs.com/makemylife/p/18101509

体验地址:引迈 - JNPF快速开发平台_低代码开发平台_零代码开发平台_流程设计器_表单引擎_工作流引擎_软件架构

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/292154.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

搜索与图论——染色法判定二分图

一个图是二分图当且仅当这个图中不含奇数环 由于图中没有奇数环&#xff0c;所以染色过程中一定没有矛盾 所以一个二分图一定可以成功被二染色&#xff0c;反之在二染色的过程中出现矛盾的图中一定有奇数环&#xff0c;也就一定不是二分图 #include<iostream> #includ…

http和https的工作原理是什么?

HTTP&#xff08;HyperText Transfer Protocol&#xff09;和HTTPS&#xff08;HyperText Transfer Protocol Secure&#xff09;是两种用于在互联网上传输数据的主要协议&#xff0c;它们均用于在客户端&#xff08;通常是Web浏览器&#xff09;与服务器之间交换信息。尽管它们…

NSSCTF Round#20 Basic 真亦假,假亦真 CSDN_To_PDF V1.2 出题笔记 (附wp+源码)

真亦假&#xff0c;假亦真 简介&#xff1a;java伪造php一句话马。实则信息泄露一扫就出&#xff0c;flag在/flag里面。 题目描述&#xff1a;开开心心签个到吧&#xff0c;祝各位师傅们好运~ 静态flag&#xff1a;NSS{Checkin_h4v3_4_g00D_tINNe!} /路由显示 <?php e…

Radash一款JavaScript最新的实用工具库,Lodash的平替!

文章目录 Lodash 的痛点进入正题--Radash特点 举例几个常用的api 一说lodash应该大部分前端同学都知道吧&#xff0c;陪伴我们好多年的JavaScript工具库&#xff0c;但是自从 ES6 出现后就慢慢退出前端人的视线&#xff0c;能ES6写的代码绝对不会用Lodash&#xff0c;也不是完全…

住宅IP是什么?与机房IP有哪些区别?

随着互联网的普及和发展&#xff0c;不同类型的IP地址在网络世界中扮演着重要角色。在网络架构中&#xff0c;机房IP和住宅IP是两种常见的IP类型&#xff0c;它们各有优劣&#xff0c;适用于不同的场景和需求。本文将对机房IP和住宅IP进行技术对比&#xff0c;并给出选择合适IP…

vue项目使用eletron将打包成桌面应用(.exe)

vue项目使用eletron将打包成桌面应用(.exe) 1.前期准备 两个项目&#xff1a; 1、自己用vue cli创建的项目 2、第二个是去gitee将案例clone下来 案例地址 https://gitee.com/qingplus/electron-quick-start.git 2、测试案例是否可以正常运行 # 进入项目 cd electron-quick-…

kubernetes负载均衡资源-Ingress

一、Ingress概念 1.1 Ingress概念 使用NodePort类型的Service可以将集群内部服务暴露给集群外部客广端,但使用这种类型Service存在如下几个问题。 1、一个端口只能一个服务使用,所有通过NodePort暴露的端口都需要提前规划;2、如果通过NodePort暴露端口过多,后期维护成本太…

IPv6-重定向,PMTU,GRE隧道

IPv6-重定向&#xff0c;PMTU&#xff08;路径最大传输单元&#xff09;&#xff0c;GRE隧道&#xff08;Generic Routing Encapsulation&#xff0c;通用路由封装协议&#xff09; 重定向过程 触发重定向的条件&#xff1a; 1、报文的入接口&#xff0c;等于自身路由之后的…

ubuntu2204配置zabbix6.4高可用

zabbix6.4-HA 配置keepalived配置haproxy数据库高可用配置zabbix-server配置proxy配置客户端agent 本实验VMware搭建zabbix6.4高可用集群&#xff0c;搭配haproxykeepalived。 master&#xff0c;node节点搭建haproxykeepalibed主备并配置vip地址 三台控制节点搭建数据库高可用…

Pytorch 下载失败原因

错误信息&#xff1a; ERROR: Could not find a version that satisfies the requirement torch (from versions: none) ERROR: No matching distribution found for torch 解决方案&#xff1a; 在官网看到&#xff0c;它需要python3.8-3.11的环境。过高和过低的版本都不…

微信小程序备案流程详细操作指南

自2023年9月1日起&#xff0c;所有新上架的微信小程序均需事先完成备案手续&#xff0c;方能成功上线。而对于已经上架的存量小程序&#xff0c;也需要在2024年3月31日前完成备案工作。若在规定时间内未完成备案&#xff0c;平台将依据备案相关规定&#xff0c;自2024年4月1日起…

金三银四面试题(八):JVM常见面试题(2)

今天我们继续探讨常见的JVM面试题。这些问题不比之前的问题庞大&#xff0c;多用于面试中​JVM部分的热身运动&#xff0c;开胃菜&#xff0c;但是大家已经要认真准备。 JRE、JDK、JVM 及JIT 之间有什么不同&#xff1f; JRE 代表Java 运行时&#xff08;Java run-time&#…

ESP8266 控制 LED 亮灭

一、引脚对应 二、按键控制 LED 亮灭 2.1样例1 #include <ESP8266WiFi.h>const int ledPin D2; // LED 连接到 D2 引脚 const int keyPin D4; // 按键连接到 D4 引脚volatile bool flag false; // 记录 LED 状态的标志// 外部中断处理函数 ICACHE_RAM_ATTR void han…

(原型与原型链)前端八股文修炼Day5

一 原型链的理解 原型链定义&#xff1a; 原型链是 JavaScript 中实现对象继承的关键机制之一&#xff0c;它是一种对象之间的关系&#xff0c;通过这种关系&#xff0c;一个对象可以继承另一个对象的属性和方法。 原型链的组成&#xff1a; 每个对象都有一个指向另一个对象的…

C# 微软官方学习文档

链接&#xff1a;https://learn.microsoft.com/zh-cn/dotnet/csharp/ 在C#的学习过程中&#xff0c;我们可以参考微软官方的学习文档。它是一个免费的学习平台&#xff0c;提供了丰富的C#学习路径和教程&#xff08;如下图&#xff09;&#xff0c;对我们入门到高级应用开发都…

汇总:五个开源的Three.js项目

Three.js 是一个基于 WebGL 的 JavaScript 库&#xff0c;它提供了一套易于使用的 API 用来在浏览器中创建和显示 3D 图形。通过抽象和简化 WebGL 的复杂性&#xff0c;Three.js 使开发者无需深入了解 WebGL 的详细技术就能够轻松构建和渲染3D场景、模型、动画、粒子系统等。 T…

【自动装箱以及包装类的缓存】⭐️通过具体案例看下每种包装类的不同结果

目录 前言 一、自动装箱与拆箱&#xff08;以 Integer 包装类为例&#xff09; 二、再来看看几个示例 ​编辑三、Double ,Float 类型亦是如此吗&#xff1f; 前言 小伙伴们大家好&#xff0c;日常使用业务层方面的代码居多&#xff0c;但也不可忘了基本的一些代码格式以及原…

npm淘宝镜像源更新

目录 前情提要&#xff1a; 背景&#xff1a; 镜像源更新&#xff1a; 清楚缓存&#xff1a; 直接切换镜像源&#xff1a; 注&#xff1a;npm 补充&#xff1a; 错误解释&#xff1a; 解决方法&#xff1a; 前情提要&#xff1a; 2024 /1 /22 &#xff0c;registry.npm…

理解游戏服务器架构-逻辑底层架构

目录 前言 什么是逻辑底层架构 逻辑底层架构的职责 1&#xff09;Thread-线程 线程管理 线程通讯 线程安全锁机制 2&#xff09;Network-网络 网络模型 网络消息协议 断线重连 网络安全 防范重复消息 防范篡改消息内容 防范篡改内存数据 网络承载 3&#xff0…

HarmonyOS 应用开发之FA模型启动Stage模型UIAbility

本文介绍FA模型的三种应用组件如何启动Stage模型的UIAbility组件。 PageAbility启动UIAbility 在PageAbility中启动UIAbility和在PageAbility中启动PageAbility的方式完全相同。 import featureAbility from ohos.ability.featureAbility; import { BusinessError } from oh…