当前位置: 首页 > news >正文

Kafka中那些巧妙的设计

一、kafka的架构

Kafka是一个分布式、多分区、基于发布/订阅模式的消息队列(Message Queue),具有可扩展和高吞吐率的特点。

在这里插入图片描述

kafka中大致包含以下部分:

  • Producer: 消息生产者,向 Kafka Broker 发消息的客户端。
  • Consumer:消息消费者,从 Kafka Broker 取消息的客户端。
  • Consumer Group:消费者组(CG),消费者组内每个消费者负责消费不同分区的数据,提高消费能力。一个分区只能由组内一个消费者消费,消费者组之间互不影响。所有的消费者都属于某个消费者组,即消费者组是逻辑上的一个订阅者。
  • Broker:一台 Kafka 机器就是一个 Broker。一个集群由多个 Broker 组成。一个 Broker 可以容纳多个 Topic。
  • Topic:可以理解为一个队列,Topic 将消息分类,生产者和消费者面向的是同一个 Topic。
  • Partition:为了实现扩展性,提高并发能力,一个非常大的 Topic 可以分布到多个 Broker (即服务器)上,一个 Topic 可以分为多个 Partition,每个 Partition 是一个 有序的队列。
  • Replica:副本,为实现备份的功能,保证集群中的某个节点发生故障时,该节点上的 Partition 数据不丢失,且 Kafka 仍然能够继续工作,Kafka 提供了副本机制,一个 Topic 的每个分区都有若干个副本,一个 Leader 和若干个 Follower。
  • Leader:每个分区多个副本的“主”副本,生产者发送数据的对象,以及消费者消费数据的对象,都是 Leader。
  • Follower:每个分区多个副本的“从”副本,实时从 Leader 中同步数据,保持和 Leader 数据的同步。Leader 发生故障时,某个 Follower 还会成为新的 Leader。
  • Offset:消费者消费的位置信息,监控数据消费到什么位置,当消费者挂掉再重新恢复的时候,可以从消费位置继续消费。
  • Zookeeper:Kafka 集群能够正常工作,需要依赖于 Zookeeper,Zookeeper 帮助 Kafka 存储和管理集群信息。

二、性能指标

在这里插入图片描述

评价一个服务的好坏可以通过看它能否满足高可用、高性能、高并发。

2.1 高性能

高性能(High Performance)指的是程序处理速度快、耗能少。与性能相关的一些指标如下:

  • 响应时间:系统对请求做出响应的时间。例如系统处理一个 HTTP 请求需要 200ms,这个 200ms 就是系统的响应时间。
  • 吞吐量:单位时间内处理的请求数量。
  • TPS:每秒响应事务数。
  • 并发用户数:同时承载能正常使用系统功能的用户数量。

高并发和高性能是紧密相关的,提高应用的性能,可以提高系统的并发能力。应用性能优化时,对于计算密集型和 I/O 密集型还是有很大差别,需要分开来考虑。

2.2 高可用

高可用性(High Availability)主要目的是为了保障「业务的连续性」,即在用户眼里,业务基本是正常对外提供服务的。

三、kafka的高可用设计

3.1 选举机制

kafka中的选举大致分为2类:控制器的选举、Leader的选举。

3.1.1 控制器选举

在Kafka集群中有多个broker,那么就有一个broker会被选举为控制器,这个控制器的主要责任包括监听Broker的变化、监听Topic变化、监听Partition变化、获取和管理Broker、Topic、Partition的信息、管理Partition的主从信息。同时还会负责副本的选举,当某个分区的leader副本出现故障时,由控制器负责为该分区选举新的leader副本。再比如当检测到某个分区的ISR集合发生变化时,由控制器负责通知所有broker更新其元数据信息。

前面我们有提起过Zookeeper,控制器的选举是由Zookeeper(协调框架)的节点的唯一性来做到的。控制器的选举过程如下:

  1. 第一个启动的节点会在ZooKeeper里创建一个临时节点/controller,并写入该节点的注册信息,该节点成为控制器
  2. 其他节点在陆续启动过程中,也会尝试去ZooKeeper中创建/controller节点,如果/controller已存在则会报错,利用ZooKeeper的节点特性来保证控制器的唯一
  3. 其他节点启动后,会在控制器上注册相应的监听器,各个监听器负责监听各自代理节点的状态变化,当监听的节点状态发生变化时,会触发相应的监听函数

3.1.2 分区leader选举

Kafka是一个多分区,多副本的消息服务,那么每个分区的多副本由一个leader与多个follower构成。而leader负责进行数据读写,并且管理着整个follower中存储的数据状态。若某一时刻该分区leader挂掉了,Broker控制器就会对该分区进行重新选举案leader副本,其中leader的诞生只能从ISR列表中产生。
具体的选举规则:Kafka会在Zookeeper上针对每个Topic维护一个称为ISR副本的的集合,一旦Leader分区丢掉,从中随机挑选一个副本做新的Leader分区。如果ISR中的副本都宕机了,则:

  1. 等待ISR中的副本任何一个恢复,接着对外提供服务,需要时间等待。可以保证一致性,但可能需要很长时间
  2. 从OSR中选一个做Leader,需设置unclean.leader.election.enable=true,不需要等待,则很可能该副本并不一致。 当宕机的重新恢复时,会把之前commit的数据清空,重新从leader里pull数据。

3.2 多副本机制

在这里插入图片描述

在Kafka中,一个主题被划分为若干个分区,一个分区包含一个或多个副本,副本对应着消息存储的日志文件。副本机制就是通过对分区数据的冗余处理,即在不同的broker节点中存储多个副本,来实现Kafka的故障转移,从而提升可靠性。kafka的每个分区都有一个ISR列表,用于维护所有同步的、可用的副本。其中,Leader副本必是同步副本,而对于Follower副本来说,需要满足以下条件才能被认为是同步副本:

  • 必须定时向ZooKeeper发送心跳
  • 在规定的时间内从Leader副本“低延迟”的获取的消息

如果副本不满足上面条件的话,就会从ISR列表中移除,直到满足条件才会被再次加入。replica.lag.time.max.ms 这个参数值表示Follower副本能够落后Leader副本的最长时间间隔,当前默认值为10s,即只要一个Follower副本落后Leader副本的时间不连续超过10s, kafka就认为两者是同步的。

3.3 ACK确认机制

Kafka的Producer有三种ack机制,参数值有0、1 和 -1

  • acks = 0: 相当于异步操作,Producer 不需要Leader给予回复,发送完就认为成功,继续发送下一条消息。这个机制下延迟最低,但是持久性可靠性也最差,当服务器发生故障时,很可能发生数据丢失。
  • acks = 1: Kafka 默认的设置。表示 Producer 要 Leader 确认已成功接收数据才发送下一条消息。不过如果Leader宕机且Follower 尚未复制这部分数据的情况下,数据就会丢失。这个机制提供了比较好的持久性和较低的延迟性。
  • acks = -1: Leader 接收到消息之后,还必须要求ISR列表里的那些Follower都确认消息已同步,Producer 才发送下一条消息。此机制持久性可靠性最好,但延时性最差。

四、kafka的高性能设计

Reactor多路复用

Kafka SocketServer 是基于Java NIO 开发的,采用了 Reactor 的模式,包含三种角色:Acceptor;Processor;Handler。Kafka Reactor包含一个Acceptor负责接收客户端请求,N个Processor线程负责读写数据(即即为每个 Connection 创建出一个 Processor 去单独处理,每个Processor中均引用独立的Selector),M个Handler来处理业务逻辑。在Acceptor和Processor,Processor和Handler之间都有队列来缓冲请求。

页缓存技术

操作系统本身有一层缓存叫做页缓存(Page Cache),是操作系统自己管理的内存缓存。页缓存是位于内存和文件之间的缓冲区,它实际上也是一块内存区域,所有的文件IO(包括网络文件)都是直接和页缓存交互,操作系统通过一系列的数据结构,比如inode, address_space, struct page,实现将一个文件映射到页的级别,这些具体数据结构及之间的关系我们暂且不讨论,只需知道页缓存的存在以及它在文件IO中扮演着重要角色,很大一部分程度上,文件读写的优化就是对页缓存使用的优化。

Kafka 在写入磁盘文件的时候,可以直接写入到页缓存里,由操作系统负责将页缓存里的数据刷入到磁盘文件中,这样消息写入就变成了写内存而不是写磁盘,大大提高了kafka写的性能。

零拷贝技术

在消费的时候kafka从磁盘文件上读取数据然后发送给下游的消费者,其数据流转为:
磁盘 -> os cache -> 应用进程缓存 -> socket缓存 -> 网卡 -> 消费者

可以看出来,从os cache 拷贝数据到应用进程缓存, 接着从应用进程缓存拷贝到操作系统的socket缓存这两步是没必要的,期间发生了好几次上下文切换,比较消耗性能。kafka为了解决这个问题,在读取数据的时候引入了零拷贝技术,即让操作系统的 os cache 中的数据直接发送到网卡后传出给下游的消费者,中间跳过了两次拷贝数据的步骤,减少了上下文的切换。其中,Socket缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到Socket缓存。

kafka主要使用到了mmap和sendfile的方式实现了零拷贝。

在这里插入图片描述

压缩传输

压缩有助于提高吞吐量,降低延迟并提高磁盘利用率。在 Kafka 中, 压缩可能会发生在两个地方: 生产者端和Broker端, 一句话总结下压缩和解压缩, 即 Producer 端压缩, Broker 端保持, Consumer 端解压缩。

Producer、Broker、Consumer 要使用相同的压缩算法, 在 Producer 向 Broker 写入数据, Consumer 向 Broker 读取数据的时候可以不用解压缩, 只需要在最终 Consumer 到消息的时候才进行解压缩, 这样可以节省大量的网络和磁盘开销。

数据顺序写入

kafka写入数据的时候,会将数据追加到文件的末尾,而不是在文件的随机位置。追加到文件末尾的写法可以大大提升数据写入磁盘的速度。

批处理设计

kafka在0.8版本之后, 进行了简单的改进, 性能得到了指数级上升,即来了一条消息后不会立马发送出去, 而是先写入到一个缓存(RecordAccumulator)队列中,封装成一个个批次(RecordBatch)。这个时候会有一个sender线程会将多个批次封装成一个请求(Request), 然后进行发送, 这样会减少很多请求,提高吞吐量。

内存池设计

Kafka是一个分布式的消息队列系统,它通过内存池(Memory Pool)来管理内存,提高内存的利用率和系统的性能。Kafka的内存池设计如下:

  1. 内存池的基本单位是chunk,chunk是一个连续的内存块。
  2. 内存池中维护了一个chunk列表,每个chunk都有一个状态(free、allocated、deallocated),表示该chunk当前的使用状态。
  3. 当Kafka需要分配内存时,会先在chunk列表中查找一个状态为free的chunk,如果找到了就将其分配出去。
  4. 如果没有找到状态为free的chunk,Kafka会尝试从操作系统申请一定数量的内存,并将其分成多个chunk,加入chunk列表中,并将其中一个chunk分配出去。
  5. 当chunk被释放时,它的状态会变成deallocated,但是并不会立即释放内存,而是等到内存池中的chunk数量超过一定阈值时才会进行一次批量内存释放。
  6. 这种设计可以避免频繁的内存分配和释放操作,提高内存利用率和系统性能。同时,由于chunk是固定大小的,可以减少内存碎片的产生,提高内存分配的效率。

相关文章:

Kafka中那些巧妙的设计

一、kafka的架构 Kafka是一个分布式、多分区、基于发布/订阅模式的消息队列(Message Queue),具有可扩展和高吞吐率的特点。 kafka中大致包含以下部分: Producer: 消息生产者,向 Kafka Broker 发消息的客户…...

《JavaEE》进程和线程的区别和联系

👑作者主页:Java冰激凌 📖专栏链接:JavaEE 目录 进程是什么? 线程是什么? 进程和线程之间的联系~ ps1:假设我们当前的大兴国际机场有一条登机口可以登入飞机 ps2:我们为…...

Matlab生成sinc信号

Matlab生成sinc信号 在Matlab中生成sinc信号非常容易。首先,我们需要了解什么是sinc波形。 sinc波形是一种理想的信号,它在时域上是一个宽度为无穷的矩形函数,而在频域上则是一个平的频谱。它的公式为: sinc⁡(x)sin⁡(πx)πx\…...

进程与线程区别与联系

进程与线程的区别与联系线程线程介绍为什么要有线程呢?线程与进程的区别于联系(重点)线程 线程介绍 我们知道进程就是运行起来的程序, 那线程又是什么呢? 一个线程就是一个 “执行流”. 每个线程之间都可以按照顺序执行自己的代码. 多个线程之间 “同时” 执行着多份代码. …...

使用vbscript.regexp实现VBA代码格式化

Office自带的VBE在编辑代码时,没有自动完成代码缩进的功能,而我们在网上找到的VBA代码,经常没有实现良好的自动缩进,复制到VBE后,可读性较差。本文介绍的宏,通过使用vbscript.regexp对象,利用正…...

选择结构习题:百分值转换成其相应的等级

Description 编一程序,输入一个百分制的成绩(整数类型),按要求输出相应的字符串信息,对应关系为:     excellent 90-100     good 80-89     middle 70-79     pass 60-69 fail 60以下或100以上 Input 输入仅一行&…...

c# 源生成器

本文概述了 .NET Compiler Platform(“Roslyn”)SDK 附带的源生成器。 通过源生成器,C# 开发人员可以在编译用户代码时检查用户代码。 生成器可以动态创建新的 C# 源文件,这些文件将添加到用户的编译中。 这样,代码可以…...

[N1CTF 2018]eating_cms1

一个cms,先打开环境试了一下弱口令,无效,再试一下万能密码,告诉我有waf,先不想怎么绕过,直接开扫(信息收集)访问register.php注册一个账号进行登录上面的链接尝试用php读文件http://…...

数据结构与算法基础(王卓)(15):KMP算法详解(含速成套路和详细思路剖析)

如果时间不够,急(忙)着应付考试没心思看,直接参考(照抄)如下套路: PART 1:关于next [ j ] PPT:P30 根据书上以及视频上给出的思路(提醒)&#x…...

【互联网架构】聊一聊所谓的“跨语言、跨平台“

文章目录序跨语言跨平台【饭后杂谈】为什么有人说Java的跨平台很鸡肋?序 很多技术都具有跨语言、跨平台的特点 比如JSON是跨语言的、Java是跨平台的、UniAPP、Electron是跨平台的 跨语言和跨平台,是比较重要的一个特性。这些特性经常能够决定开发者是否…...

1.JVM常识之 类加载器

1.jvm组成 JVM组成: 1.类加载器 2.运行时数据区 3.执行引擎 4.本地库接口 各组件的作用: 首先通过类加载器(ClassLoader)会把 Java 代码转换成字节码,运行时数据区(Runtime Data Area)再把字节码…...

一天搞定《AI工程师的PySide2 PyQt5实战开发手册》

PySide2/PySide6、PyQt5/PyQt6:都是基于Qt 的Python库,可以形象地这样说,PySide2 是Qt的 亲儿子(Qt官方开发的) , PyQt5 是Qt还没有亲儿子之前的收的 义子 (Riverbank Computing这个公司开发的,有商业版权限…...

身份推理桌游

目录 杀人游戏(天黑请闭眼) (1)入门版 (2)标准版 (3)延伸版——百度百科 (3.1)引入医生和秘密警察 (3.2)引入狙击手、森林老人和…...

[LeetCode周赛复盘] 第 99 场双周赛20230304

[LeetCode周赛复盘] 第 99 场双周赛20230304 一、本周周赛总结二、 [Easy] 2578. 最小和分割1. 题目描述2. 思路分析3. 代码实现三、[Medium] 2579. 统计染色格子数1. 题目描述2. 思路分析3. 代码实现四、[Medium] 2580. 统计将重叠区间合并成组的方案数1. 题目描述2. 思路分析…...

Parcel Bundle漏洞学习

Bundle的序列化细节看上去还是有些复杂的,在之前已经讨论过,一般我们使用Parcel的时候,都是严格的write和read相对应。一些疏漏,不对应,竟然就可以成为漏洞,https://xz.aliyun.com/t/2364 里介绍了Bundle漏…...

RTP载荷H264(实战细节)

RTP包由两部分组成,RTP头和RTP载荷: RTP头 RTP头的 结构如下: 代码结构: typedef struct RtpHdr {uint8_t cc : 4, // CSRC countx : 1, // header extendp : 1, // padding flagversion : 2; // versionuint8_t …...

软考高级信息系统项目管理师系列之四十三:信息系统安全管理

软考高级信息系统项目管理师系列之四十三:信息系统安全管理 一、信息系统安全管理内容二、信息安全策略1.信息系统安全策略的概念与内容2.信息系统安全等级保护的概念三、信息安全系统1.信息安全系统三维空间2.信息安全系统三种架构体系四、PKI公开密钥基础设施1.PKI总体架构2…...

并发编程之AtomicUnsafe

目录 原子操作 定义 术语 处理器如何实现原子操作 处理器自动保证基本内存操作的原子性 使用总线锁保证原子性 使用缓存锁保证原子性 Java当中如何实现原子操作 Atomic 定义 原子更新基本类型类 原子更新数组类 原子更新引用类型 原子更新字段类 Unsafe应用解析…...

GDB调试快速入门

什么是GDB: GDB - - - (GNU symbolic debugger)是Linux平台下最常用的一款程序调试器。 自己的Linux是否安装GDB? 一般来说,使用Ubuntu的话,系统就会自带的有GDB调试器的 命令窗口输入如下命令可以查看是否安装了gdb: gdb -v …...

Vim一次复制,多次粘贴

我们平常在使用Vim时候,通过viwy或者yy等复制操作之后,p操作粘贴的时候,只能粘贴一次,想要粘贴多次怎么办? 解决方案:在使用p的是时候使用"0p,这样就能无限制的一直粘贴了。 可是&#xff…...

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...

<6>-MySQL表的增删查改

目录 一,create(创建表) 二,retrieve(查询表) 1,select列 2,where条件 三,update(更新表) 四,delete(删除表&#xf…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...

visual studio 2022更改主题为深色

visual studio 2022更改主题为深色 点击visual studio 上方的 工具-> 选项 在选项窗口中,选择 环境 -> 常规 ,将其中的颜色主题改成深色 点击确定,更改完成...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级

在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...

网站指纹识别

网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...

OD 算法题 B卷【正整数到Excel编号之间的转换】

文章目录 正整数到Excel编号之间的转换 正整数到Excel编号之间的转换 excel的列编号是这样的:a b c … z aa ab ac… az ba bb bc…yz za zb zc …zz aaa aab aac…; 分别代表以下的编号1 2 3 … 26 27 28 29… 52 53 54 55… 676 677 678 679 … 702 703 704 705;…...

ubuntu22.04 安装docker 和docker-compose

首先你要确保没有docker环境或者使用命令删掉docker sudo apt-get remove docker docker-engine docker.io containerd runc安装docker 更新软件环境 sudo apt update sudo apt upgrade下载docker依赖和GPG 密钥 # 依赖 apt-get install ca-certificates curl gnupg lsb-rel…...

[特殊字符] 手撸 Redis 互斥锁那些坑

📖 手撸 Redis 互斥锁那些坑 最近搞业务遇到高并发下同一个 key 的互斥操作,想实现分布式环境下的互斥锁。于是私下顺手手撸了个基于 Redis 的简单互斥锁,也顺便跟 Redisson 的 RLock 机制对比了下,记录一波,别踩我踩过…...