面对 Kafka 规模快速增长带来的成本、效率和稳定性挑战时,小红书大数据存储团队采取云原生架构实践:通过引入冷热数据分层存储、容器化技术以及自研的负载均衡服务「Balance Control」,成功实现了集群存储成本的显著降低、分钟级的集群弹性迁移、高性能的数据访问策略和自动化的资源调度。
这些技术革新不仅极大提升了 Kafka 集群的运维效率,还为小红书业务带来了更优质的服务体验,同时为未来在存算分离、多活容灾等方向的进一步优化奠定了基础。
1.1 小红书 Kafka 的发展现状
小红书 Kafka 集群规模伴随着公司业务的蓬勃发展而显著扩张。目前,集群的峰值吞吐量已经达到 TB 级别,并且随着 AI 大模型和大数据技术的持续扩展,数据量仍在快速增长。
尽管经典的 Apache Kafka 架构在提供高吞吐、高性能数据传输方面表现出色,但也逐渐暴露出了一些弊端。一方面,基于多副本和云盘/SSD 的模式,Apache Kafka 的存储成本居高不下,难以满足业务长期存储数据的需要;另一方面,数据与计算节点之前的强绑定关系,严重阻碍了集群的扩缩容效率,在弹性和调度能力方面受到了很大的挑战。
1.2 面临的问题
随着小红书 Kafka 集群规模的持续扩大,一系列挑战也随之而来,涉及成本、能效、运维和系统稳定性等多个方面:
成本:
存储成本昂贵:Kafka 的存储成本较高,按当前内部机器规格配比,在充分利用带宽的情况下,数据存储的生命周期非常有限。
算力资源浪费:Kafka 的性能瓶颈主要集中在 IO 操作上,存在大量的 CPU 资源处于闲置状态。加之现有的虚拟机部署方式在资源共享和隔离方面表现不佳,进一步限制了 CPU 资源的有效分配。
效率:
集群运维耗时长:因磁盘和节点绑定,Kafka 集群的扩缩容需要搬迁海量数据,这不仅速度缓慢,而且耗时可能从数天到数周不等。
调度能力弱:因虚机部署,缺乏灵活的资源调度能力,一旦坏机,补货效率低。
稳定性:
应急能力差:缓慢的扩缩容速度导致性能指标在高负载下显著下降,请求响应时间可能延长至正常情况的两倍,影响整体服务质量。
追赶读期间稳定性受损:在追赶读操作期间,系统资源的大量消耗会使得资源使用率飙升,从而影响到实时读写任务的稳定性
综上所述,Kafka 集群面临的主要痛点可归纳为两个核心问题:存算一体化架构的局限性,以及虚拟机部署方式带来的运维和资源调度难题。解决这些问题,对于提升 Kafka 集群的整体性能和运维效率,具有重要意义。
1.3 解决方案
1.3.1 如何解决“存算一体化”带来的问题?
为了解决存算一体化架构弊端,我们需要引入「Cloud-Native」弹性架构模式,来解耦存储与计算,下述为方案对比:
1)自研存算分离(on ObjectStore):
该方案通过对象存储作为统一的存储基础,实现了计算层与数据绑定关系的解耦。存储层利用对象存储的纠删码技术和规模经济效应,能同时获得秒级弹性与成本两大收益,是较为理想的解决方案。
然而,对象存储本身延迟较高,想要达到整体较高的性能,需要有独立的读写加速层配合,这一部分也需要考虑弹性化的架构设计。整体架构复杂度较高,因此方案研发周期会比较长。
2)冷热分层存储(on ObjectStore):
冷热分层的概念,即为本地仅保留少量的热数据,将大部分冷数据卸载到较为便宜的对象存储中,以实现成本节约。Kafka 和其他 MQ 类社区,近年来陆续提出该概念并进行发展。
此架构不改变数据核心的写入流程和高可用性(HA)机制,而是异步卸载数据以减少对核心架构的改动,实现难度较低。不过弊端也正是因为没有触动核心的副本机制,数据与计算节点之间仍然存在部分的耦合,在弹性能力方面稍逊一筹。
3)Apache Pulsar
Apache Pulsar 是近年来非常火热的一款云原生消息引擎,它天生支持存算分离架构,具备快速的弹性扩展特性,同样是一个选择。不过其底下的存储底座 Bookkeeper 仍然基于磁盘存储,单节点受限于磁盘容量,在存储成本上没有明显收益(但 Pulsar 近期也引入了分层存储能力)。此外,考虑到历史大量的存量作业,转向 Pulsar 可能面临较高的推广难度和替换周期,眼下难以快速拿到收益。
在当前阶段,“成本”是我们最关心的问题。如何获得大量成本节省?如何缩短收益获取周期?都是需要核心考虑的因素。在经过大量对比和取舍后,「分层存储」架构依靠其低成本、中等弹性、短落地周期的特点,成为了我们当下的更优选择。
与社区版本相比,小红书分层架构经过了完全的重新设计,解决了原有方案的多项问题,并显著提升了数据迁移速度和冷数据读取性能。在新架构上线六个月内,我们已完成线上 80% 的集群升级覆盖,充分地获得了新架构带来的各项收益。
1.3.2 如何解决“虚机部署”带来的问题?
为了解决虚机部署带来的问题,关键在于提升混部与调度能力、优化算力资源的使用、以及增强自动化运维的水平。以下是几种方案的对比分析:
综合考虑,采用小红书容器底座结合 PaaS 平台托管的新型容器化架构,不仅能够平滑地将 Kafka 迁移至云端,还能显著提升算力资源的利用率,加强运维自动化。
2.1 整体架构
小红书 Kafka 云原生架构共分为四层:
接入层:小红书 Kafka 特色 SDK,提供鉴权、限流、服务发现等丰富功能,实现更加灵活和安全的数据流管理
计算层:Kafka Broker 基于「分层存储」技术,实现本地数据“弱状态化”,有效地解决了系统的弹性问题,保障系统的稳定性和可扩展性
调度层:负载均衡调度器向北可均衡 Broker 间流量负载,向南结合容器实现自动化弹性扩缩容,保障系统能够根据实际需求动态调整资源,实现 “弹性伸缩、按量付费”
基建层:容器和对象存储底座,为整个系统提供了强大的 PaaS 平台化运维管理调度能力和低成本无限存储能力
2.2 分层存储
分层存储作为 Kafka 云原生化的核心能力,提供成本优化、消费隔离、弹性扩展等多重优势。其整体架构如下图所示。基本原理是基于冷热分层,即将近实时的热数据保留在高性能云盘中,而将冷数据下沉至低成本、可靠性极高的对象存储中。
对象存储具有无限扩展、低成本、可靠性极高的特点。通过利用对象存储来存储数据,我们能够从根本上解决不断增长的数据存储需求,摆脱了传统数据存储所带来的诸多烦恼。对象存储的架构设计理念,使其在处理大规模数据时表现出色,同时确保了数据的高可用性和安全性,为 Kafka 架构的云原生化提供了强大的支撑。
2.2.1 存储成本优化
在大数据场景下,业务方经常需要回溯过去多天的数据,以进行各种分析、回溯和审计等操作。然而,传统的基于云盘的 Kafka 存储解决方案不仅成本高昂,而且在存储能力上也存在限制,只能满足短期数据的存储需求,这对于需要长期数据保留的业务场景构成了重大挑战。
为了突破这一瓶颈,我们采用基于对象存储的分层存储架构。这一创新举措显著降低了存储成本并提升了数据存储的灵活性。对象存储的低成本特性,结合其出色的扩展能力,使得小红书 Kafka 能够经济高效地存储大量数据,同时保证了数据的高可靠性和安全性。
在实施分层存储架构的过程中,我们采取了以下策略:
冷数据存储:将不常访问的冷数据迁移到成本更低的对象存储中,从而大幅度减少存储开支。
热数据存储:对于频繁访问的热数据,继续使用性能较高的云盘存储(EBS),但通过优化存储策略,将存储容量减少了75%。
通过这种新型的存储架构,小红书 Kafka 实现了存储成本的大幅度降低——最高可达 60%。此外,这种架构还允许 Topic 的存储时间从原来的 1 天延长至 7 天或更久,极大地增强了业务数据的回溯能力,为业务数据驱动决策提供更加坚实的基础。
2.2.2 分钟级弹性迁移
在 Kafka 原生架构中,集群扩容是一个复杂且耗时的过程。由于冷数据存储在磁盘上,扩容时需要搬迁海量数据,这不仅会导致磁盘和网络 IO 的负载达到极限,也会对集群的稳定性造成影响。
我们引入了分层存储机制后,Topic 的所有副本可以共享同一份冷数据。这意味着对于 Topic 的新副本,在集群扩容时不再需要复制 Leader 本地的所有热数据,而只需拷贝远端尚未拥有的部分,通常是 Leader 本地存储的最后一个 segment。
这种优化显著减少了迁移数据的量,从而将 Topic 迁移的时间从天级别缩短到分钟级别。在实际应用场景中,即使是对于具有 10GB/s 吞吐量的 Topic,在流量高峰期的迁移过程也仅需 5 分钟即可完成。
2.2.3 高性能缓存策略
引入对象存储后,虽然解决了存储成本和弹性等问题,但也面临了一些挑战,主要包括访问速度和延迟等方面,具体表现为:
访问速度: 对象存储的总吞吐上限理论只受带宽限制,但单线程访问速度较低,远远低于传统磁盘存储。
延迟: 目前对象存储主要通过 HTTP 协议进行访问,因此存在较高的延迟,包括建立连接等操作的延迟可达到 20 毫秒级别,对于部分小文件访问极不友好。
针对这些问题,我们采取了以下优化策略:
批量读取: 以 8MB 对齐的方式读取 Segment 数据,减少访问次数,从而提升数据读取的效率。
缓存预加载: 结合数据访问的局部性原理和消息队列的顺序读特性,实现了并发的预读机制,以提高数据的访问速度和响应性。同时,通过内存隔离技术,避免了 pagecache 被污染的问题。
这些策略的实施带来了显著的性能提升:
高缓存命中率: 缓存命中率达到了 99%,有效地提高了数据访问的效率和速度。
性能提升:冷数据读取性能相比开源架构提升了 30%,这在大规模数据处理场景中尤为重要。
2.3 容器化
下图为小红书 Kafka 容器化的整体架构:
PaaS 能力托管:通过小红书容器化调度 PaaS 平台来托管 Kafka 集群,这不仅简化了部署和运维流程,降低了运维成本,而且通过图形化界面实现了集群版本和配置的直观管理,即所谓的「白屏化操作」。
服务状态管理:为了保证有状态应用服务的连续性和状态的一致性,我们采用 DupicateSet(StatefulSet) 来管理 Kafka 服务。
异常保护机制:
基于 Supervisord 的进程监控:在容器内部,Supervisord 作为主要的进程管理工具,监控 Kafka 进程。一旦 Kafka 进程异常退出,Supervisord 能够迅速重启进程,避免了容器级别的重建,从而减少了服务中断时间。
快速修复(HotFix):当基础环境如数据存储出现问题时,业务团队可以直接进入容器进行快速修复,这种即时的干预能力大大提高了系统的稳定性和恢复速度。
集群状态的删除保护:我们实现了基于 Kafka 集群状态的删除防护机制。当集群中掉队实例的数量超过预设阈值时,通过 Webhook 技术自动拒绝所有可能恶化集群状态的操作请求,从而保护集群不受进一步损害。
2.3.1 状态管理
在 Kubernetes 环境中部署有状态服务如 Kafka 时,确保其状态的持久性和可靠性是至关重要的。
Kafka 的状态主要包括拓扑状态和存储状态,以下是对这两部分状态的管理策略:
拓扑状态:拓扑状态涉及 Pod 的网络和身份标识,确保每个 Pod 具有固定的标识和访问方式。我们通过容器底座提供的能力保障了 Pod IP 不变。
存储状态:存储状态包括云盘数据、日志数据和配置文件等,这些数据需要在 Pod 迁移、重启或升级时保持不变。
持久卷(PV)和持久卷声明(PVC):使用 DupicateSet 使用,为每个 Pod 分配专用的存储资源,确保存储状态的持久性和一致性。
配置管理:使用 ConfigMap 和环境变量来管理 Kafka 的配置,确保 Pod 即使重启,配置也能保持不变。
日志管理:将日志目录放置在持久化数据卷中,保障日志数据在 Pod 重启或迁移时不会丢失。
2.3.2 离线混部
在上云之前,Kafka 作为存储产品,面临着单机 CPU 能效低下的问题,大约只有 10% 的效率,这主要是由于夜间流量低谷以及 IO-bound 特性所致。在这种情况下,往往存在大量的闲置 CPU 资源,导致资源利用率不高。
上云后通过容器提供的混部能力,我们可以将离线业务调度至 Kafka Kubernetes 机器池中,填平 CPU 低谷,从而保证全天利用率达到一个较高的水平。这种整合策略显著提升了资源的全天利用率,上云后的能效利用率提高到了 40% 以上,远高于之前的水平。
利用容器技术的混部能力,使得我们能够更加灵活地管理和调度资源,根据实际情况对资源进行动态分配和利用,从而最大限度地提高了系统的整体性能和资源利用率。
2.3.3 CA 资源调度
除了上述提及能力外,容器技术还为我们带来了资源层面的弹性调度能力,其中 Cluster Autoscaler(CA)是一项关键技术。
在未采用 Cluster Autoscaler 的传统模式下,系统工程师(SRE)需要手动执行服务器的启动和关闭操作,这不仅效率低下,而且在面对紧急的扩容需求时,现有的流程显得繁琐且响应迟缓,无法及时适应业务需求的波动。
引入 Cluster Autoscaler 之后,这一状况得到了根本性的改善。CA 能够自动管理业务集群的扩缩容流程,以缓冲区(Buffer)的形式智能地调整资源分配。它通过实时监控集群的负载情况,动态地增加或减少节点数量,实现了快速且精准的资源弹性调度。这种自动化的调度机制不仅提升了系统的适应性和稳定性,而且显著降低了运维团队的工作负担,确保了业务的持续稳定运行。
2.4 弹性调度
在线上部署的 Apache Kafka 集群中,流量波动、Topic 的增减以及 Broker 的启动与关闭是常态。这些动态变化可能导致集群中节点的流量分布不均衡,进而引起资源浪费和影响业务的稳定性。为了解决这一问题,需要对 Topic 的分区进行主动调整,以实现流量和数据的均衡分配。
原生 Apache Kafka 由于磁盘上存储大量历史数据,因此在进行均衡调度时会打满磁盘 IO 和网络带宽,从而影响实时业务的正常运行,导致集群负载均衡较为困难。
相比之下,分层的弹性架构则为负载均衡提供了可能。这种架构设计使得在进行负载均衡调度时可以避免过多的 IO 压力,从而减少对实时业务的影响,使得负载均衡的调整更加灵活和高效。
因此,除了分层和容器两大关键 『弹性』 技术,我们还自研了负载均衡服务 「Balance Control」,其能够充分利用分层和容器的软硬件弹性能力,实现持续数据平衡和自动弹性扩缩容,使得集群能够更加灵活地应对流量波动和业务变化,从而保障了系统的稳定性和可靠性。
2.4.1 持续数据自平衡(Auto-Balancing)
Balance Control 采用多目标优化算法来实现资源分配的最优化。其能够综合考虑 Topic 副本、网络带宽、磁盘存储、计算资源等多种因素,自动调整 Partition 分配,以达到更优的资源负载平衡。整体自平衡流程如下:
数据采集:Kafka 侧 Metrics Reporter 监听 Kafka 内置的所有指标信息,并定期对感兴趣的指标(如网络进出口流量、CPU 利用率等)进行采样,并上报指标
指标聚合:收集的指标用于生成集群状态快照 ClusterModel,包括 Broker 状态、Broker 资源容量、各 Broker 管理的 Topic-Partition 流量信息等
调度决策自平衡:调度决策器定期获取集群状态模型的快照,并根据各个 Broker 的容量和负载信息,识别出流量过高或过低的 Broker。随后,它会尝试移动或交换分区,以完成流量的重新平衡。
2.4.2 自动弹性扩缩容(Auto-Scaling)
原生 Kafka 扩容需要搬迁海量数据,耗时通常为小时甚至天级,几乎无法做到按需扩缩容。为了维持集群的稳定性,运维团队不得不提前规划资源,以应对可能的流量高峰,这种做法往往导致资源的浪费和效率的降低。
云原生时代,通过借助分层和容器的软硬件弹性能力,Balance Control 可以在分钟级自动完成集群的原地扩缩容和流量的重新调度,以适应业务负载的变化,做到 「弹性伸缩、按量付费」 的目标。这一关键能力我们称之为 AutoScala。
AutoScala:实时监控 Kafka 集群的负载,并根据预设的策略自动调整集群规模。例如,当集群负载超过某个阈值(如 70%)并保持一段时间时,系统会自动增加集群规模;从而实现快速、高效的集群扩缩容,优化资源利用率。
整体流程如下:
负载监控:Kubernetes 的 Horizontal Pod Autoscaler(HPA)组件根据预设的策略(如定时、资源水位等)来判断是否需要扩容,并相应地调整集群规模配置。
自动负载均衡:当 Balance Control 探测到新加入的 Broker,分钟级完成流量调度平衡。
总体来看,云原生弹性架构为小红书 Kafka 带来了巨大的成本收益和运维效率提升。从落地效果上看,我们实现了 60% 的存储成本节省和 10 倍的扩缩容运维效率提升,并成功实现了「弹性伸缩、按量付费」的商品化模式。
此外,我们正不断探索和优化云原生消息引擎的能力,以期提供更稳定和高效的服务。未来,我们计划持续研究存算分离技术和多活容灾方案,以实现极致的系统可扩展性和稳定性,满足业务日益增长的服务需求。
随着技术的不断演进,我们将不断引入新的技术能力和创新方案,为业务提供更加卓越的消息引擎服务,期待您加入团队!