本文来说下 Kafka的存储选型

文章目录

  • 概述
  • Kafka的存储难点是什么
  • Kafka的存储选型分析
    • 存储领域的基础知识
    • Kafka 的存储选型考虑
  • Kafka 的存储设计
  • 本文小结

概述

谈到 Kafka 的存储设计,了解不多的同学,可能会有这样的疑惑:为什么 Kafka 会采用 Logging(日志文件)这种很原始的方式来存储消息,而没考虑用数据库或者 KV 来做存储?

而对 Kafka 有所了解的同学,应该能快速说出一些 知识点:比如 Append Only、Linear Scans、磁盘顺序写、页缓存、零拷贝、稀疏索引、二分查找等等。

此外,也希望大家在了解了 Kafka 的存储设计后,能对 Append Only Data Structures 这一经典的底层存储原理认识更加深刻,因为它驱动了业界太多极具影响力的存储系统走向成功,比如 HBase、Cassandra、RocksDB 等等。


Kafka的存储难点是什么

Kafka 通过简化消息模型,将自己退化成了一个海量消息的存储系统。既然 Kafka 在其他功能特性上做了减法,必然会在存储上下功夫,做到其他 MQ 无法企及的性能表现。

但是在讲解 Kafka 的存储方案之前,我们有必要去尝试分析下:为什么 Kafka 会采用 Logging(日志文件)的存储方式?它的选型依据到底是什么

Kafka 的存储选型逻辑,我认为跟我们开发业务需求的思路类似,到底用 MySQL、Redis 还是其他存储方案?一定取决于具体的业务场景。

我们试着从以下两个维度来分析下:

  1. 功能性需求:存的是什么数据?量级如何?需要存多久?CRUD 的场景都有哪些?
  2. 非功能性需求:性能和稳定性的要求是什么样的?是否要考虑扩展性?

再回到 Kafka 来看,它的功能性需求至少包括以下几点:

1、存的数据主要是消息流:消息可以是最简单的文本字符串,也可以是自定义的复杂格式。

但是对于 Broker 来说,它只需处理好消息的投递即可,无需关注消息内容本身。

2、数据量级非常大:因为 Kafka 作为 Linkedin 的孵化项目诞生,用作实时日志流处理(运营活动中的埋点、运维监控指标等),按 Linkedin 当初的业务规模来看,每天要处理的消息量预计在千亿级规模。

3、CRUD 场景足够简单:因为消息队列最核心的功能就是数据管道,它仅提供转储能力,因此 CRUD 操作确实很简单。

首先,消息等同于通知事件,都是追加写入的,根本无需考虑 update。其次,对于 Consumer 端来说,Broker 提供按 offset(消费位移)或者 timestamp(时间戳)查询消息的能力就行。再次,长时间未消费的消息(比如 7 天前的),Broker 做好定期删除即可。

我们再来看看非功能性需求:

1、性能要求:之前的文章交代过,Linkedin 最初尝试过用 ActiveMQ 来解决数据传输问题,但是性能无法满足要求,然后才决定自研 Kafka。ActiveMQ 的单机吞吐量大约是万级 TPS,Kafka 显然要比 ActiveMQ 的性能高一个量级才行。

2、稳定性要求:消息的持久化(确保机器重启后历史数据不丢失)、单台 Broker 宕机后如何快速故障转移继续对外提供服务,这两个能力也是 Kafka 必须要考虑的。

3、扩展性要求:Kafka 面对的是海量数据的存储问题,必然要考虑存储的扩展性。

再简单总结下,Kafka 的存储需求如下:

1、功能性需求:其实足够简单,追加写、无需update、能根据消费位移和时间戳查询消息、能定期删除过期的消息。

2、非功能性需求:是难点所在,因为 Kafka 本身就是一个高并发系统,必然会遇到典型的高性能、高可用和高扩展这三方面的挑战。


Kafka的存储选型分析

有了上面的需求梳理,我们继续往下分析。

为什么 Kafka 最终会选用 logging(日志文件)来存储消息呢?而不是用我们最常见的关系型数据库或者 key-value 数据库呢?


存储领域的基础知识

先普及几点存储领域的基础知识,这是我们进一步分析的理论依据。

  1. 内存的存取速度快,但是容量小、价格昂贵,不适用于要长期保存的数据。
  2. 磁盘的存取速度相对较慢,但是廉价、而且可以持久化存储。
  3. 一次磁盘 IO 的耗时主要取决于:寻道时间和盘片旋转时间,提高磁盘 IO 性能最有效的方法就是:减少随机 IO,增加顺序 IO。
  4. 磁盘的 IO 速度其实不一定比内存慢,取决于我们如何使用它。

关于磁盘和内存的 IO 速度,有很多这方面的对比测试,结果表明:磁盘顺序写入速度可以达到几百兆/s,而随机写入速度只有几百KB/s,相差上千倍。此外,磁盘顺序 IO 访问甚至可以超过内存随机 IO 的性能

再看数据存储领域,有两个 “极端” 发展方向:

  • 加快读:通过索引( B+ 树、二份查找树等方式),提高查询速度,但是写入数据时要维护索引,因此会降低写入效率。
  • 加快写:纯日志型,数据以 append 追加的方式顺序写入,不加索引,使得写入速度非常高(理论上可接近磁盘的写入速度),但是缺乏索引支持,因此查询性能低。

基于这两个极端,又衍生出来了 3 类最具代表性的底层索引结构:

  • 哈希索引:通过哈希函数将 key 映射成数据的存储地址,适用于等值查询等简单场景,对于比较查询、范围查询等复杂场景无能为力。
  • B/B+ Tree 索引:最常见的索引类型,重点考虑的是读性能,它是很多传统关系型数据库,比如 MySQL、Oracle 的底层结构。
  • LSM Tree 索引:数据以 Append 方式追加写入日志文件,优化了写但是又没显著降低读性能,众多 NoSQL 存储系统比如 BigTable,HBase,Cassandra,RocksDB 的底层结构

Kafka 的存储选型考虑

有了上面这些理论基础,我们继续回到 Kafka 的存储需求上进行思考。

Kafka 所处业务场景的特点是:

  • 写入操作:并发非常高,百万级 TPS,但都是顺序写入,无需考虑更新
  • 查询操作:需求简单,能按照 offset 或者 timestamp 查询消息即可

如果单纯满足 Kafka 百万级 TPS 的写入操作需求,采用 Append 追加写日志文件的方式显然是最理想的,前面讲过磁盘顺序写的性能完全是可以满足要求的。

剩下的就是如何解决高效查询的问题。如果采用 B Tree 类的索引结构来实现,每次数据写入时都需要维护索引(属于随机 IO 操作),而且还会引来“页分裂”等比较耗时的操作。而这些代价对于仅需要实现简单查询要求的 Kafka 来说,显得非常重。所以,B Tree 类的索引并不适用于 Kafka。

相反,哈希索引看起来却非常合适。为了加快读操作,如果只需要在内存中维护一个「从 offset 到日志文件偏移量」的映射关系即可,每次根据 offset 查找消息时,从哈希表中得到偏移量,再去读文件即可。(根据 timestamp 查消息也可以采用同样的思路)

但是哈希索引常驻内存,显然没法处理数据量很大的情况,Kafka 每秒可能会有高达几百万的消息写入,一定会将内存撑爆。
可我们发现消息的 offset 完全可以设计成有序的(实际上是一个单调递增 long 类型的字段),这样消息在日志文件中本身就是有序存放的了,我们便没必要为每个消息建 hash 索引了,完全可以将消息划分成若干个 block,只索引每个 block 第一条消息的 offset 即可,先根据大小关系找到 block,然后在 block 中顺序搜索,这便是 Kafka “稀疏索引” 的来源。


最终我们发现:Append 追加写日志 + 稀疏的哈希索引,形成了 Kafka 最终的存储方案。而这不就是 LSM Tree 的设计思想吗?

也许会有人会反驳 Kafka 的方案跟 LSM Tree 不一样,并没有用到树型索引以及 Memtable 这一层。但我个人认为,从「设计思想」从这个角度来看,完全可以将 Kafka 视为 LSM Tree 的极端应用。


Kafka 的存储设计

了解了 Kafka 存储选型的来龙去脉后,最后我们再看下它具体的存储结构。

可以看到,Kafka 是一个「分区 + 分段 + 索引」的三层结构:

1、每个 Topic 被分成多个 Partition,Partition 从物理上可以理解成一个文件夹。

之前的文章解释过:Partition 主要是为了解决 Kafka 存储上的水平扩展问题,如果一个 Topic 的所有消息都只存在一个 Broker,这个 Broker 必然会成为瓶颈。因此,将 Topic 内的数据分成多个 Partition,然后分布到整个集群是很自然的设计方式。

2、每个 Partition 又被分成了多个 Segment,Segment 从物理上可以理解成一个「数据文件 + 索引文件」,这两者是一一对应的。

一定有读者会有疑问:有了 Partition 之后,为什么还需要 Segment

如果不引入 Segment,一个 Partition 只对应一个文件,那这个文件会一直增大,势必造成单个 Partition 文件过大,查找和维护不方便。

此外,在做历史消息删除时,必然需要将文件前面的内容删除,不符合 Kafka 顺序写的思路。而在引入 Segment 后,则只需将旧的 Segment 文件删除即可,保证了每个 Segment 的顺序写。


本文小结

本文从需求分析、到选型对比、再到具体的存储方案,一步步拨开了 Kafka 选用 logging(日志文件)这一存储方案的奥秘。也是希望大家能去主动思考 Kafka 在存储选型时的难点,把它当做一个系统设计题去思考,而不仅仅记住它用了日志存储。

Kafka的存储设计相关推荐

  1. 如何实现百万TPS?详解JMQ4的存储设计

    专注于Java领域优质技术号,欢迎关注 来自 京东技术 导 读 JMQ是京东中间件团队自研的消息中间件,诞生于2014年,服务京东近万个应用,2018年11.11大促期间的峰值流量超过5000亿条消息 ...

  2. kafka 不同分区文件存储_Kafka深入理解-1:Kafka高效的文件存储设计

    Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx日志.访问日志,消 ...

  3. Kafka#4:存储设计 分布式设计 源码分析

    https://sites.google.com/a/mammatustech.com/mammatusmain/kafka-architecture/4-kafka-detailed-archite ...

  4. 搞透Kafka的存储架构,看这篇就够了

    阅读本文大约需要30分钟.这篇文章干货很多,希望你可以耐心读完. 从这篇文章开始,我将对 Kafka 专项知识进行深度剖析, 今天我就来聊聊 kafka 的存储系统架构设计, 说到存储系统,大家可能对 ...

  5. Kafka文件存储机制及offset存取

    Kafka是什么 Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx ...

  6. Kafka文件存储机制那些事

    Kafka是什么 Kafka是最初由Linkedin公司开发,是一个分布式.分区的.多副本的.多订阅者,基于zookeeper协调的分布式日志系统(也可以当做MQ系统),常见可以用于web/nginx ...

  7. 知乎基于Kubernetes的kafka平台的设计和实现

    我是知乎技术中台工程师,负责知乎存储相关的组件.我的分享主要基于三个,第一,简单介绍一下Kafka在知乎的应用,第二,为什么做基于Kubernetes的Kafka平台.第三,我们如何去实现基于Kube ...

  8. kafka是存储到本地磁盘么_【漫画】Kafka是如何实现高性能的?

    宏观架构层面利用Partition实现并行处理 Kafka中每个Topic都包含一个或多个Partition,不同Partition可位于不同节点. 同时Partition在物理上对应一个本地文件夹, ...

  9. Kafka整体结构图、Consumer与topic关系、Kafka消息分发、Consumer的负载均衡、Kafka文件存储机制、Kafka partition segment等(来自学习资料)

    ##1. Kafka整体结构图 Kafka名词解释和工作方式  Producer : 消息生产者,就是向kafka broker发消息的客户端.  Consumer : 消息消费者,向kafka ...

最新文章

  1. [转]WxEmojiView
  2. python面试技巧和注意事项_Python 程序员面试须知须会的5个问题
  3. CentOS cannot change locale UTF-8解决方法及设置中文支持
  4. 如何学习机器学习、看待算法竞赛?粉丝精选留言
  5. java基础—GUI概述
  6. JAVA仿真之银行出纳员
  7. 计算机没有设置光盘,U盘重装系统如何在没有光驱的电脑中操作?
  8. apache指定的网络名不再可用错误解决方法
  9. 容量规划的一些探讨与实践
  10. Android控件-TabLayout使用介绍
  11. 最全java面试题及答案(208道)
  12. 深度linux操作系统怎么样,深度Deepin国产操作系统使用体验报告!
  13. Ubuntu/Windows 双系统安装教程
  14. CS229 机器学习课程复习材料-线性代数
  15. java微信机器人_GitHub - linux-china/weixin-robot-java: 微信公共平台机器人Java SDK
  16. 原著《西游记》中的几点不解和穿帮
  17. artTemplate模板引擎
  18. 事业单位招聘计算机类面试自我介绍,事业单位面试自我介绍范文2分钟|2019事业单位面试自我介绍范文...
  19. mysql数据库中,查询一个表的下一条数据减上一条数据的值的写法
  20. java中文句号转换英文句号_java实现中文或其他语言及标点符号等转换成unicode字符串,或unicode的16进制码转换回文字或符号等...

热门文章

  1. 批次程序安裝手冊寫法
  2. windows7企业版 IIS常见问题
  3. mdadm中文man帮助
  4. 中国股市悬着四把利剑
  5. 关于 # 符号的使用 - 给 厨师 的回复
  6. VC++ 使用CreateProcess创建新进程
  7. 【leetcode】390. Elimination Game
  8. 实现WinForm窗体的美化(借助第三方控件)
  9. Centos/Linux下如何查看网关地址/Gateway地址
  10. Swift面向对象基础(中)——Swift中的存储属性和计算属性