深入理解消息队列的协议层设计

news2024/12/17 10:56:43

先抛个问题:为什么同样是做消息队列,RabbitMQ选择了AMQP,Kafka要自己搞一套私有协议,Pulsar明明有现成的协议不用,非要自己设计一个,而RocketMQ更是在最新版本决定All in gRPC?这背后到底是什么考虑?

从场景说起
要理解这个问题,我们得先看看消息队列在分布式系统中是怎么用的。拿一个常见的电商系统来说,当用户下单的时候,订单服务要通知库存服务、支付服务、物流服务,这些服务可能分布在不同的机器上,甚至不同的数据中心。怎么保证这些消息又快又稳地传输?这就是消息队列要解决的核心问题。

但问题没这么简单。消息队列不是简单地把消息从A传到B就完事了。它还要处理各种复杂场景:消息要按顺序投递吗?要持久化保存吗?如果系统崩溃了消息会丢吗?生产者发送太快消费者处理不过来怎么办?

这些问题的答案直接影响了协议层的设计。就像我们设计API一样,协议层本质上就是定义了一套"接口规范",规定了各种场景下系统应该如何交互。

协议层的核心要素
说到协议层,很多人第一反应就是"这不就是定义个消息格式吗?"这个理解太简单了。一个完整的协议层设计要考虑三个核心问题:

  • 连接管理:这就像手机打电话,建立连接、保持心跳、检测断线、重连,这些都是协议层要处理的基础问题。

  • 消息传输:这个就比较复杂了,不光要定义消息格式,还要考虑消息边界怎么划分、优先级怎么处理、批量传输怎么做,等等。

  • 流量控制:这个更有意思了。比如生产者发送速度是100条/秒,但消费者只能处理50条/秒,这时候协议层就要有机制来处理这种速度不匹配的问题。

MQ场景下的特殊协议需求
在消息队列这个特定场景下,协议层还要额外处理一些问题:

消息路由:
在MQ系统中,消息往往需要从一个生产者投递给多个消费者,或者根据某些规则选择性地投递。协议需要支持灵活的路由模式,例如:

  • 点对点(Queue)模式
  • 发布订阅(Topic)模式
  • 基于内容的路由

持久化保证:
消息队列通常需要提供消息持久化的能力,确保系统崩溃后消息不会丢失。协议需要定义:

  • 消息持久化的标识方式
  • 持久化的确认机制
  • 恢复场景下的消息重传机制

事务支持:
在某些场景下,消息的发送和消费需要事务保证。协议需要提供:

  • 事务的开启和提交机制
  • 分布式事务的协调方式
  • 事务失败的回滚处理

几个主流MQ的协议选择
好,理解了这些背景,我们再来看看几个主流MQ的协议选择就更有意思了。

RabbitMQ的AMQP之路
RabbitMQ选择AMQP是非常有意思的。AMQP最早是金融机构主导设计的,他们的诉求是什么?一是可靠性要高(金融嘛,消息丢了就出大事了),二是要标准化(这样可以避免被具体某个厂商绑定)。

AMQP的设计特别有意思,它不光定义了通信协议,还定义了一整套消息模型。它引入了Exchange、Queue、Binding这些概念,让消息路由变得特别灵活。这就像设计一个餐厅,与其只关注食物怎么端到客人面前,不如把整个点餐、分发的流程都设计好。

AMQP协议的核心特点包括:

  • 模型层面的标准化:AMQP不仅标准化了通信协议,还定义了完整的消息模型。它引入了Exchange、Queue、Binding等概念,使得消息路由变得灵活而强大。比如,一条消息可以通过Exchange根据不同的规则被路由到多个Queue,支持多种消息分发模式。
  • 可靠性保证:AMQP提供了完整的消息确认机制。发送方可以等待服务器确认(publisher confirm),消费方可以在处理完成后再确认(consumer ack)。就像快递需要签收一样,这种机制确保了消息不会丢失。
  • 事务支持:AMQP原生支持事务,可以将多个消息发送操作打包成一个事务,要么全部成功,要么全部失败。这对于金融等需要严格事务保证的场景非常重要。

Kafka的极简主义
再看Kafka,走了完全不同的路子。它说我就要一个简单的、性能极致的协议。为此,Kafka直接基于TCP搞了个二进制协议,简单到什么程度?请求头就那么几个固定字段,连接复用、批量操作、Zero-Copy,能优化的都优化了。

这种设计很大程度上决定了Kafka的高性能。就像F1赛车,为了速度,把所有不必要的东西都去掉。当然代价是协议不够通用,但在Kafka的场景下,这是值得的权衡。

Kafka协议的特点:

  • 简单的请求-响应模型:每个请求都有固定的格式,包含请求头和请求体。请求头包含API键、API版本、相关ID等信息,结构简单清晰。这种设计使得协议处理的开销降到最低。
  • 批量处理机制:协议原生支持消息批量发送和批量获取,一次网络往返可以处理多条消息。这显著提高了网络利用率,就像货车运输比单独派送每个包裹更效率。
  • Zero-Copy优化:协议的设计考虑到了现代操作系统的特性,支持零拷贝传输,减少了数据在内核空间和用户空间之间的复制,显著提升了性能。

Pulsar的混合策略
再来看Pulsar,它的策略更有意思。核心消息传输用自己设计的Pulsar Protocol,但是对外又提供了多协议支持。这就像一个餐厅,后厨用标准化流程,但是点餐方式既支持电话又支持外卖平台。

Pulsar Protocol特别关注多租户场景,协议里直接内置了租户和命名空间的概念。这在云原生时代特别有价值。同时,它的协议还内置了完善的流控和背压机制,这些都是针对大规模分布式系统的痛点来设计的。

RocketMQ的云原生转型
最后说说RocketMQ。它在5.0版本做了个大动作 —— 引入gRPC作为通信协议。这个选择特别有意思,它反映了云原生时代的新趋势。

为什么选择gRPC?因为在云环境下,系统的可观测性、可维护性、易扩展性可能比极致的性能更重要。gRPC天然支持多语言、服务发现、负载均衡,还有完善的监控和跟踪能力,这些都是云原生环境的刚需。

RocketMQ的协议特点:

  • 自定义协议:早期版本使用类似Kafka的自定义二进制协议,追求极致性能。协议格式精简,只包含必要的字段。
  • 多协议支持:新版本引入gRPC支持,基于代理模式实现,同时保留了原有协议,实现了平滑过渡。这种演进策略既保证了性能,又提升了易用性。

Pulsar协议
Pulsar采用了自己设计的二进制协议(Pulsar Protocol),这是一个专门为消息系统设计的协议。值得注意的是,虽然Pulsar也支持其他协议(如Kafka协议、AMQP等),但其核心消息传输仍然使用Pulsar Protocol。 Pulsar Protocol在设计时特别考虑了多租户场景。协议内置了命名空间和租户的概念,支持复杂的消息路由和访问控制。同时,协议还包含了完善的流控和背压机制,能够优雅地处理生产者和消费者之间的速度不匹配问题。

序列化与反序列化
序列化和反序列化本质上是一个数据转换的过程。在分布式系统中,当数据需要在网络中传输或存储到磁盘时,我们需要将内存中的数据结构转换成可传输或存储的格式。 具体来说,序列化反序列化有三个主要作用:

  • 网络传输 当生产者发送消息到Broker,或者消费者从Broker获取消息时,数据都需要在网络上传输。而网络传输只能传输字节流,所以需要将对象转换为字节流(序列化),接收方再将字节流转回对象(反序列化)。
  • 持久化存储 消息队列需要将消息持久化到磁盘以保证可靠性。存储时需要将内存中的消息对象序列化成二进制格式,读取时再反序列化回对象。
  • 跨语言通信 在分布式系统中,生产者和消费者可能使用不同的编程语言。序列化和反序列化提供了一种语言无关的数据交换格式,使得不同语言的系统可以相互通信。

MQ的序列化机制
RabbitMQ的序列化机制:
RabbitMQ底层使用Erlang实现,它的序列化机制是基于AMQP协议的。具体来说:

1、消息序列化过程发生在AMQP协议层:

  • 首先消息被编码成AMQP格式
  • 然后通过Erlang的内部序列化机制(称为External Term Format, ETF)进行序列化
  • 最后转换成二进制流在网络上传输

2、AMQP协议定义了消息的格式:

Basic.Properties
|- content-type (消息类型)
|- content-encoding (编码方式)
|- headers (自定义属性)
|- delivery-mode (持久化标记)
|- priority (优先级)

Kafka的序列化机制:
Kafka实现了自己的序列化框架。它的特点是:

提供了可插拔的序列化器接口:

public interface Serializer<T> {
    void configure(Map<String, ?> configs, boolean isKey);
    byte[] serialize(String topic, T data);
    void close();
}

消息格式包含多个部分:

消息集合(MessageSet)
|- 消息长度(4字节)
|- 消息版本(1字节)
|- CRC32校验(4字节)
|- 消息属性
   |- Key长度
   |- Key内容
   |- Value长度
   |- Value内容

RocketMQ的序列化机制:
RocketMQ使用了自定义的序列化协议,称为RemotingCommand协议。它的结构如下:

消息格式:

RemotingCommand
|- 消息长度(4字节)
|- 序列化类型编号(1字节)
|- 消息头长度(4字节)
|- 消息头内容(JSON格式)
|- 消息体内容(二进制)

序列化实现:

public class RemotingCommand {
    private static SerializeType serializeTypeConfigInThisServer = SerializeType.JSON;
    
    public static RemotingCommand decode(final ByteBuffer byteBuffer) {
        int length = byteBuffer.getInt();
        int serialTypeCode = byteBuffer.get();
        SerializeType serializeType = SerializeType.valueOf(serialTypeCode);
        // 根据序列化类型进行解码
        switch (serializeType) {
            case JSON:
                return jsonDecode(byteBuffer);
            case ROCKETMQ:
                return rocketMqDecode(byteBuffer);
            default:
                break;
        }
        return null;
    }
}

基于gRPC的序列化: gRPC默认使用Protocol Buffers(protobuf)作为序列化协议。这是因为:

Protobuf具有优秀的特性:

  • 高效的二进制格式
  • 强类型的消息定义
  • 优秀的向前/向后兼容性
  • 跨语言支持

消息定义方式:

message Person {
    string name = 1;
    int32 age = 2;
    repeated string hobbies = 3;
}
service PersonService {
    rpc GetPerson (PersonRequest) returns (Person) {}
}

各种序列化机制的性能比较:
序列化大小:
Protobuf ≈ Avro < RocketMQ < Kafka < RabbitMQ(AMQP) < JSON
序列化速度:
Protobuf > RocketMQ > Kafka > Avro > RabbitMQ > JSON
开发便利性:
JSON > RabbitMQ > Kafka > RocketMQ > Protobuf > Avro

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

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

相关文章

IDEA搭建SpringBoot,MyBatis,Mysql工程项目

目录 一、前言 二、项目结构 三、初始化项目 四、SpringBoot项目集成Mybatis编写接口 五、代码仓库 一、前言 构建一个基于Spring Boot框架的现代化Web应用程序&#xff0c;以满足[公司/组织名称]对于[业务需求描述]的需求。通过利用Spring Boot简化企业级应用开发的优势&…

Redis应用—4.在库存里的应用

大纲 1.库存模块设计 2.库存缓存分片和渐进式同步方案 3.基于缓存分片的下单库存扣减方案 4.商品库存设置流程与异步落库的实现 6.库存入库时"缓存分片写入 渐进式写入 写入失败进行MQ补偿"的实现 7.库存扣减时"基于库存分片依次扣减 合并扣减 扣不了…

25. 深浅拷贝

一、什么是浅拷贝 只对对象的最顶层进行的拷贝称为 浅拷贝。我们可以用 copy 模块中的 copy() 方法实现浅拷贝。 import copya [11, 22, 33] b [44, 55, 66] c [a, b] d copy.copy(c)print(f"c: {c}") print(f"d: {d}") print(f"c d: {c d}&q…

【GCC】2015: draft-alvestrand-rmcat-congestion-03 机器翻译

腾讯云的一个分析,明显是看了这个论文和草案的 : 最新的是应该是这个 A Google Congestion Control Algorithm for Real-Time Communication draft-ietf-rmcat-gcc-02 下面的这个应该过期了: draft-alvestrand-rmcat-congestion-03

学习笔记:Verilog VHDL硬件描述语言简介及在线仿真Verilog环境

RTL Verilog VHDL HLS等概念 RTL Register Transfer Level&#xff0c;寄存器传输级。它是数字电路设计中的一种抽象层次&#xff0c;描述了电路中寄存器之间的数据传输和逻辑操作。RTL代码通常用Verilog或VHDL语言编写&#xff0c;是后续综合、仿真等工作的基础。 VHDL全名Ve…

druid图形化监控 + MyBatis优化器使用

文章目录 1.集成druid图形化监控1.配置application.yml2.测试访问 http://localhost:项目端口/druid 2.MyBatis优化器(显示完整sql)1.目录2.SqlBeautyInterceptor.java&#xff1a;sql拦截器3.MybatisConfiguration.java&#xff1a;将sql拦截器注入容器4.测试5.MyBatis优化器动…

1216作业

思维导图 作业 使用无名信号量实现输出春夏秋冬 #include <myhead.h> sem_t sem1,sem2,sem3,sem4; void *fun1() {while(1){sem_wait(&sem1);sleep(1);printf("春\n");sem_post(&sem2);} }void *fun2() {while(1){sem_wait(&sem2);sleep(1);prin…

学习maven(maven 项目模块化,继承,聚合)

前言 本篇博客的核心&#xff1a;理解maven 项目模块化&#xff0c;继承&#xff0c;聚合 的含义 maven 项目模块化 含义 maven项目模块化&#xff1a;使用maven 构建项目&#xff0c;管理项目的方式&#xff0c;我们可以将maven项目根据内在的关系拆分成很多个小项目【模块】…

【Linux】自定义项目-进度条

更多精彩内容..... &#x1f389;❤️播主の主页✨&#x1f618; Stark、-CSDN博客 准备工作&#xff1a;"\r"与"\n"字符 ①&#xff1a;基本含义 在C语言和Linux环境中&#xff0c;\r是回车符&#xff0c;\n是换行符&#xff0c;用于控制文本格式和输出…

OpenLinkSaas 2025年1月开发计划

先来看看OpenLinkSaas的大目标 在OpenLinkSaas的产品目标中&#xff0c;让开发人员更加方便的使用云资源是目标之一。通过各大云厂商的API&#xff0c;来可视化云上基础设施的数据是远远不够的。我们准备在2025年1月份增加方便管理和运营研发场景下服务器的能力。 这部分的功能…

电工电子技术实验:电压比较器及其应用电路

实验目的 1&#xff0e;了解电压比较器与运算放大器的性能区别&#xff1b; 2&#xff0e;掌握电压比较器的结构及特点&#xff1b; 3&#xff0e;掌握电压比较器电压传输特性的测试方法&#xff1b; 4&#xff0e;学习比较器在电路设计中的应用 实验原理 电压比较器是一…

代理 IP 行业现状与未来趋势分析

随着互联网的飞速发展&#xff0c;代理 IP 行业在近年来逐渐兴起并成为网络技术领域中一个备受关注的细分行业。它在数据采集、网络营销、隐私保护等多个方面发挥着重要作用&#xff0c;其行业现状与未来发展趋势值得深入探讨。 目前&#xff0c;代理 IP 行业呈现出以下几个显著…

旅游系统旅游小程序PHP+Uniapp

旅游门票预订系统&#xff0c;支持景点门票、导游产品便捷预订、美食打卡、景点分享、旅游笔记分享等综合系统 更新日志 V1.3.0 1、修复富文本标签 2、新增景点入驻【高级版本】3、新增门票核销【高级版】4、新增门票端口【高级版】

【日常笔记】Spring boot:编写 Content type = ‘text/plain‘ 接口

一、项目场景&#xff1a; 接口&#xff1a;Context-Type&#xff1a;text/plain 方式&#xff1a;POST 项目场景&#xff1a;硬件回调接口 二、实战 PostMapping(value "/xx/xxx", consumes "text/plain" ) 2.1、接口 /*** return String* time 202…

STM32F407+LAN8720A +LWIP +FreeRTOS UDP通讯

STM32F407+LAN8720A +LWIP +FreeRTOS ping通 上一篇实现了LWIP ping 通 本篇实现UDP通讯 实现如下功能: 串口1空闲中断+DMA接收,收到数据用UDP发送UDP接收,收到数据用串口1发送STM32CUBEIDE配置和代码 1. 配置UARAT1的空闲中断+DMA接收 UART1接收到数据,释放信号量,在任…

KeyFormer:使用注意力分数压缩KV缓存

Keyformer: KV Cache Reduction through Key Tokens Selection for Efficient Generative Inference 202403&#xff0c;发表在Mlsys Introduction 优化KV cache的策略&#xff0c;主要是集中在系统级别的优化上&#xff0c;比如FlashAttention、PagedAttention&#xff0c;它…

3.9 网际控制报文协议ICMP

欢迎大家订阅【计算机网络】学习专栏&#xff0c;开启你的计算机网络学习之旅&#xff01; 文章目录 前言1 ICMP报文的封装2 ICMP差错报告报文的类型3 不应发送ICMP差错报告报文的情况4 常用的ICMP询问报文类型5 ICMP的应用 前言 网际控制报文协议&#xff08;ICMP&#xff09…

东北大学《2024年839自动控制原理真题》 (完整版)

本文内容&#xff0c;全部选自自动化考研联盟的&#xff1a;《东北大学839自控考研资料》的真题篇。后续会持续更新更多学校&#xff0c;更多年份的真题&#xff0c;记得关注哦~ 目录 2024年真题 Part1&#xff1a;2024年完整版真题 2024年真题

百度智能云千帆AppBuilder升级,百度AI搜索组件上线,RAG支持无限容量向量存储!

百度智能云千帆 AppBuilder 发版升级&#xff01; 进一步降低开发门槛&#xff0c;落地大模型到应用的最后一公里。在千帆 AppBuilder 最新升级的 V1.1版本中&#xff0c;企业级 RAG 和 Agent 能力再度提升&#xff0c;同时组件生态与应用集成分发更加优化。 • 企业级 RAG&am…

就业相关(硕士)

一、嵌入式 1.机器人行业 1.1 大致情况 要做机器人行业&#xff0c;主要技术栈是运动控制、深度学习、强化学习、具身智能等&#xff0c;主要求职方向有运动控制算法工程师和机器人算法工程师等等。大致薪资在30w到50w不等&#xff0c;主要看方向&#xff08;双211&#xff…