- 工程实践 - 《QPS百万级的有状态服务实践》03 - 消息队列

news2024/12/25 9:16:31

         本文属于专栏《构建工业级QPS百万级服务》


        继续上篇《QPS百万级的有状态服务实践》02 - 冷启动和热更新。我们的架构如图1。上一章在热更新部分,我们引入了消息队列。本章我们介绍下各个消息队列的优缺点,并选择其中一个说下核心概念和原理。

图1

        目前市面上的消息中间件优缺点和使用案例如下。

消息中间件优点缺点著名使用案例
Apache Kafka高吞吐量、可扩展性好、持久化、故障容错配置复杂、消息重复(至多一次或至少一次的交付保证)、较高的学习曲线LinkedIn, Netflix, Uber, Twitter
RabbitMQ支持多种消息协议、轻量级、易于部署、管理界面友好性能受限于单节点、集群配置和网络分区敏感Reddit, Instagram, Robinhood
Apache Pulsar扩展性强、持久化、原生支持多租户相对较新的系统、社区和生态相对较小Yahoo, Tencent
Apache ActiveMQ成熟稳定、支持多种语言客户端、易于理解和部署在极高吞吐量场景下性能可能受限、内存占用较高Canadian Tire, E*TRADE
Redis Pub/Sub低延迟、简单易用、支持多种数据结构用于消息不持久化(Pub/Sub模式下)、无消费者确认机制导致不可靠消息传输Twitch, GitHub, Stack Overflow
Amazon SQS完全托管、高可靠性、无需服务器维护、集成AWS服务有消息大小限制(256KB)、可能存在延迟问题、费用可能随使用量显著增加Airbnb, Samsung, BMW
Google Pub/Sub完全托管、无服务器、全球分布式、与Google Cloud服务集成与Google Cloud平台耦合、价格可能较高Spotify, Wix, Coca-Cola
Microsoft Azure Service Bus完全托管、与Azure生态系统集成良好、支持多种通信模式如队列、主题和事件网格与Azure平台耦合、可能存在一定的延迟、成本随使用量增长BMW, GEICO, Fujifilm
NATS轻量级、高性能、简单高效的API、支持多种消息模式不支持持久化(NATS Streaming Server除外)、功能简单可能不适合复杂场景Baidu, Siemens, HTC
ZeroMQ高性能、无中心节点、可以用作库集成到应用中、灵活的拓扑结构不是传统意义上的消息队列服务、需要自行处理消息持久化、没有管理界面AppNexus, BitTorrent, Wargaming.net
Apache RocketMQMQ高性能、高吞吐量、支持分布式事务、多种消息模式、丰富的客户端语言支持部署配置相对复杂、社区相比Kafka较小、学习曲线相对陡峭阿里巴巴, DiDi, OPPO

        正如我之前的文章《选择项目工具的方法论》所说,在业务深入,对关键节点,是需要自己制作最时候自己的业务。毕竟工具只有最适合,没有最好。虽然每个中间件都有自己的特点,但是核心原理也有很多共通点,我们以开源RocketMQ为例,介绍一下中间件的核心思想。

        中间件架构如图2。Producer集群对应我们的架构就是数据生产服务集群,Consumer集群就是计算节假日数量的服务容器集群,这两个都是业务方自己维护的集群。而RocketMQ的核心功能有客户端和服务端两个部分。客户端部分,一方面集成在Producer集群,业务代码使用RocketMQ提供的三方库函数进行数据发送,另一方面继承在Consumer集群,业务代码使用RocketMQ提供的三方库函数进行数据接受。

图2

        RocketMQ客户端逻发送辑,先通过Name Server获取Broker地址,然后向对应地址发送消息。这里有一些性能优化点值得注意。第一,数据发送是I/O密集型,占用CPU有限,为了提高发送速度,配置多线程发送是很有必要的,最佳线程数量,需要业务测试。第二,对没有顺序性要求的数据,使用异步发送。第三,在单个消息体很小,在可接受延迟范围内,在Producer逻辑中对数据聚合之后再发送,以减少网络调用次数。最后,还有一些数据发送/拉取失败的重试次数、每次数据下拉等众多细节参数,建议在业务遇到相关问题时再看。

        RocketMQ客户端接受逻辑,是先通过Name Server获取Broker地址,然后向Broker轮询,主动Pull数据。这里Pull的方式,牺牲了少量的延迟,减少了RocketMQ服务端,也就是Broker集群的复杂度。性能方面,主要是调整Pull的线程数。另外在Pull时有两个模式可以选择。

  • 集群消费:一条消息被其中一个机器消费
  • 广播消费:一条消息被每个机器都消费一次

        消息队列,核心数据流水线是“发+存+收”,Producer负责发,Consumer负责收,那数据在RocketMQ服务端是如何存的呢。 简单的说,如图3,数据生产者把消息发送给Broker,Broker把数据存在Commit Log中,并根据标签,在每个Consume Queue中添加索引。图中有几个概念需要了解:

  • topic:消息发布和订阅的类别或者标签,它用来区分不同的消息流。在生产者发送消息时,必须指定一个topic,这个topic描述了消息的类别或者用途。消费者则订阅它感兴趣的topic来接收消息。在RocketMQ中,一个topic可以有多个producer(生产者)发送消息,也可以有多个consumer(消费者)订阅消息
  • Queue ID:在RocketMQ中,每个Topic都可以细分成若干个队列,称为Message Queue(消息队列)。Queue ID是消息队列的唯一标识符。在一个broker里,一个Topic可以有多个Queue ID,这是为了实现消息负载均衡和并行处理。Queue ID可以帮助在分布式环境中水平扩展消息处理能力。每个消息队列都有自己的Commit Log和Consume Queue,并且保证队列内的消息是有序的
  • message:消息是在生产者和消费者之间传递的数据包。每个消息都有一个具体的内容体(Payload)和一组属性(例如,消息键、标签、延迟级别等)。在RocketMQ中,消息被附加到指定的topic,然后可被发送到对应topic下的一个或多个消息队列。消费者从订阅的消息队列中拉取并处理消息。消息在提交到broker时会追加到Commit Log中,并且通过Consume Queue来索引,以便快速检索和消费
  • Message Tag HashCode:tag 是与消息(Message)关联的一个可选字段,它为消息提供了额外的维度来进行分类和过滤。tag 可以看作是对同一个 topic 下消息的进一步细分。你可以将 tag 理解为对消息主题(topic)的子分类,它使得消费者(Consumer)能够更精细地选择感兴趣的消息进行消费。tag一个重要的作用是在服务端过滤消费者不想要的数据。比如Topic为动物园的动物们,消息内容为每个动物的编号,那tag是每个动物的类型,如鱼类、鸟类。作为管理鱼类的系统,在消费时就可以告诉Broker,只想消费鱼类的数据,这样数据就在服务端过滤了,而不是客户端       

图3

        除了以上介绍的核心功能,RocketMQ还有一些重置消费Offset位点、消息优先级队列、消息重复、消息顺序等细节功能或问题,但不是本系列的重点,对大部分业务,理解上面的内容已经足够。

        截止目前为止,我们的架构通过消息队列,增加了数据更新的推送机制。但是不同机器收到消息的时间是有差别的,那机器更新数据版本的时间就有差别,比如一个机器已经是版本B了,另一个机器还是版本A,那一个请求方的短时间大量请求结果,可能在两个版本反复横跳,用户体验会很不好。那如何解决数据一致性问题,架构还需要做怎样的升级。我会在后续的文章中说下我的经验。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Go语言】Go语言的数据类型

GO 语言的数据类型 Go 语言内置对以下这些基本数据类型的支持: 布尔类型:bool 整型:int8、byte、int16、int、uint、uintptr 等 浮点类型:float32、float64 复数类型:complex64、complex128 字符串:st…

嵌入式学习 Day21

一. 文件IO: 1. lseek off_t lseek(int fd, off_t offset, int whence); 功能: 重新设定文件描述符的偏移量 参数: fd:文件描述符 offset:偏移量 whence: SEEK_SET 文件开头 …

基于STM32F407的coreJSON使用教程

目录 概述 工程建立 代码集成 函数介绍 使用示例 概述 coreJSON是FreeRTOS中的一个组件库,支持key查找的解析器,他只是一个解析器,不能生成json数据。同时严格执行 ECMA-404 JSON 标准。该库用 C 语言编写,设计符合 ISO C90…

杨氏矩阵和杨辉三角

杨氏矩阵 有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。 要求:时间复杂度小于O(N); 分析 若要满足要求时间复杂度小于O(N),就不能每一行一个个…

机器学习基础(一)理解机器学习的本质

导读:在本文中,将深入探索机器学习的根本原理,包括基本概念、分类及如何通过构建预测模型来应用这些理论。 目录 机器学习 机器学习概念 相关概念 机器学习根本:模型 数据的语言:特征与标签 训练与测试&#xf…

elementui 中 el-date-picker 控制选择当前年之前或者之后的年份

文章目录 需求分析 需求 对 el-date-picker控件做出判断控制 分析 给 el-date-picker 组件添加 picker-options 属性&#xff0c;并绑定对应数据 pickerOptions html <el-form-item label"雨量年份&#xff1a;" prop"date"><el-date-picker …

正整数A+B(PTA团体天题练习题)细节题刨析

哎呀&#xff0c;又是看似简单的AB模型&#xff0c;这题确实也是AB&#xff0c;不过这个题让我debug1个多小时才找出来问题所在&#xff0c;服了&#xff0c;真是所谓细节决定成败&#xff0c;这题也挺值得记录下来的&#xff0c;话不多嗦&#xff0c;看题 题的目标很简单&…

[ansible] playbook运用

一、复习playbook剧本 --- - name: first play for install nginx #设置play的名称gather_facts: false #设置不收集facts信息hosts: webservers:dbservers #指定执行此play的远程主机组remote_user: root #指定执行此play的用…

css3的var()函数

css3的var()函数 变量要以两个连字符--(横杆)(减号)为开头 变量可以在:root{}中定义, :root可以在css中创建全局样式变量。通过 :root本身写的样式&#xff0c;相当于 html&#xff0c;但优先级比后者高。 在CSS3中&#xff0c;var()函数是一个用于插入CSS自定义属性&#xff…

如何创建WordPress付款表单(简单方法)

您是否正在寻找一种简单的方法来创建付款功能WordPress表单&#xff1f; 小企业主通常需要创建一种简单的方法来在其网站上接受付款&#xff0c;而无需设置复杂的购物车。简单的付款表格使您可以轻松接受自定义付款金额、设置定期付款并收集自定义详细信息。 在本文中&#x…

QT编写工具基本流程(自用)

以后有人让你写工具的时候&#xff0c;可以方便用这个模版及时提高工作效率&#xff0c;可以争取早点下班。包含库目录&#xff0c;头文件目录&#xff0c;输出目录以及翻译和部署&#xff0c;基本上都全了&#xff0c;也可以做收藏用用。 文章目录 1、创建项目Dialog Widget都…

Vue | (三)使用Vue脚手架(上) | 尚硅谷Vue2.0+Vue3.0全套教程

文章目录 &#x1f4da;初始化脚手架&#x1f407;创建初体验&#x1f407;分析脚手架结构&#x1f407;关于render&#x1f407;查看默认配置 &#x1f4da;ref与props&#x1f407;ref属性&#x1f407;props配置项 &#x1f4da;混入&#x1f4da;插件&#x1f4da;scoped样…

element-plus日期选择器2次封装

预期效果 官网默认样式&#xff1a; 修改后的样式&#xff1a; 代码实现 DatePicker.vue <template><div class"date-picker-container"><el-date-picker v-model"date" change"handleChange" type"date" value-for…

TypeScript中的Omit、Pick、Partial、Required类型

首先有这么个人员接口 interface IInfo {name: string; // 姓名age: number; // 年龄height: string; // 身高phone: string; // 联系电话email: string; // 邮箱 } 1. Omit Omit类型可以从一个对象类型中 忽略某些属性 假设我们使用IInfo接口&#xff0c;但是不想要其中p…

OpenAI文生视频物理世界模型——Sora降世,AI视频领域降维打击令五大行业一夜变天!

年初六&#xff0c;OpenAI发布了“文生视频”的工具&#xff0c;Sora。AI技术变革又一次震撼了整个世界。或许你又开始担心&#xff0c;AI发展那么快&#xff0c;将会取代自己。但请记住&#xff0c;危机时代也是变革时代&#xff0c;变革就是机会。开工第一天&#xff0c;相信…

搜狗的workflow的简单使用

workflow是一个网络库&#xff0c;是一个基于C在在线服务引擎 GitHub官网 运行hello world 1,创建一个server&#xff0c;构造函数入参传入一个入参是task的lamda函数&#xff0c;函数的内容会拿到response&#xff0c;并且可以在response中写body 2、server启动&#xff0c;…

Vue中$root的使用方法

查看本专栏目录 关于作者 还是大剑师兰特&#xff1a;曾是美国某知名大学计算机专业研究生&#xff0c;现为航空航海领域高级前端工程师&#xff1b;CSDN知名博主&#xff0c;GIS领域优质创作者&#xff0c;深耕openlayers、leaflet、mapbox、cesium&#xff0c;canvas&#x…

XR行业首家|李未可科技通过深度合成服务算法备案

2月18日&#xff0c;国家网信办发布第四批深度合成服务算法备案。 根据《互联网信息服务深度合成管理规定》第十九条规定&#xff0c;具有舆论属性或者社会动员能力的深度合成服务提供者&#xff0c;应当按照《互联网信息服务算法推荐管理规定》履行备案和变更、注销备案手续。…

探索海洋世界,基于YOLOv5全系列【n/s/m/l/x】参数模型开发构建海洋场景下海洋生物检测识别分析系统

前面的博文中&#xff0c;开发实践过海底相关生物检测识别的项目&#xff0c;对于海洋场景下的海洋生物检测则很少有所涉及&#xff0c;这里本文的主要目的就是想要开发构建基于YOLOv5的海洋场景下的海洋生物检测识别系统。 前文相关的开发实践如下&#xff0c;感兴趣的话可以…

【DDD】学习笔记-应用服务

Eric Evans 为运用领域驱动设计的系统架构划定了层次&#xff0c;在领域层和展现层之间引入了应用层&#xff08;Application Layer&#xff09;&#xff1a;“应用层要尽量简单&#xff0c;不包含业务规则或者知识&#xff0c;而只为下一层&#xff08;指领域层&#xff09;中…