前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >系列一:关于kafka的思考——后kafka时代下的消息队列,Kafka还会走多远?【kafka技术事务所】

系列一:关于kafka的思考——后kafka时代下的消息队列,Kafka还会走多远?【kafka技术事务所】

作者头像
大数据事务所-大菜菜
发布2021-09-09 11:44:31
4620
发布2021-09-09 11:44:31
举报

❝何为后kafka时代那?kafka自从 2011 年被捐献给 Apache 基金会到现在,已经发展到现如今的消息队列事实标准。作为一个优秀的分布式消息系统,Kafka 已经被许多企业采用并成为其大数据架构中不可或缺的一部分。Kafka也 已经不再只是分布式消息队列,而是想做集成了分发、存储和计算的“流式数据平台”。与此同时,大数据“新秀 Pulsar” 站在的kafka的肩膀上,针对kafka使用与维护过程中的痛点问题,明确提到“Pulsar 旨在取代 Apache Kafka 多年的主宰地位”的口号。 ❞

kafka作为一个老的基础组件,很多读者都已经对其设计和原理十分熟悉,面向Pulsar的冲击下,很多人或许会犹豫究竟要选择哪个技术?

本人在 Tencent 中负责维护数据总线与数据集成服务,kafka与pulsar是消息总线中的基本组件需求,并且我们的系统在具体的大数据消息队列之上,又抽象了一层管道(channel)的概念,使得可以将两种消息队列可以可插拔的嵌入服务中。因此,我们团队同时在使用Kafka与Pulsar。不可否认,Pulsar确实十分优秀,站在了前人的基础上,在架构底层重新定义的大数据消息队列。

但是,即使是Pulsar时代下,kafka的存在价值和使用场景是否发生了变化那?

本系列文章会带大家重新梳理和回顾Kafka的概念、设计、发展历史和其当下使用的场景。

发展历程和底层设计

Kafka 是 2010 年左右在 LinkedIn 研发的一套流数据处理平台。LinkedIn发现这些 MQ 系统都有两个比较通用的缺陷:一是当消费者出现,无法及时消费的时候,数据就会丢掉;二是可延展性问题,MQ 系统很难很好地配合数据的波峰或波谷。

这些需求正好对应当时的消息队列系统不能解决的一些问题:「横向拓展、持久化、高吞吐、高性能、甚至是低成本」。因此Kafka这一流处理系统出现后,瞬间成为大数据流处理系统的事实标准。

2010 年LinkedIn开始自己开发 Kafka。设计理念非常简单,就是一个以 「append-only 日志作为核心的数据存储结构」。简单来说,就是我们把数据以日志的方式进行组织,所有对于日志的写操作,都提交在日志的最末端,对日志也只能是顺序读取。

从我们当下的角度看待当时的kafka设计确实什么简单又十分优雅!kafka能实现上述的:横向拓展、持久化、高吞吐、高性能都得益于这个基础设计。

  1. 「顺序读写,高吞吐」:HDD 的随机读取和写入因为其本身原因会非常慢,但其实如果能够把所有的读和写都按照顺序来进行操作,会发现它几乎可以媲美内存的随机访问。kafka利用append-only 日志作为核心的数据存储结构,只会对文件进行顺序的读写操作,大大的利用了这一优点。【机械硬盘的连续读写性能很好,但随机读写性能很差,这主要是因为磁头移动到正确的磁道上需要时间,随机读写时,磁头需要不停的移动,时间都浪费在了磁头寻址上,所以性能不高。衡量磁盘的重要主要指标是IOPS和吞吐量。】
  2. 「物理分区,多分区扩展」:在Kafka中,Topic 只是一个逻辑的概念。每个 Topic 都包含一个或多个 Partition,不同 Partition 可位于不同节点。一方面,由于不同 Partition 可位于不同机器,因此可以充分利用集群优势,实现机器间的并行处理。另一方面,由于 Partition 在物理上对应一个文件夹,即使多个 Partition 位于同一个节点,也可通过配置让同一节点上的不同 Partition 置于不同的磁盘上,从而实现磁盘间的并行处理,充分发挥多磁盘的优势。
  3. 「多副本,保证高可用」:每个broker中的partition都会设置有replication(副本)的个数,生产者写入的时候首先根据分发策略(有partition按partition,有key按key,都没有轮询)写入到leader中,follower(副本)再跟leader同步数据,这样有了备份,也可以保证消息数据的不丢失。
  4. 「低成本」:Kafka 的日志存储持久化到磁盘,在部署时可以使用成本较低的HDD磁盘。
  5. 「页缓存加速」:顺序写文件时,「读操作可直接在 Page Cache 内进行。如果消费和生产速度相当,甚至不需要通过物理磁盘(直接通过 Page Cache)交换数据」;页缓存会将连续的小块写组装成大块的物理写从而提高性能;页缓存会 尝试将一些写操作重新按顺序排好,从而减少磁盘头的移动时间;【Cache 层在内存中缓存了磁盘上的部分数据。当数据的请求到达时,如果在 Cache 中存在该数据且是最新的,则直接将数据传递给用户程序,免除了对底层磁盘的操作,提高了性能】
  6. 「零拷贝,充分利用IO」:Kafka 在这里采用的方案是通过 NIO 的 transferTo/transferFrom 调用操作系统的 sendfile 实现零拷贝。总共发生 2 次内核数据拷贝、2 次上下文切换和一次系统调用,消除了 CPU 数据拷贝。【零拷贝(Zero-copy)技术指在计算机执行操作时,CPU 不需要先将数据从一个内存区域复制到另一个内存区域,从而可以减少上下文切换以及 CPU 的拷贝时间。它的作用是在数据报从网络设备到用户程序空间传递的过程中,减少数据拷贝次数,减少系统调用,实现 CPU 的零参与,彻底消除 CPU 在这方面的负载】

从我们当下的角度看待当时的kafka设计还是那么简洁和优雅,kafka能实现上述的:横向拓展、持久化、高吞吐、高性能都得益于这个基础设计。但是,这种简单的设计也有一些弊端,但是在kafka刚出的那个时候,这个设计和功能确实太优秀了。

Kafka使用痛点

首先先说结论,「后kafka时代下,kafka的某些设计已经比较落后了」。在运营/运维kafka的过程中,其实遇到了很多问题。

而很多问题是在基础架构确定之后,就决定了会有这样的结果。

单机器的分区上限问题

虽然 Kafka 的 topic partition 是顺序写入,但是当 broker上有成百上千个topic partition 时,从磁盘角度看就变成了随机写入,此时磁盘读写性能会随着 topic partition 数量的增加而降低,因此 「Kafka broker 上存储的 topic partition 数量是有限制的」

这大大限制了kafka在多主题情况下的使用。

非存储与计算分离的架构

kafka并不是一个存储与计算分离的架构,因此无法从存储和计算单个维度进行扩容。

数据存储和消息队列服务绑定,集群扩缩容/分区均衡需要大量拷贝数据,造成集群性能下降,并且带来了很大的运维成本。

一个分区只能归属于一台机器带来的文件存储

Kafka中根据设置的保留期来删除消息。有可能消息没被消费,过期后被删除。不支持TTL。

但是这其中的本质问题来自于:一个分区只能归属于一台Broker机器,如果想要扩容的话,只能扩分区,拆分区

在极端情况下,如果原有kafka集群负载到达50%,流量这时如果翻三四倍,这对kafka的运维来说简直是个灾难!

运维成本高

如果某个机器磁盘满了,需要显式的使用工具迁移分区(kafka-reassign-partitions.sh)

数据存储和消息队列服务绑定,集群扩缩容/分区均衡需要大量拷贝数据,会带来了很大的运维成本。

随着 Kafka 集群规模的增长,Kakfa 集群的运维成本急剧增长,需要投入大量的人力进行日常运维。在某互联网公司中,扩容一台机器到 Kafka 集群并进行分区均衡,需要 0.5人/天;缩容一台机器需要 1 人/天。

PageCache 污染问题,造成读写性能下降

Kafka对page cache需求巨大。根据经验值,为Kafka分配6~8GB的堆内存就已经足足够用了,将剩下的系统内存都作为page cache空间,可以最大化I/O效率。

另一个需要特别注意的问题是lagging consumer,即那些消费速率慢、明显落后的consumer。它们要读取的数据有较大概率不在broker page cache中,因此会增加很多不必要的读盘操作。

比这更坏的是,「lagging consumer读取的“冷”数据仍然会进入page cache,污染了多数正常consumer要读取的“热”数据」,连带着正常consumer的性能变差。在生产环境中,这个问题尤为重要。

在 catch-up 读场景下,容易出现 PageCache 污染,造成读写性能下降。虽然kafka可以利用PageCache进行读取加速,在一些场景下实践效果不佳。

「Kafka不支持读写分离」

在 Kafka 中,生产者写入消息、消费者读取消息的操作都是与 leader 副本进行交互的,从 而实现的是一种「主写主读」的生产消费模型。Kafka 并不支持「主写从读」

其实kafka的「主写主读」也是有一些优点的:

  1. 可以简化代码的实现逻辑,减少出错的可能;
  2. 将负载粒度细化均摊,与主写从读相比,不仅负载效能更好,而且对用户可控;
  3. 没有延时的影响;
  4. 在副本稳定的情况下,不会出现数据不一致的情况。

但是这些也不能算是完全的优点,「只是在当前kafka架构下,做到读写分离的收益不如主写主读方案。」

kafka中IO 不隔离,因此「消费者在清除 Backlog 时会影响其他生产者和消费者」

后Kafka时代的使用场景

什么样的场景下可以继续用kafka?

在集群内topic不多或增长速度不是特别快的情况下,kafka依旧是很好的选择。

不需要复杂的企业级场景的时候,kafka仍旧是首选。

Kafka 原生的集群模式使用简单,能满足少量业务的需要。但对于大型企业(网站),大量的业务使用 Kafka,数据量、流量极大,必然同时存在多个集群,需要对用户的接入、运行时监控、集群运维提供统一的解决方案

版本变更

kafka 0.7 版本

kafka开源后的第一个正式的版本

提供了数据的压缩以及 MirrorMaker,也就是跨集群之间的数据拷贝。

这个版本太过久远,我们就不再占用篇幅介绍了

kafka 0.8 版本

Kafka 0.8.0 里面加入了多副本功能,也就是基于备份的一个高可用性的特性。

该版本中提出了一个叫做 ISR,或者叫做实时备份列表的机制。我们把所有的备份分为已同步和未同步的备份。

已同步的备份指,Leader 所有的 Data 在 replica 里面都有;未同步的很简单,由于可能比较慢,或者备份还不完整,也许有些数据在 Leader 上面有,但是在 replica 上没有。Leader 可以通过来管理这样的一个列表来做到实时的修改。同时,发布者发布信息的时候,可以要求备份方式。

kafka 0.9 版本

当 Kafka 集群不断变大、使用场景不断增多的时候,多租户之间的影响就会非常显著,一个人可以影响其他所有用户。

有一个员工写的客户端,当获取元数据失败时会一直发请求,并部署到了几十台机器上,结果就影响了所有的其他用户。所以我们在 0.9 里第一个要加的重大机制就是配额,限定每一个 user 能够用多大的流量跟 Kafka 交互。如果你超过配额,Kafka broker 就故意延迟你的请求,使一个 User 不会影响别人。这就是 0.9 的配额机制。

之前版本,Kafka其实存在一个比较大的隐患,就是利用 Zookeeper 来存储记录每个消费者/组的消费进度。虽然,在使用过程当中,JVM帮助我们完成了一些优化,但是消费者需要频繁的去与 Zookeeper 进行交互,而利用ZKClient的API操作Zookeeper频繁的Write其本身就是一个比较低效的Action,对于后期水平扩展也是一个比较头疼的问题。如果期间 Zookeeper 集群发生变化,那 Kafka 集群的吞吐量也跟着受影响。

从kafka-0.9版本及以后,kafka的消费者组和offset信息就不存zookeeper了,而是存到broker服务器上,所以,如果你为某个消费者指定了一个消费者组名称(group.id),那么,一旦这个消费者启动,这个消费者组名和它要消费的那个topic的offset信息就会被记录在broker服务器上。

kafka 0.10 版本

Kafka Streams 是在 0.10 里面加入的,它是一个流处理的平台,或者叫它是流处理的一个库。它是基于发布端和消费端的处理平台,它能够做到的是 Event-at-a-time、Stateful,并且支持像 Windowing 这样的操作,支持 Highly scalable、distributed、fault tolerant。所有这些都很大程度上利用了 Kafka broker,也就是服务器端本身的延展性和高可用性。

简单来说,Kafka Streams 所做的就是从 Kafka 的 Topic 里实时地抓取数据。这个数据会通过用户所写拓扑结构,把所有的 record 实时进行 transform 之后,最终再写回到 Kafka 里面,是个很简单的流数据处理。那么它怎么做延展性呢?也很简单,当用户写好一个拓扑结构以后,可以在多个机器,或者多个容器、多个虚拟机、甚至是多个 CPU 上面,部署多个应用,当应用同时进行的时候,会利用 Kafka 自动地划分每一个不同的应用所抓取的不同 partition 的数据

kafka 1.0版本

在该版本下做到 Exactly-Once,这才能使 Kafka 作为一个成熟的流数据平台

非 Exactly-Once 是指由于网络延迟或其他各种原因,导致消息重复发送甚至重复处理。那么直白来说 Exactly-Once 的定义,就是从应用的角度来说,当发生了错误,希望做到每一个接收到的 record,处理结果会被反映到它的处理状态中,一次且仅有一次,也就是 Exactly-Once。

之后的版本中,虽然在持续迭代,但是从kafka的底层架构来看,没有其他的重大更新了

参考资料:

https://mp.weixin.qq.com/s/p-jJVMjh9yr8QVqgRKtPtA

https://zhuanlan.zhihu.com/p/337861077

https://zhuanlan.zhihu.com/p/344277683

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-09-04,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大数据技术事务所 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 发展历程和底层设计
  • Kafka使用痛点
    • 单机器的分区上限问题
      • 非存储与计算分离的架构
        • 一个分区只能归属于一台机器带来的文件存储
          • 运维成本高
            • PageCache 污染问题,造成读写性能下降
              • 「Kafka不支持读写分离」
              • 后Kafka时代的使用场景
              • 版本变更
                • kafka 0.7 版本
                  • kafka 0.8 版本
                    • kafka 0.9 版本
                      • kafka 0.10 版本
                        • kafka 1.0版本
                        相关产品与服务
                        消息队列 CMQ 版
                        消息队列 CMQ 版(TDMQ for CMQ,简称 TDMQ CMQ 版)是一款分布式高可用的消息队列服务,它能够提供可靠的,基于消息的异步通信机制,能够将分布式部署的不同应用(或同一应用的不同组件)中的信息传递,存储在可靠有效的 CMQ 队列中,防止消息丢失。TDMQ CMQ 版支持多进程同时读写,收发互不干扰,无需各应用或组件始终处于运行状态。
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档