掘金 后端 ( ) • 2024-04-27 23:08

theme: fancy highlight: a11y-dark

本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!


分布式队列 - Kafka

Kafka作为分布式消息队列领域的杰出代表,已深深嵌入于各式流处理平台的核心,被广大用户广泛认可并采纳为关键性的数据供给渠道。其在多种技术栈中不可或缺的地位,有力地证明了Kafka在应对大规模、持续不断的实时数据流挑战时所展现出的卓越性能与高度适配性。

接下来,让我们深入剖析其服务架构与功能特性,揭示其背后蕴藏的设计精妙与技术实力,以理解其如何缔造如此出色的性能表现。

架构特性

Kafka通过运用其独特的分布式体系结构、精心设计的【磁盘利用机制】、【庞大的存储容量】、【先进的数据打包与压缩技术】,以及对【操作系统级缓存资源】的巧妙的运用,彰显出无与伦比的扩展潜能、存储经济性与数据处理效能。 在这里插入图片描述 经过精心优化的内核设计使得 Kafka 能够以极低的延迟处理大量消息,轻松支撑每秒百万级别的消息投递,满足大数据时代对实时性与处理速度的严苛要求。

可扩展性

Kafka 采用分布式集群部署,支持水平扩展以应对不断增长的数据量与处理需求,同时通过数据分区与副本机制确保数据的高可用性与容灾能力。这种弹性扩展能力使得Kafka能够在保持服务稳定的同时,轻松应对大规模数据流的挑战。 在这里插入图片描述

磁盘优化与顺序访问

Kafka巧妙利用磁盘空间,规避随机访问开销,消息以追加方式写入磁盘,并以分段日志形式存储。 在这里插入图片描述 确保了写入过程主要为顺序操作,极大提升了I/O效率,Kafka将消息持久化存储在磁盘上,不仅允许短暂的消息缓冲,还能作为长期数据存储,便于下游系统进行回溯消费或离线分析。 在这里插入图片描述 此外,Kafka巧妙管理日志段的生命周期,即使消息已被消费者消费,仍可保留一定时间,以供新加入的消费者回溯历史数据,或者用于离线分析与备份。

大容量存储与历史数据利用

通过高效利用磁盘存储资源,Kafka展现出强大的数据承载能力,能够从容应对大规模数据流。其设计允许即使在消息已被消费者处理后,仍可暂时保留在系统中。

  • 回溯消费:加入的消费者能够追溯并处理过去的历史数据,这对于实现无缝对接新消费者或恢复丢失状态至关重要。
  • 批量处理:Kafka允许一次性拉取大量数据,确保了批处理作业的高效执行,减少了网络交互次数,提升了整体处理吞吐。

高效数据封装与压缩

Kafka在数据封装方面采取轻量化策略,消息格式简洁且支持压缩,有效减少了传输和存储时的空间占用。 在这里插入图片描述 通过消除冗余对象包装,直接以接近原始数据的形态进行处理,降低了资源消耗。这种设计不仅加快了数据传输速度,还减少了中间环节的解码开销。

智能内存管理与OS缓存利用

Kafka巧妙利用操作系统级别的页面缓存(Page Cache),避免了应用程序层面额外缓存的引入,从而节省宝贵的内存资源。 在这里插入图片描述 直接操作文件数据,使得Kafka能够与OS缓存机制紧密协作,充分利用硬件缓存的优势,进一步提升数据读写的性能和效率,同时避免了多个组件间对内存资源的竞争。

Kafka发布/订阅模型

Kafka作为一款高度工程化的分布式消息传递系统,其内在价值体现在它精心构筑了一个坚如磐石的基础架构,该架构深度融合了容错性、扩展性和卓越的吞吐性能,旨在为大规模分布式环境中的数据流转提供无可挑剔的安全性与效率保障。 在这里插入图片描述 提供灵活的消息发布与订阅机制,多个生产者可以向同一Topic发送消息,而多个消费者可以根据自己的消费速率独立地订阅并处理这些消息,实现了数据流的解耦与异步处理。

Kafka架构分析

接下来,我们将详尽解析Kafka的基本架构以及Kafka系统的核心组件及其交互方式。

Kafka 在分布式消息传递体系中扮演着至关重要的中介角色,其核心功能体现为一个高度可扩展且高容错性的 broker 系统。作为一个消息代理,Kafka 有效地联结了消息的生产者(producers)与消费者(consumers),在二者之间建立起可靠的通信桥梁。 在这里插入图片描述 实际上,Kafka 构建于一个由多个节点组成的集群(cluster)之上,这种集群架构赋予了系统卓越的吞吐能力、数据冗余以及故障恢复能力。

Producer和Consumer接口交互

Kafka 集成了专属的 producer API 与 consumer API,这两套接口构成了与系统进行交互的标准接入层。无论开发者选择直接利用官方提供的客户端库对接这些 API。基于 API 规范自主研发符合业务需求的访问逻辑,producer 和 consumer 客户端均需遵循这些接口规范以确保与 Kafka broker 的顺畅通讯与数据交换。

Producer通过Topic发送数据

在Kafka中,数据流被组织成一系列被称为topic 的集合,为有效管理和控制单个topic 内的数据规模,topic 可以进一步划分为多个 Partition,并尽可能地分布在不同的节点上以实现负载均衡和水平扩展。为了确定数据写入哪个 Partition,Producer 需要执行一项决策过程。 在这里插入图片描述 在 Kafka 的 Producer API 设计中,提供了允许用户指定 Partition 键的参数机制。当用户指定了 Partition 键后,Producer API 会采用哈希算法对该键值进行计算,从而得出相应的 Partition 编号,以此来实现数据的定向发送和均匀分布。

Consumer通过Topic消费数据(消费组)

Kafka 灵活支持点对点(point-to-point)和发布/订阅(pub/sub)这两种消息队列模式,其关键在于引入了 Consumer Group 的概念。每个 Consumer Group 虽然被视为一个逻辑上的虚拟消费者,但实际上它可以包含多个实际的 consumer 实例。

点对点模式

所有 consumer 被配置为隶属于同一 Consumer Group,确保消息在组内严格有序且仅消费一次。 在这里插入图片描述

发布/订阅模式下

来自不同发布者的订阅者会被划分到不同的 Consumer Group 中,任何给定的 partition 在同一时间只能被所属 consumer group 中的一个 consumer 进行消费。 在这里插入图片描述

注意,每个 Consumer 实例在同一时刻仅与一个 partition 进行绑定,这意味着每个 consumer 只从分配给它的唯一一个 partition 中拉取消息进行处理。这样的设计保证了消息的有序消费及并行处理能力,同时也确保了 Consumer Group 内部的消息均衡分发。

Kafka设计的局限性

在这里插入图片描述

1. 消费组的consumer数量不应少于Partition数量

若 Consumer Group 内的实际 consumer 数量小于 Partition 数量,且没有正确地配置分区分配策略,则可能导致部分 Partition 中的数据无法得到对应 consumer 的消费处理。为了确保 Consumer Group 中的每个 Partition 均能够有 consumer 进行数据消费,Consumer Group 内的 consumer 数量不应少于 Partition 数量,否则将会面临某些 Partition 数据无人处理的现象。

2. 消费组的consumer的服务器尽量保持配置相近

若各consumer 消费数据的速度存在差异,那么 Partition 的消费进度可能会出现不均衡状况。具体表现为,部分 Partition 已经迅速消费至最新产生的数据,而其他Partition则仍停留在较早阶段的数据消费过程中,从而导致整个系统的消费进度不一致。

3. 简单的数据路由无法真正实现对应的消费均衡

  • Producer必须自行选择将数据投递至哪一个 Partition,因此,由于 Partition 的选择权在于 Producer,故由 Producer 端调整数据分布以改善消费不均衡的问题并不现实。
  • Consumer 同时只能与一个 Partition 绑定,通过简单的轮询策略(round-robin)在 Producer 或 Consumer 端均无法有效解决消费进度不均衡的问题。

4. 无法实现全局的消息的先进先出的顺序实现

每个Partition 实质上可视为一个消息子队列,它们各自维护消息顺序。尽管 Partition 机制存在,但 Kafka 并不保证跨 Partition 的全局顺序一致性;相反,它确保的是每个 Partition 内部消息的局部有序性。换言之,消息在单一 Partition 内遵循严格的先入先出(FIFO)原则,而不同 Partition 之间的消息顺序则不予保证。

Kafka的双R机制

Kafka的rebalance机制

Consumer group 内部动态调整,例如新增Consumer时,会自动触发重新平衡过程。这一过程旨在重新配置 partition 与 consumer 之间的映射关系,从而有效地均衡各 consumer 的数据负载。

下图是一个借鉴图,基本描述了整个rebalance的流程和过程: 在这里插入图片描述 通过这样的动态调整,原本可能存在的数据消费不均状况得以缓解,提升了整体系统的处理效率与资源利用率。

Kafka的replication机制

Kafka 实现复制的核心在于以Partition为基本单位,采取直接而高效的方式,让复制节点(Replicas)订阅并追踪目标 Partition,利用队列的天然订阅机制来简化复制流程。

每个复制集(Replica Set)内置一个主节点(Leader),专职处理所有读写操作,而其余跟随节点(Followers)作为热备,处于待命状态。

  1. 主节点之外的跟随节点集体构成了ISR(In-Sync Replicas)列表,该列表记录了与主节点数据同步状况良好的副本,确保了高可用性。ISR成员并非固定不变,而是根据同步状况动态调整。

  2. 数据写入流程中,尽管操作首先通过主节点执行,但系统默认要求数据必须被复制到ISR中的所有副本方视为提交成功(committed),之后方可供消费者检索。

这一策略确保了数据的持久性和一致性,即使在主节点故障时,也能从ISR中选举出新的主节点无缝接替,保障服务连续性,无需担忧数据丢失或不一致问题。

Kafka网络ACK机制

分布式系统因网络通信的介入,使得消息传递的可靠性成为一大挑战。网络环境如同其本身性质所示,有时能够容忍数据包丢失,而有时则要求数据包的可靠传输并具备重传及去重机制。

最多一次(at-most once)

Kafka消费者而言,其确认(ack)消息的时机直接关乎消息传递语义的界定。若消费者在接收到消息但尚未进行处理时即刻发送确认,一旦消费者在数据处理前遭遇故障,数据处理便无法确保完成,这种情况下,消息传递体现为“最多一次”(at-most once)语义。

至少一次(at-least once)

若消费者选择在消息接收并处理完毕后再发送确认信号,尽管确保了数据被处理,但在确认发送前的任何故障都将导致消息被重传,进而产生重复处理的情形,这对应着“至少一次”(at-least once)语义。