4.3-中间件之Kafka

一、初识Kafka

什么是Kafka?

Kafka是一种分布式的,基于发布 / 订阅的一个消息系统。在没有Kafka之前,系统架构是一个"蜘蛛网"模型,用户A在网站上发表了一条动态,这条数据需要被送到无数个地方:

  • 写入主数据库
  • 更新搜索索引,让其他人能搜到
  • 更新用户画像,用于推荐系统
  • 发送通知给他的粉丝
  • 生成数据报表,给运营看

这样设计数据库会被系统不停的轮询,压力巨大,此外数据容易不一致且耦合严重,要修改一个接口需要牵一发动全身。

所以Kafka的设计目标就是:

目标一:高吞吐量

  • ​含义​:每秒钟能处理海量的消息(目标是百万级/秒)。

  • ​必要性:这是 Kafka 诞生的首要原因。要作为整个公司数据的"中枢神经系统",必须能承受所有系统产生的数据洪流。

  • ​如何实现​:

    • ​顺序读写磁盘​:即使使用廉价的机械硬盘,也能获得极高的吞吐。

    • ​批量处理​:生产/消费都采用批量操作,减少网络I/O和系统调用次数。

    • ​零拷贝技术​:优化数据在内核态和用户态之间的传输路径。

目标二:可扩展性

  • ​含义​:系统容量可以通过增加普通的硬件来线性提升。

  • 必要性:业务是增长的,数据量是指数级增加的,系统必须能轻松地水平扩展。

  • ​如何实现​:

    • ​分区模型​:每个 Topic 可以被划分为多个 Partition,这些 Partition 可以分散到不同的服务器上。增加服务器就能增加整体容量。

    • ​无状态 Broker​:Kafka 的 broker(kafka集群中的一台服务器) 本身不记录消费者的状态,使得增删 broker 变得简单。

目标三:持久化与可靠性

  • ​含义​:消息一旦被写入 Kafka,就不能丢失,并且可以被多次、长时间地消费。

  • ​必要性​:Kafka 的定位不仅是消息队列,更是实时的、分布式的提交日志。数据是公司的资产,绝对不能丢。

  • ​如何实现​:

    • ​消息直接持久化到磁盘​:而不是先存内存,再刷盘,避免了断电丢失消息的风险。

    • ​多副本机制​:每个 Partition 的数据都有多个副本,分散在不同机器上,防止单点故障。

目标四:松耦合与实时性

  • ​含义​:让数据生产者无需关心谁用数据、何时用数据,同时保证数据能被实时消费。

  • ​必要性​:这是解耦系统的关键。生产方和消费方独立发展、独立伸缩,互不影响。

  • ​如何实现​

    • ​发布-订阅模型​:生产者发送消息到 Topic,多个消费者组可以独立订阅同一个 Topic。

    • ​消费者拉取模式​:消费者自己控制消费节奏,不会因为消费能力慢而拖垮生产者和 Kafka 服务本身。

    • ​消息保留策略​:数据会持久保存一段时间(可配置),允许新的消费者随时接入并消费历史数据。

二、kafka高吞吐量的实现

kafka的划分很细,即使对 TB 级以上数据也能保证常数时间复杂度的访问性能,依赖于其中的各个部分:有Topic Partition Segment索引文件 Segment数据文件 offset值

各部分的理解:

  • Kafka是一个图书馆

  • Topic是一个图书大类(如"少儿图书"类)

  • partition是这个大类下的书架(如 一个作者一个书架)

  • segment是书架的一层(关键),也是kafka文件存储的最小单位

  • 索引文件和数据文件就是书架里面存放的书,一个负责查找,一个负责记录

  • offset即书的页码,也是查找的关键。

    | --topic1-0 topic1的0号分区
    | --00000000000000000000.index segment 文件
    | --00000000000000000000.log 后缀分表表示 Segment 索引文件和数据文件。
    | --00000000000000368769.index
    | --00000000000000368769.log
    | --00000000000000737337.index
    | --00000000000000737337.log
    | --00000000000001105814.index
    | --00000000000001105814.log
    | --topic2-0
    | --topic2-1

查找流程:假设要查找页码(offset)为368772 的内容(消息)

  • 在根据查找消息的key确定他的"书架分区"partition
  • 到指定书架前,每一层的编号,用的是这一层存放的起始页码,比如第一层存放(1-10000)第二层(10001-20000)...
  • 利用二分查找定位368772 所在的层号
  • 取出对应层里面的目录(索引文件),这个目录是稀疏的,只稀疏记录了页码(offset)1从第0个字符开始读,页码(offset)3从第497个字符开始读....(而这条消息的全局页码(offset)是 368769 + 3 = 368772
  • 直接从这一层的数据文件的497字符开始读取

总结:找索引文件利用二分查找,找文件中对应的消息,利用偏移量和索引文件中的稀疏索引。

Kafka 高性能很重要的原因:

  1. 顺序磁盘 IO 存储设计,写在log数据文件里面的消息都是顺序的(kafka将生产者发送的消息攒成一批,顺序追加到数据文件末尾),这种顺序磁盘IO快于随机读写内存。
  2. PageCache,进程准备读写磁盘前,OS会先查看内容是否读取到PageCache上,如果命中,则可以避免磁盘IO
  3. 零拷贝,从磁盘读取消息,然后原封不动地通过网络发送给消费者。这样可以减少一半的拷贝操作,避免了内核缓冲区读到用户缓冲区,然后用户缓冲区再写回到内核缓冲区 的两次拷贝操作。只需要从磁盘读出到内核缓冲区,然后直接从内核缓冲区发送到网卡。(DMA负责)

三、kafka可扩展性的实现

Kafka一个很重要的特性就是,只需写入一次消息,可以支持任意多的应用读取这个消息。一个应用如果看作一个消费组,然后消费组里对应多个消费者,每一个消费者可以与一个Topic里面的分区对应。如果该应用消费能力不足,那么可以考虑在这个消费组里增加消费者。如果应用需要读取全量消息,那么就为该应用设置一个消费组。

消费者可以1:n个分区,但是如果消费者数量>分区数量,多余的消费者会空闲,因为一个分区不支持同一个消费组里的多个消费者消费,所以对应的Topic里面的分区应该多一些。

zookeeper的作用:注册服务发现,标识各broker的ip。

四、kafka可靠性保证

1.保证消息不丢失:生产者确认 + 服务端多副本冗余 + 消费者手动提交

  • 生产者设置 acks 参数:acks=all:需分区的 leader 以及 follower的确认。
    acks=0,则不等broker返回,提供了最低延迟,但是最不安全。
    acks=1,等待分区的leader落盘成功后返回ACK
  • broker采用多副本机制,消费者什么时候能读取消息?LEO和HW

HW标识了消费者可以读取的消息的位置,也就是主副分区中,更新消息最慢的分区的位置

LEO 标记的是主分区的最新消息的位置

  • 消费者在消费完毕后,再提交偏移量offset
    如果是自动提交offset,比如1s一次,可能会导致丢失数据,因为可能1s还没有处理完数据
    如果是手动提交offset,丢数据情况对于消费者一般不存在,但是无法避免重复消费(拉取)的情况,即消费者消费完但是没有提交offset就宕机了,需要重复消费。最大限度避免重复消费的办法就是 同步提交消息,这样最多重复消费一条消息。

五、kafka的策略

生产者消息的分区分配策略:

  • 如果消息有指明分区号,之前归入对应分区。
  • 如果没有指明分区号,但是消息带有对应的key值,Hash(key) % 分区数后,放入对应分区
  • 没有指明分区也没有key,顺序轮询各个分区均匀放入。

消费者的分区分配策略:(消费组数量<分区)

  • 整除分配,分区数/消费者数为消费者分配到的分区数,但是当无法整除的时候,不能实现均匀分配
  • 轮询分配,把分区号按字典排序后,顺序轮询消费者分配。但是当各个消费者订阅的Topic不同的时候,无法实现均匀分配
  • 粘性分配,首先按轮询分配对分区进行分配,但有一个关键改进:**它严格遵循消费者的订阅信息。**而且在出现有消费者C1脱离了消费组的情况下,进行分区重定向的时候,按照轮询只把C1的分区分给其余消费者,遵循尽量少的移动。

kafka的rebalance策略

当消费组的成员发生变更,有消费者加入或者有消费者宕机,或者消费者无法在规定时间内完成消费,会触发rebalance机制。

session.timeout.ms表示消费者向broker发生心跳的超时时间,一般大于3*发送心跳的时间间隔

max.poll.interval.ms表示每两次消费的时间间隔,也就是一次消费时长,如果超过这个时间,会认为消费者死了,会进行rebalance

相关推荐
235163 小时前
【并发编程】详解volatile
java·开发语言·jvm·分布式·后端·并发编程·原理
虫师c4 小时前
分布式缓存实战:Redis集群与性能优化
redis·分布式·缓存·redis集群·高可用架构·生产环境·数据分片
WnHj7 小时前
kafka的数据消费通过flinksql 入数到Doris的报错(Connection timed out)
分布式·kafka
哥不是小萝莉11 小时前
Kafka监控工具 EFAK-AI 介绍
ai·kafka
Java战神18 小时前
Hadoop
大数据·hadoop·分布式
不会写代码的加加20 小时前
告别重构噩梦:基于 Oinone 实现单体到微服务的平滑演进
spring boot·分布式
1.01^100021 小时前
[7-01-02].第05节:环境搭建 - 基础环境
kafka
szxinmai主板定制专家21 小时前
RK3588+AI算力卡替代英伟达jetson方案,大算力,支持FPGA自定义扩展
arm开发·人工智能·分布式·fpga开发
Pota-to成长日记1 天前
Redisson 看门狗机制深度解析:分布式锁的守护者
分布式·wpf