这是我参与「第五届青训营 」伴学笔记创作活动的第14天
讲师: 黄庭坚
思考时间
案例一: 系统崩溃
搜索直播间
搜索行为记录 ->↓
点击商品 记录存储
点击行为记录 ->↑
如果此时记录存储程序所在的机房被删库跑路了, 上面这个流程会发生什么问题?
解决方案: 解耦
搜索商品
搜索行为记录 ->↓
点击商品 消息队列->存储服务
点击行为记录 ->↑
案例二: 服务能力有限
面对庞大的请求量, 处理订单的服务一脸茫然, 它的命运该何去何从?
解决方案: 削峰
发起订单
消息队列
处理订单(每次只获取10个请求进行处理)
案例三: 链路耗时长尾
发起订单(5ms)->库存记录-1(100ms)->订单记录+1(100ms)->通知商家(30s)->下单成功
对于这个流程应该怎样优化来挽回这个暴躁的用户?
解决方案: 异步
发起订单(5ms)
消息队列(50ms)->下单成功
↓ ↓ ↓
↓ ↓ 订单记录+1(100ms)
↓ 库存记录-1(10ms)
通知商家(30s)
案例四: 日志存储
日志如何处理
解决方案:
Log->消息队列->LogStash->ES->Kibana
什么是消息队列?
消息队列(MQ), 指保存消息的一个容器, 本质是个队列. 但这个队列, 需求支持高吞吐, 高并发, 并且高可用
生成 -> [Message Message Message] -> 消费
01 消息队列发展历程
TIB: 诞生于1985年, 服务于金融机构和新闻机构
IBM MQ/WebSphere: 诞生于1993年, 商业消息队列平台市场主要玩家
MSMQ: 微软发布于1997年
JMS: 诞生于2001年, 本质上是一套Java API
AMQP/RabbitMQ: 规范发布于2004年, 同年RabbitMQ面市
Kafka: 2010年由Linked开源
RocketMQ: 2011年阿里中间件团队自研
Pulsar: 2012年诞生于Yahoo内部
01 业界消息队列对比
Kafka: 分布式的, 分区的, 多副本的日志提交服务, 在高吞吐场景下发挥较为出色
RocketMQ: 低延迟, 强一致, 高性能, 高可靠, 万亿级容量和灵活的可扩展性, 在一些实时场景中运用较广
Pulsar: 是下一代云原生分布式消息流平台, 集消息, 存储, 轻量化函数式计算为一体, 采用存算分离的架构设计
BMQ: 和Pulsar架构类似, 存算分离, 初期定位是承接高吞吐的离线业务场景, 逐步替换对于的Kafka集群
02 消息队列 - Kafka
2.1 使用场景
搜索服务 直播服务 订单服务 支付服务
↓
日志信息 Metrics数据 用户行为
2.2 如何使用Kafka
创建集群
新增Topic
编写生产者逻辑
编写消费者逻辑
2.3 基本概念
Topic: 逻辑队列, 不同的业务可以建立不同的Topic
Partition: Topic的分区, 不同分区可以并发处理, 以此提高吞吐能力
Cluster: 物理集群, 每个集群中可以建立多个不同的Topic
Producer: 生产者, 负责将业务消息发送到Topic中
Consumer: 消费者, 负责消息Topic中的消息
ConsumerGroup: 消费者组, 不同组Consumer消费进度互不干涉
Offset: 消息在Partition内的相对位置消息, 可以理解为唯一ID, 在Partition内部严格递增
Replica: 每个分片有多个Replica, Leader Replica将会在ISR中选出 ISR: In-Sync Replicas(Replica-Leader以及与Leader相差不大的Replica-Follower们)
2.4 数据复制
Broker代表Kafka中的节点, Broker中会选出Controller
Broker主要功能是持久化Producer发送的消息, 以及将消息队列中的消息从发送端传输到消费端(Consumer)
Controller管理集群中所有分区和副本的状态并执行相应的管理操作
2.5 Kafka架构
见PPT图
2.6 一条消息的自述
Producer -> Broker -> Consumer
为什么Kafka可以这么高的吞吐?
2.7 Producer
批量发送
批量发送可以减少IO次数, 从而加强发送能力
如果消息量很大, 网络带宽不够用, 如何解决?
数据压缩
通过压缩, 减小消息大小, 目前支持Snappy, Gzip, LZ4, ZSTD压缩算法
2.8 Broker
消息文件结构
LogSegment
.log(日志文件)
.index(偏移量索引文件)
.timeindex(时间戳索引文件)
其他文件\
磁盘结构
磁盘: 移动磁头找到对应磁道, 磁盘转动, 找到对应扇区, 最后写入. 寻道成本比较高
⭐因此, 顺序写可以减少寻道所带来的时间成本
如何找到消息
Conumer通过发送FetchRequest请求消息数据, Broker会将指定Offset处的消息, 按照时间窗口和消息大小窗口发送给Consumer
寻找数据这个细节是如何做到的呢?
偏移量索引文件
二分查找小于目标offset的最大索引位置
时间戳索引文件
先二分查找小于目标时间戳最大的索引位置, 再通过offset的方式找到数据
零拷贝
2.9 Consumer
如何解决Partition在Consumer Group中的分配问题?
方法一: 手动分配
缺点:
不能自动容灾
扩容要启停
方法二: 自动分配
Rebalance
见PPT图
小结
Kafka如何提高吞吐或者稳定性的?
Producer: 批量发送, 数据压缩
Broker: 顺序写, 消息索引, 零拷贝
Consumer: Rebalance
2.11Kafka缺点
1 运维成本高
数据复制问题: 节点变动(重启, 替换, 扩容, 缩容)都会带来数据复制问题, 带来很大的时间, 人力成本
2 对于复杂不均衡的场景, 解决方案复杂
3 没有字节的缓存, 完全依赖Page Cache
4 Controller和Coordinator和Broker在同一进程中, 大量IO会造成性能下降
03 消息队列 - BMQ
兼容Kafka协议, 存算分离, 云原生消息队列
加了层Proxy
引入了HDFS分布式存储
运维操作由分钟级甚至天级, 优化为秒级
Partition状态机, 保证对于任意分片在同一时刻只能在一个Broker上存活
Parquet: Hadoop生态圈中一种新型列式存储格式
小结
1 BMQ的架构模型(解决Kafka存在的问题)
2 BMQ的读写流程(Failover机制, 写入状态机)
3 BMQ高级特性(泳道, Databus, Mirror, Index, Parquet)
04 消息队列 - RocketMQ
基本概念
名称 | Kafka | RocketMQ
逻辑队列 | Topic | Topic
消息体 | Message | Message
标签 | 无 | tag
分区 | Partition | ConsumerQueue
生产者 | Producer | Producer
生产者集群 | 无 | Producer Group
消费者 | Consumer | Consumer
消费者集群 | Consumer Group | Consumer Group
集群控制器 | Controller | Nameserver
小结
1 RocketMQ的基本概念(Queue, Tag)
2 RocketMQ的底层原理(架构模型, 存储模型)
3 RocketMQ的高级特性(事务消息, 重试和死信队列, 延迟队列)