消息队列(kafka 与 rocketMQ)

为什么要使用消息队列?

作用1: 削峰填谷(突发大请求量问题)

case1:

  • 聊天(比如 QQ ,微信): 在过年的前后的短时间内QPS差距非常大
  • 过年前(23:59:59): QPS 只有1万
  • 过年后(00:00:00): QPS 会超过 10 万;所有人都在疯狂的发送"新年快乐"这样的新年祝福
  • 这时服务器不可能承受瞬间超过平时 10 倍的压力

这时就可以使用消息队列:

  • 将消息存在消息队列中
  • 按照服务能够消费的速度进行消费
  • K8S的弹性伸缩,当压力太大时会自动拓展服务器,加快处理能力;当压力降低会收缩服务器降低成本(k8s 的弹性伸缩也需要时间,如果没有消息队列做削峰填谷,还没有拓展服务器服务就被打爆了)
  • 当压力变小后: 将拓展的服务器杀掉,节约成本

作用2: 解耦(单一原则)

case1:

  • 用户登录: 关联的功能非常多(token 颁发,消息推送,活动的推荐,计算在线时长等)
  • 如果全部做在登录的api 中:登录的代码可能超过几千行,开发困难,并且难以维护.

原则是一次只做一件事

  • 登录就只颁发 token
  • 将登录的消息存在消息队列中
  • 与登录相关的其他服务(消息推送,活动的推荐,计算在线时长等)订阅登录的消息,然后做进一步的操作

作用3: 异步(减少处理时间)

  • 用户登录: 关联的功能非常多(token 颁发,消息推送,活动的推荐,计算在线时长等)
  • 要自信的任务非常多,执行时间久(用户等待时间长)

使用消息队列进行异步处理

  • 完成关键业务(获取 token,消息放入消息队列)就可以返回
  • 服务器后台再逐渐执行其他业务(消息推送,活动的推荐,计算在线时长等),不需要等所有服务执行完成,减少用户等待时间.

如何选择消息队列(kafka&RocketMQ)

成本

按阿里云的计费标准

kafka: 标准版 60MB/s 读写; 500GB 磁盘: ¥1,189.75 /月

RocketMQ: (按每条消息 100 字节算)15000TPS 的61,710/月

两个吞吐量性能相似,价格相差 50 多倍

功能

  • kafka: 提供基本的消息队列的功能(生产与消费)
    具体可以查阅 kafka 官方文档或者 sdk 的 api

RocketMQ: 提供了更加丰富的功能

  1. 消息的种类: 提供普通消息;顺序消息,延时消息,事务消息 4 种
  2. 生产: 提供普通的 send 与 request 两种模式
  3. 消费: 提供了 push 与 pull 两种模式,同时提供消息过滤功能

具体可以查阅 RocketMQ 官方文档或者 sdk 的 api

性能

  • kafka



  • RocketMQ



根据测试结果来看

kafka : 发送 25MB/s; 接收400MB/s(最高情况)

RocketMQ: 发送:12MB/s;接收 20MB/s

总结:

  • kafka 可以达到 100w QPS
  • RocketMQ 大概是 20w QPS

选择

  • 首先考虑 kafka(普通消息传输:case IM): 成本低,性能好等诸多优势
  • 如果kafka无法满足使用的功能需求(比如需要事务,或者延时发布等功能: case: 支付/订单等功能):再考虑使用 RocketMQ.

rocketMQ是参考kafka进行实现的为什么rocketMQ与kafka性能差距很大呢?

kafka 的底层数据储存实现

  • kafka 的数据是进行分区储存的,每一个分区对应单独的文件夹(数据,索引都是单独的),这样在并发(多生产者与消费者)读写的情况下性能更好(特别是读)
  • 可以减少并发读写的冲突问题
  • 在读的情况下,可以更好的使用批量读取的方式获取数据,提升读取性能

rocketMQ 的底层数据储存实现

  • rocketMQ 的 index 的分开储存的,但是数据(message)是混合储存的,所有 topic 的所有分区的数据都是储存一起的.
  • 这样使得 rocketMQ 在并发的条件下读写性能略逊一筹
  • 并发写会有更多冲突
  • 在读取的时候,每次需要通过索引映射数据,更加麻烦,不利于批量读取

零拷贝实现的差异

原始的发送流程
  • 磁盘数据->内核空间->用户空间->socket 发送缓冲区->网卡

  • 数据经历了 4 次拷贝

kafka使用的sendfile模式
  • 磁盘数据->内核空间->网卡

  • 数据经历了 2 次拷贝

rocketMQ的mmap模式
  • 磁盘数据->内核空间->socket 发送缓冲区->网卡
  • 数据经历了 3 次拷贝
mmap与sendfile的差异
  • mmap:数据会先存在 socket 发送缓冲区中,再发送;方便做重试等功能

  • sendfile: 只关心发送了几个字节,不关心发送的内容

  • rocketMQ 需要做重试与二次消费,所以选择了 mmap 的模式

为什么rocketMQ不使用分区分开储存而要使用混合储存的方式?

我没有在文档与书籍中看到为什么 rocketMQ 要使用混合储存的方式,但是我在探究他们的不同的时候发现 kafka 存在分区数量庞大(10000+)会导致性能下降的问题.

  • 原因 1: zookeeper 维护了每一个分区的元数据,当分区非常大的时候 zookeeper 压力很大
  • 原因 2:操作系统持有文件句柄数量是有限的,文件数量太多会导致性能下降
rocketMQ针对大topic支持的调整
  • 调整中心节点: rocketMQ 使用的无状态的 nameserv 的模式,只储存他们的端口消息,不储存元数据,在大 topic 的情况下对中心节点的影响很小

  • 采用混合储存的方式减少文件的数量(文件数量减少 1/3)

参考

https://kafka.apache.org/documentation/#introduction

https://rocketmq.apache.org/zh/docs/featureBehavior/01normalmessage

https://blog.csdn.net/m0_71513446/article/details/143386962

https://rocketmq-learning.com/faq/ons-user-question-history16752/

https://www.bilibili.com/video/BV1Zy411e7qY/?spm_id_from=333.337.search-card.all.click&vd_source=45cb101876b00a49e608d7ab220c9736

相关推荐
郭涤生1 小时前
Chapter 10: Batch Processing_《Designing Data-Intensive Application》
笔记·分布式
郭涤生3 小时前
微服务系统记录
笔记·分布式·微服务·架构
马达加斯加D3 小时前
MessageQueue --- RabbitMQ可靠传输
分布式·rabbitmq·ruby
小哀25 小时前
RocketMQ 5.2.0 集群Dledger的扩展调研/实践
后端·rocketmq
西岭千秋雪_5 小时前
Sentinel核心源码分析(上)
spring boot·分布式·后端·spring cloud·微服务·sentinel
东阳马生架构10 小时前
zk基础—4.zk实现分布式功能二
分布式
ChinaRainbowSea10 小时前
8. RabbitMQ 消息队列 + 结合配合 Spring Boot 框架实现 “发布确认” 的功能
java·spring boot·分布式·后端·rabbitmq·java-rabbitmq
IT成长日记10 小时前
【Kafka基础】Kafka高可用集群:2.8以下版本超详细部署指南,运维必看!
分布式·zookeeper·kafka·集群部署
码界筑梦坊11 小时前
基于Spark的酒店数据分析系统
大数据·分布式·python·信息可视化·spark·毕业设计·个性化推荐