这是我参与[第五届青训营]伴学笔记创作活动的第 12 天
问题提出:四个场景,如何解决?
- 系统崩溃
- 服务处理能力有限
- 链路耗时长尾
- 日志如何处理
解决方案:解耦、削峰、异步、日志处理
消息队列
消息队列(MQ),指保存消息的一个容器,本质是个队列,但这个队列呢,需要支持高吞吐,高并发,并且高可用
发展历程
业界消息队列对比
- Kafka:分布式的、分区的、多副本的日志提交服务,在
高吞吐场景下发挥较为出色 - RocketMQ:低延迟、强一致、高性能、高可靠、万亿级容量和灵活的可扩展性,在一些
实时场景中运用较广 - Pulsar:是下一代云原生分布式消息流平台,集消息、存储、轻量化函数式计算为一体.采用存算分离的架构设计
- BMQ:和Pulsar架构类似,存算分离,初期定位是承接高吞吐的离线业务场景,逐步替换掉对应的Kafka集群
Kafka
使用场景
- 日志信息
- Metrics数据,程序运行中对程序状态的采集
- 用户行为( 搜索、点赞、评论、收藏 )
如何使用
创建集群 -> 新增Topic -> 编写生产者逻辑 -> 编写消费者逻辑
基本概念
- Topic : 逻辑队列,不同Topic可以建立不同的Topic
- Cluster : 物理集群,每个集群中可以建立多个不同的Topic
- Producer : 生产者,负责将业务消息发送到Topic中
- Consumer : 消费者,负责消费Topic中的消息
- ConsumerGroup : 消费者组,不同组Consumer消费进度互不干涉
基本概念-Offset
Offset : 消息在partition内的相对位置信息,可以理解为唯一ID,在partition内部严格递增
一个Topic有多个分区Partition
基本概念-Replica
每个分片有多个 Replica,Leader Replica将会从 ISR中选出
partition里有多个副本,副本包含不同角色,分布在集群当中不同的机器上,以达到容灾的效果
Leader进行对外的写入和读取,消费
Follwer不断从Leader拉取数据,争取保持一致,如果与Leader的差距过大会被踢出ISR
数据复制
Broker:节点,所有节点组成集群
Controller:对集群中的所有副本以及节点进行分配
Kafka架构
ZooKeeper:与controller配合
Producer
Batch处理:批量发送可以减少IO次数,从而加强发送能力,提高吞吐量
数据压缩:(网络带宽不足)通过压缩,减少消息大小,目前支持Snappy、Gzip、LZ4、ZSTD压缩算法
Broker数据的存储
Broker-消息文件结构
Broker-磁盘结构
移动磁头找到对应磁道,磁盘转动,找到对应扇区,最后写入。寻道成本比较高,因此顺序写可以减少寻道所带来的时间成本
Broker-顺序写
采用顺序写的方式进行写入,以提高写入效率,末尾追加
Broker-如何找到消息
Consumer通过发送FetchRequest 请求消息数据, Broker会将指定Ofiset处的消息,按照时间窗口和消息大小窗口 发送给Consumer
寻找数据这个细节是如何做到的呢?
- 偏移量索引文件:二分找到小于目标 offset 的最大索引位置
- 时间戳索引文件:二分找到小于目标时间戳最大的索引位置,再通过寻找 offset的方式找到最终数据
Broker一零拷贝
Consumer一消息的接收端
Consumer-Low Level
通过手动进行分配,哪一个 Consumer消费哪一个 Partition完全由业务来决定
缺点:当一个consumer挂掉,对应的partition流就失效了(不能自动容灾);新增consumer时,需要停机重新分配
优点:快
Consumer-High Level
每个 Cunsumer group使用一个Coordinator自动分配(Rebalance)
Kafka存在的问题
- 运维成本高
- 对于负载不均衡的场景,解决方案复杂
- 没有自己的缓存,完全依赖 Page Cache
- Controller和Coordinator和Broker 在同一进程中,大量IO会造成其性能下降
BMQ
兼容Kafka协议,存算分离,云原生消息队列
HDFS写文件流程
随机选择一定数量的DataNode进行写入
Broker-Partition状态机
保证对于任意分片在同一时刻只能在一个 Broker上存活
BMQ-高级特性
泳道消息
BOE: Bytedance Offline Environment,是一套完全独立的线下机房环境
PPE: Product Preview Environment,即产品预览环境
解决主干泳道流量隔离问题以及泳道资源重复创建问题
下游的消费者只会消费其所在泳道的生产者的信息
Databus
直接使用原生SDK会有什么问题?
- 客户端配置较为复杂
- 不支持动态配置,更改配置需要停掉服务
- 对于latency 不是很敏感的业务, batch效果不佳
- 简化消息队列客户端复杂度
- 解耦业务与Topic
- 缓解集群压力,提高吞吐
Mirror
使用 Mirror通过最终一致的方式,解决跨 Region读写问题
Index
如果希望通过写入的Logld、Userld或者其他的业务字段进行消息的查询 应该怎么做?
- 直接在 BMQ中将数据结构化,配置索引 DDL,异步构建索引后, 通过Index Query服务读出数据
Parquet
Apache Parquet是Hadoop生态圈中一种新型列式存储格式,它可以兼容Hadoop生态圈中大多数计算框架(Hadoop、Spark等),被多种查询引擎支持(Hive、Impala、Drill等)
直接在BMQ中将数据结构化,通过Parquet Engine,可以使用不同的方式构建Parquet格式文件
RocketMQ
使用场景
例如,针对电商业务线,其业务涉及广泛,如注册、订单、库存、物流等;同时,也会涉及许多业务峰值时刻,如秒杀活动、周年庆、定期特惠等
基本概念
高级特性
事务场景、延时发送、消费重试和死信队列