目录
[1 kafka总体体系结构](#1 kafka总体体系结构)
[2 疑问解答](#2 疑问解答)
[2.1 高吞吐低延迟](#2.1 高吞吐低延迟)
[2.2 实现分布式存储和数据读取](#2.2 实现分布式存储和数据读取)
[2.3 如何保证数据不丢失](#2.3 如何保证数据不丢失)
背景
最近在和产品过项目审批的时候,深刻感受到业务方对系统的时时响应提出了更高的要求。目前手上大部分的业务都是基础定时任务去实现的,如果要实现更快速的响应,最佳的方式无非是采用消息中间件,在课余的时间也重温了下消息中间件kafka的架构知识点,本文主要总结kafka的数据存储相关方的知识:
1 kafka总体体系结构
-
架构图
-
名称解释
|----------------|-----------------------------------------------------------------------------------------------------|
| 名称 | 含义 |
| Broker | 消息中间件处理节点,一个Kafka节点就是一个broker,一个或者多个Broker可以组成一个Kafka集群,通俗说就是 每台机器上都运行一个Kafka的进程 |
| Topic | 代表了逻辑上的一个数据集 |
| Partition | 物理上的概念,一个topic可以分为多个partition ,说白就是数据 |
| Controller | kafka集群的总控组件,负责管理整个kafka集群范围内的各种东西 |
| Consumer | 消费者,从Broker拉去消息 |
| Consumer group | 每个Consumer属于一个特定的Consumer Group,一条满息可以发送到多个不同的Consumer Group但是一个Consumer Group中只能有一个Consumer能够满费该消息 |
| Producer | 生产者,向Broker推送消息 |看完整体架构后,不妨带上几个问题思考下
-
kafka的是如何实现高吞吐低延迟呢?
-
如何实现分布式存储和存储的数据是如何保证高性能读取呢?
-
如何保证数据不丢失?
2 疑问解答
2.1高吞吐低延迟
吞吐量概念:单位时间内可以处理多少条数据,就叫做吞吐量。
提升了吞吐量,但是计算的延时就增加
kafka的高吞吐低延迟的原因主要体现在下面几个方面
- 写数据:使用页缓存+磁盘顺序写
rabbitmq相比:rabbitmq这种消息中间件,他会先把数据写入内存里,然后到了一定时候再把数据一次 性从内存写入磁盘里
- 写数据:使用零拷贝技术
零拷贝:零拷贝是指在将数据从Kafka的日志文件传输到网络的过程中,避免了在Java堆内存(JVM)和操作系统之间拷贝数据。这样做可以减少CPU的使用,提高数据传输的效率
1 从page cache读,读不到才从磁盘IO读
2 会将数据放在os层的一个page cache里
3 接着会发生上下文切换到系统那边,把os的读缓存数据拷贝到应用缓存里
4 接着再次发生上下文二切换到os层,把应用缓存的数据拷贝到os的socket缓存中
5 最后数据再发送到网卡上
2.2实现分布式存储和数据读取
每个partition可以放在一台机器上,通过这个方式就可以实现数据的分布式存储了,落盘后的数据,其实就是个文件,类似日志。
- 分布式存储实现:其实很简单,就是将每个partition可以放在一台机器上,通过这个方式就可以实现数据的分布式存储了。
- 高性能的日志存储
- 每个分区对应的目录:
比如说有个topic叫做"order-topic" 3台机器上分别会有3个目录
"order-topic-0","order-topic-1","order-topic-2"
|-----|---------------|------------------------------------------------------------------------------------|-------------------------------------------------|
| 机器 | partition目录结构 | 下级文件格式 | 解释 |
| 机器1 | order-topic-0 | 00000000000009936472.index 00000000000009936472.log 00000000000009936472.timeindex | 每个分区里面就是很多的log segment file, 也就是日志段文件【有自己的索引文件】 |
| 机器2 | order-topic-1 | 00000000000019936472.index 00000000000019936472.log 00000000000019936472.timeindex | 每个分区里面就是很多的log segment file, 也就是日志段文件【有自己的索引文件】 |
| 机器3 | order-topic-2 | 00000000000029936472.index 00000000000029936472.log 00000000000029936472.timeindex | 每个分区里面就是很多的log segment file, 也就是日志段文件【有自己的索引文件】 |
-
- 基于二分查找快速定位数据
- 写入日志文件的时候,同时会写索引文件,就是.index和.timeindex【位移索引,时间戳索引】
- 定位流程:索引文件里的数据是按照位移和时间戳升序排序的,用二分查找,时间复杂度是O(logN),找到索引,就可以在.log文件里定位到数据
- 查找数据例子
- 基于二分查找快速定位数据
|--------------|----------------------------------------------------------------------------------------|----------------------------------------------------------------|-----------------------------------------------------|
| 需求 | 查找流程 | 例子 | 查找offset = 58892 |
| 根据offset查找 | 1 先在这个文件里二分查找找到offset, 2 在.index里根据offset二分查找找对应的.log文件里的位置, 3 最后就去.log文件里查找对应的数据 | 假设存在文件: 44576 物理文件(.log位置)57976 物理文件(.log位置) 64352 物文件(.log位置) | 因58892> 57976& 58892<64352 因此数据在 57976 .log文件的位置 |
| 查找某段时间范围内的时间 | 1 先在对应的索引文件里二分查找找到offset 2 然后再去.index里根据offset二分查找找对应的.log文件里的位置, 3 最后就去.log文件里查找对应的数据 | 略略 | 略略 |
2.3如何保证数据不丢失
- 多副本冗余的机制
对数据做多副本冗余,也就是每个parttion都有副本【follower partition】
- ISR【in-sync replica】 同步副本集
ISR 其实可以理解理解为与leader保持同步的所有副本的集合。主要是动态维护了一个和leader副本保持同步副本集合,ISR中的副本全部都和leader的数据保持同步。可以做到故障转移,保障服务的可用性。
架构图如下:
总之,保证写入kafka的数据不丢失,首先需要保证ISR中至少有一个follower。其次就是在一条数据写入了leader partition之后,要求必须复制给ISR中所有的follower partition。
关于ISR机制的原理,下期在详讲
作者:老喵