1. kafka架构图
1.1. broker内部模块说明:
-
KafkaController,controller控制器,监听zk并指挥broker操作
-
SocketServer, 网络模块,接收和发送数据
-
KafkaApis,分发请求,类似于spring mvc
-
ReplicaManager,Partition及其replica的管理,设置leader partition等操作
-
LogManager,日志文件操作相关,比如kafka-log-retention,kafka-log-flusher,kafka-delete-logs等及创建目录,具体读取log,写log由Log代理
-
GroupCoordinator , 分组管理,消费者join及unjoin管理group
-
KafkaHealthcheck ,通过注册监听器向zk注册自己的消息
-
KafkaScheduler , 实际上就是ScheduledThreadPoolExecutor
-
AdminManager, 向zk发送创建topic、删除topic、穿创建partition,更新和查询配置,给kafkaapis模块使用
-
TransactionCoordinator,事务管理
-
DynamicConfigManager,配置管理
-
Authorizer,身份和权限认证
1.2. kafka的目录结构
文件说明:
-
cleaner-offset-checkpoint: 记录全部partition的cleaned offset,cleaned offset用于计算非活跃segment的dirtyRatio(log head和log tail的比例),dirtyRatio在日志压缩的模块会被使用
-
recovery-point-offset-checkpoint: 记录每个partition最新刷盘的message的offset
-
replication-offset-checkpoint: 记录每个partition最后一条被成功备份到副本的消息的offset
-
log-start-offset-checkpoint: 记录每个partition的第一条(earliest)信息的offset
-
meta.properties: 记录cluster或者broker的元数据如clusterId and brokerId.
-
log日志:
- Kafka 分区目录由 topic名称+partition序号 组成
- 分区目录下是日志数据,由segment组成,segment的名称当前segment第一条数据的offset,固定长度20位,不足补0
1.3. zookeeper中kafka的数据结构
2. kafka设计
2.1.设计目标
-
高吞吐
-
低延迟
-
处理大量数据积压,支持来自离线系统的定期数据加载(持久化 、成本、读写性能优化、数据压缩)
-
对数据分区、分布式、实时处理,且能够基于数据派生新数据(激发分区、和消费者模型)
-
容错,在机器挂掉的情况下,数据仍然可以正确传递给其他服务(副本设计)
基于上面的目标,kafka的使用了一些特有的设计元素,比起传统的消息系统,这些设计让系统看起来更有点像数据库日志
2.2.持久化
2.2.1. kafak和文件系统
比起内存够读写,磁盘读写非常慢,既然要设计高吞吐、低延迟的系统,为什么kafka还要选择将数据存储在磁盘上而不是内存?
有几点原因:
磁盘随机读写很慢,但磁盘顺序读写速度很快,对于由6个7200转每分钟(RPM)的SATA硬盘组成的RAID-5阵列(Six 7200rpm SATA RAID-5 array)
- 顺序写入速度大约600 MBps,即每秒写入600兆字节的数据
- 随机写入速度大于100 KBps, 即每秒写入100字节数据
原因是顺序读写提供了可预测的使用模式,操作系统利用这种模式对磁盘做了重点优化,即预读和延迟写:利用这种技术操作系统提前读取数倍大块的数据,并将较小的逻辑写入组合成大块的物理写入,以实现顺序的读写操作。
提示:某些情况下,顺序的磁盘访问可能比随机的内存访问更快,下图是2009年的一个测试
deliveryimages.acm.org/10.1145/157…
自测(自己mac电脑 4C16G)
内存随机/顺序读写20MB,随机写速度115MB/s
磁盘随机/顺序写 500MB数据,磁盘随机写入速度 5-10MB/s,顺序写入速度186MB/s,大于内存随机写115MB/s
磁盘顺序读 500MB数据,顺序读速度256MB/s
磁盘随机读 500M数据,随机读速度15MB/s
- 操作系统会将所有空闲的内存用作磁盘缓存,且当内存被回收时,回收内存的操作对系统的影响极小,所有的读写都会经过这些缓存再到磁盘,操作系统的这个特性很难被关闭,即使在应用中使用了程序级别缓存,缓存中的数据还会在操作系统的page cache中进行二次缓存
代码演示:一边写入数据,一边读取数据,读取数据时,数据基本上从缓存读取,很少读磁盘
2.2.2. kafka与JVM
kafka运行在JVM之上,JVM的内存有两个特点
-
对象占用的内存很大,通常是被存储数据本身大小的的两倍甚至更多
-
随着堆内存的增加,垃圾回收会变得越来越繁琐和缓慢
基于上面的缺陷,kafka采用文件系统和pagecache存储数据,数据存储在pagecache中如同访问内存,而且数据直接存储在pagecache而不是堆内存,可以获取2倍甚至更多的存储空间,一台32G内存的机器,能够使用到的内存可达28-30G,另外还有一个好处,如果kafka重启,pagecache缓存的数据还是热数据,如果存储在堆内存中,服务重启后,需要重建内存。
另外,数据写入磁盘时,kafka会将数据直接写入到文件,但是不会flush将数据刷入磁盘,这样数据会被写入pagecache,而pagecache与磁盘的同步由操作系统完成,这里有个问题:因为没有主动flush数据到磁盘,kafka如何确保数据不丢失?
2.2.3. 恒定的索引查询时间(索引的数据结构)
传统的消息队列一般采用BTrees数据结构存储数据的元数据
BTrees
优点:
-
通用的数据结构,适合多种场景,时间复杂度是O(log N),O(log N)可认为是恒定时间
缺点:
-
操作成本很高,在相同的内存下,数据增长一倍,性能下降两倍甚至更多
-
实现复杂度高
队列
kafka采用队列存储数据和元数据
优点
- 写入数据时,直接将数据追加到队列末尾,所以写数据的时间复杂度是O(1),而且读和写两个操作不用相互加锁
- 读元数据的时间复杂度时间复杂度是O(log N),但是因为索引序号是递增,可以采用二分法对数据进行查询,且索引数据可以映射到内存中,读取速度也极快
- 索引实现简单
- kafka利用上面的这些优点,可以在一台服务器上使用多个1+TB SATA 硬盘,对于超大的读写数据场景下,可以到达可接受的性能表现,利用1/3的价格实现3倍的存储容量
2.2.4. 传输效率提升
数据传输和数据读写存在两个性能瓶颈
- 太多的小 I/O 操作
- 太频繁字节码复制
developer.ibm.com/articles/j-…
-
操作系统将数据从磁盘读入内核空间的页面缓存
-
应用程序将数据从内核空间读入用户空间缓冲区
-
应用程序将数据写回到内核空间的套接字缓冲区
-
操作系统将数据从套接字缓冲区复制到 NIC 缓冲区,然后通过网络发送
涉及的上下文切换4次
kafka的优化方案:
-
批量 I/O 操作
-
使用0拷贝技术
使用transferTo传输数据
上下文切换2次
系统还会优化,减少socket buffer赋值,直接将文件数据写到网卡
2.2.5. 端到端数据压缩
在某些场景下,CPU和磁盘并不一定是瓶颈,而是网络带宽,因此kafka支持从生产者到服务端、服务端到消费者的 全链路数据压缩,kafka支持 GZIP, Snappy, LZ4 等压缩方式
优化:对单条数据进行压缩效果不明显,通常kafka对批量数据进行压缩后再传输,批量压缩才是关键,压缩能达到最大
2.3. 生产者
生产者的2个关键设计
2.3.1. Load balancing
-
随机选择partition
-
轮训partition
-
按照key hash
-
自定义路由
2.3.2. Asynchronous send
生产者会在本地内存中积累数据,然后一次发送积累的批量数据,以此提升传输效率。
缓存多少批量数据可以通过数据大小(字节)和延迟时间决定(比如64k or 10 ms),具体配置多少要平衡吞吐量和延迟的需求
2.4. 消费者
消费者设计
2.4.1. Push vs. pull
服务端推送消息给消费者(Push)还是消费者从服务端拉取信息(Pull),两种方式各有优缺点,应该如何选择?
2.4.1.1. Push
Push的优点:
时效性极高,信息可以及时推送给消费者
Push的缺点:
-
由于服务端控制信息的发送速率,主动推送很难应对多样化的消费者,如果消费者跟不上生产者的速度,消费者可能会超负荷运行,本质上类似于拒绝服务攻击
-
虽然可以通过协议约定让服务器感知消费者的负载压力,然后降低传输率,但实现比较麻烦
2.4.1.2 Pull
Kafka偏向于Pull设计, 作为对比,看看Pull的优缺点
Pull的优点:
-
即使消费者落后于生产者的生产速度,但是在条件允许的情况下,消费者可以最终跟上生产者的速度
-
消费者可以更好处的处理批量数据读取,基于Push的系统无论是选择立即发送数据还是积累一定数据,都有弊端,因为服务端不知道下游是否能处理推送的数据
Pull的缺点:
- 如果服务端无数据,会导致消费者不停地轮训服务器,导致消费者处于空转的状态
kafka如何解决空转的问题?
kafka在请求参数中设置了等待时长参数,如果服务端无数据,则服务端会挂起当前请求(通过时间轮实现延迟),直到生产者有数据写入或者等待时长到期。
2.4.2. 消费者position管理
kafka需要追踪哪些数据被消费了,追踪哪些数据被消费的信息可以在服务端进行,也可在客户端进行,应该如何选择?
2.4.2.1. 服务端管理
在服务端追踪的优点:
-
当服务端数据发送给消费者后,服务端知道数据已经被消费,于是可以立即删除数据,服务端可以保证数据是最小的,节省存储空间
在服务端追踪的缺点:
-
信息丢失或者重复消费
- 信息丢失: 如果服务端将数据发送给消费者后,就认为消息已经送达(consumed状态),当消费者尚未来得及处理消息就挂掉了,则会造成消息丢失
- 重复消费:如果服务端将数据发送给消费者后,将信息记录为send状态,消费者处理完后再发送ack给服务端,如果消费者处理信息后还未发送ack就挂掉了,则消息可能会被重复消费
-
性能问题
服务端需要记录每一条信息的多种状态,比如send/consumed状态,而且需要处理消费者不发送ack时,消息应该如何处理的棘手问题
2.4.2.2. 客户端管理
kafka选择在客户端追踪哪些数据被消费的元数据,我们看看在客户端的优缺点:
优点:
- 实现简单、成本小
kafka的每个topic可以分成多个partition,但是每个partition只会被一个消费者订阅(一个分组下的消费者),因此可以在消费者中跟踪订阅的partition的position,而且只要一个数字,成本非常小。如果一个partition会被多个消费者订阅(一个分组下的多个消费者),则多个消费者需要协调谁消费哪些数据,在客户端则难以实现
-
消费者可以回溯到之前的位置,重新消费数据,这个特性在某些场景有用,比如代码出了bug,需要重新消费
2.5. 消息传递的语义(传递规则和行为)
- At most once, 最多一次 — 消息可能会丢失,但绝不会重新传递
生产者
-
At least once, 至少一次 — 消息绝不会丢失,但可能会重新传递
-
Exactly once, 恰好一次 — 这是人们真正想要的,每条消息只传递一次
生产者和消费者都存在这些语义
2.5.1. 对于生产者:
- At least once
如果信息发出去后,生产者未收到信息已经发送成功的响应信息,则生产者可能重新发送信息,这就是At least once,从0.11.0.0版本开始,kafka支持幂等传递,重复发送不会产生重复数据,另外这个版本还支持了在多个topic之前实现事务发送,数据要么成功,要么失败。
- At most once
如果生产者禁用retries,则最多只发送一次,如果生产者与服务器中间发送网络异常,则信息可能丢失
2.5.2. 对于消费者
- At most once
消费者读取信息后,随即提交position,最后再处理数据,则可能出现position保存成功但是处理数据时消费者挂了,导致数据处理失败,如果另外一个消费者接着处理,则只会处理position之后的数据,已经处理失败的数据则不会处理,这就是At most once,最多处理一次
- At least once
消费者读取信息后,随即处理数据,最后提交position,则可能出现数据已经处理成功但是保存position时消费者挂了,如果另外一个消费者接着处理,则会重复消费已经处理成功的数据,这就是At least once ,至少处理一次
- Exactly once
场景1(kafka系统之内): 如果消费者从一个topic消费数据,然后处理数据,最后将数据写入另外一个topic,则可以利用kafka的事务能力,这种情况需要把消费者的position存储在一个topic中,于是position可以和处理结果(存储在另外一个topic)放在同一个事物中提交,如果事务被中断,则position恢复到原来的值,并且处理结果也不会对消费者可见,当然消费者是否可以看到数据,取决于事物隔离级别,如果是"read_uncommitted",消费者是可以看到数据的,如果是"read_committed",则消费者只能看到已经提交的数据。
场景2(kafka与外部系统):
-
两阶段提交,position和输出结果通过两阶段提交存储到外部系统,但是很多外部系统不支持两阶段提交,所以不推荐
-
将position和输出结果存储在一个事务中,要么都成功、要么都失败,当然将position存储在外部系统中会涉及与kafka系统的协调,kafka提供Kafka Connect组件来帮助实现这个功能
总结:对于Exactly once的实现,如果在kafka系统内部,kafka可以通过事务实现,如果需要与外部系统交互,kafka提供Kafka Connect帮助实现这个功能,另外如果使用Kafka Streams(kafka大数据流处理平台),Kafka Streams支持Exactly once。
最后,kafka默认配置是At least once
2.6. Replication(副本)
kafka会备份每个topic所有partition的数据,并将备份的数据均匀分布到多个服务节点上(可以针对单个topic设置副本因子),如果集群有服务挂掉,kafka会自动进行故障转移,使用副本继续提供服务。
备份的对象是partition,备份数量取决于topic的副本数量/副本因子( replication factor),副本数量包含leader,所有写操作都在leader partition进行,读操作可以在leader 或者 follower partition进行,follower的数据和数据的顺序与leader保持一致,follower同步数据其实和消费者读取数据方式一样,也是消费leader的数据,然后写入日志。当然,在任何给定时间点,leader的日志末尾可能会有尚未完成备份的少量数据。
2.6.1.1. “alive”节点 的定义:
在分布式系统中,要自动处理故障需要明确定义 alive节点 是什么? kafka系统中有一个特殊的节点叫 Controller节点,这个节点会管理集群中其他节点的注册,alive节点需要满一个条件:
-
保持心跳(active session),节点必须与Controller保持活动会话,以便定期接收元数据更新
其中保持心跳(active session)的行为在新老版本有所不同
在KRaft集群(不用zookeeper)中,主要是维护节点与Controller的心跳,心跳时间通过broker.session.timeout.ms配置,节点超时未发送心跳给Controller,则认为节点下线
在使用Zookeeper的集群中,心跳是通过节点注册在zookeeper的临时路径决定的,如果zookeeper.session.timeout.ms时间内,节点未与zookeeper发送心跳,则临时节点会被删除,于是Controller就会感知节点被删除,然后Controller将相应节点标记为下线
2.6.1.2. “in sync”节点的定义:
-
节点必须是“alive”节点
-
follower节点必须保持与leader节点同步,follower的数据不能落后太多leader节点的数据
不能落后太多的含义,如果follower在一定时间还未读到leader末尾的数据则认为落后了,时间通过replica.lag.time.max.ms配置
2.6.1.3. “ISR”定义(in sync replica):
leader节点会跟踪“in sync”的节点,处于“in sync”的节点则被认为是ISR,如果节点挂掉了或者follower节点的数据落后leader节点(不是“in sync” )但是节点并未挂掉,这两种情况,leader都会将节点从ISR中移除
ISR用来做什么?
-
可以更准确的定义消息提交,比如acks=all 或 acks=-1时:生产者等待集群中的所有in sync的副本(ISR,In-Sync Replicas)接收到确认才认为消息提交成功,当然生产者可以在latency and durability之间权衡,如果选择低延迟则可以选择不需要ISR中的副本确认,或者仅仅leader确认即可。
-
节点发生故障时,用于leader选择
2.6.2. 副本复制:Quorums, ISRs, and State Machines
Kafka 分区的核心是数据复制,数据复制是分布式数据系统中最基本的原语之一,有许多方法可以实现数据复制。最简单和快捷的方式就是选择一个leader,leader负责数据的写入顺序,只要leader还存活,follower复制leader的值即可。
数据复制算法需要确保客户端的发送的数据只要被commited,即使leader挂了,从follower中选举的新leader必须有被commited的数据。这也意意味着leader等待越多的follower ack(复制数据后对leader进行反馈),则可选择的潜在leader越多。
2.6.2.1 Quorums
Quorums(法定人数)的定义:
如果 需要ack的follower数量 和 实际的partition的副本数量 进行比较并能从中选择leader,要求这两个数的范围必须有重叠,这个follower数就是法定人数。
选择Quorums的常见做法是采用majority vote,数据提交和leader选举中通常使用majority vote算法。假如有 2f+1 个副本,如果有大于等于f+1(正好大于f)个副本接收到了数据,则可以认为数据成功提交(commited),当leader挂了后,从这f+1个副本选举一个新leader,可以确保新leader有完整的数据。所以f+1个副本可以容忍f个节点挂掉,因为f+1个副本中,至少有一个以上的节点包含完整的(所有已经提交)数据。
majority vote有一个很好特点是:
延迟(latency)取决于最快的节点,比如有3个副本,1个leader,两个follower,只要一个follower复制成功即可,而延迟则取决于最快的那个follower。
majority vote的缺点:
majority vote可能在面对多个故障时变得脆弱,因为它依赖于足够数量的成员参与投票。比如要容忍1个节点失败,则需要2*1+1=3个节点,要容忍2个节点失败,则需要5个节点,也意味着需要5次数据写入,和5倍的存储容量而吞吐量却只有1/5,对于大容量数据系统来说这不是很适用。
所以quorum 算法一般适用于共享集群配置如zookeeper系统。HDFS namenode的高可用性特性建立也是建立在majority-vote-based journal,但是HDFS的数据存储没有使用这种算法。
很多算法如ZooKeeper's Zab, Raft和Viewstamped Replication 都属于majority vote算法的变种。
2.6.2.2. ISRs
kafka的选择Quorums的方式不一样,不是采用majority vote,而是动态维护一个 in sync状态的副本集,也就是ISR。生产者发送数据后,只有数据被所有 in sync的副本接受了,才会认为信息被提交成功(committed),通过 ISR 模型和 f+1 个副本,Kafka 主题可以容忍 f 个副本故障而不会丢失已提交的消息。
ISR与Majority vote的对比:
在认为信息被认为committed之前, ISR和Majority vote要等待ack的副本数是一样的,例如,为了承受一次故障,Majority vote需要三个副本和其中一个副本ack,而 ISR 方法需要两个副本和其中一个副本ack。如果要承受两次故障,Majority vote需要2*2+1=5个副本和其中2个副本ack(一个leader,2个follower ack),而ISR需要3个副本和其中2个副本ack(一个leader,2个follower ack)
ISR的优点:
-
kafka可以通过客户端参数来决定是否要阻塞以等待所有in sync副本同步完成还是无需副本ack来优化延迟(对比Majority vote的优点),以此提高系统吞吐量,并且由于所需的副本更少,更节省存储空间
-
kafka的这种设计 不要求崩溃的节点在所有数据完好无损的情况下才能恢复。而Majority vote对磁盘的稳定性和数据完整性(比如频繁刷盘以持久化数据)要求更高。ISR 的协议确保崩溃的节点在重新加入ISR队列之前,节点必须完成与Leader数据的完成同步,即使在崩溃时丢失了未刷新的数据。
与ISRs算法类似的是来自微软的 PacificA 算法
2.6.3. Unclean leader election(所有副本都挂了怎么办)?
两种策略
-
等待 ISR 中的副本恢复运行,并选择恢复的副本作为领导者(希望它仍拥有所有数据)。
-
选择第一个恢复运行的副本(不一定在 ISR 中)作为领导者,这就是Unclean leader election。
这是可用性和一致性之间的简单权衡。0.11.0.0版本开始,kafka默认使用第一种策略
2.6.4. 可用性和一致性保证
当数据写入 Kafka 时,生产者可以选择等待 0、1 个或all(-1)个副本确认消息。默认情况下,当 acks=all 时,所有in sync状态的副本收到消息后才会认为信息被committed。比如有两个副本,但是其中一个副本挂掉了,另外一个副本是in sync状态,如果此时acks=all,则只要in sync状态的副本写入数据成功,就认为信息committed。这种行为虽然保证了partition的最大可用性,但对于数据一致性要求很高的应用来说并不一定是期望的行为,比如in sync写完数据后也挂了,则可能导致数据丢失,为此kafka提供了两个topic级别的配置:
-
Disable unclean leader election,如果所有的副本的都不可用了,则kafka也会不可用,直到有副本恢复并成为leader。
-
指定最小 ISR 大小 - 仅当 ISR 数量高于某个最小值时,分区才会接受写入。此设置在一致性和可用性之间提供了权衡。
2.7. 日志压缩
kafka除了提供简单的日志保留机制:固定时间段后或日志达到预定大小时丢弃旧日志数据。kafka还提供了日志压缩的保留机制,日志压缩提供了更细粒度的保留机制,这样kafka可以保存每个主键的最后一次更新记录,而不是每一次更新记录,日志压缩可确保单个topic 分区的数据日志中保留每个消息键的最后一个已知值。
压缩在后台通过定期重新复制日志的segment完成,日志清理不会阻止数据读取,并且可以限制使用不超过可配置的 I/O 吞吐量,以避免影响生产者和消费者。压缩日志的实际过程如下所示:
日志压缩要求每条信息都必须带有Key。
使用场景:
可以利用kafka存储数据的最终状态,当系统挂掉后用于状态重建、缓存重建等场景
日志压缩过程:
日志压缩由日志清理器(log cleaner)处理,它是一组后台线程,用于重新复制日志段文件,删除日志头部出现的键记录。每个线程的工作原理如下
-
选择日志头与日志尾比例最高的日志
-
为日志头中的每个键创建最后偏移量的简洁摘要信息
-
从头到尾重新复制日志,删除日志中较晚出现的键。新的干净段会立即交换到日志中,因此所需的额外磁盘空间只是一个额外的日志段(而不是日志的完整副本)
-
日志头的摘要本质上只是一个空间紧凑的哈希表。它的每个条目使用 24 个字节。因此,使用 8GB 的缓冲区,一次清洁迭代可以清理大约 366GB 的日志头(假设一条信息1k大小)。
2.8. Quote(配额:服务器资源使用额度 or 降级)
Kafka 集群能够对请求实施配额,以控制客户端使用的服务器资源,因为生产者和消费者可能会生产/消费大量数据或以极高的速率生成请求,从而垄断服务器资源,导致网络饱和,并通常会对其他客户端和broker本身造成 DOS 攻击。
2.8.1. kafka有两种类型的配额设置:
- 网络带宽配额(自 0.9 版本起)
比如10MB/s,表示每秒钟生产者/消费者最多只能发送/消费10MB的数据
- 请求速率配额,即 CPU 利用率(自 0.11 版本起)
由于kafka服务端用于处理 I/O和网络的线程数是基于机器的CPU核数,所以线程的使用时间可以认为是CPU的处理时间,比如num.io.threads + num.network.threads=10,那么总的CPU使用率的计算公式是 ((num.io.threads + num.network.threads) * 100)%= 1000%,如果配额是10%,则表示 单位时间内,一个线程只能使用10%的CPU时间。
2.8.2. 配额限制的对象是谁?
配置是针对client group,注意不是consumer group。client group是通过<user,client-id> 二元组构成的,或者单独的user group、单独的client-id group,生产者或者消费者初始化时需要设置<user、client-id>,user or client-id。
2.8.3. 如何设置配额
zookeeper有两个路径用于存储配额,分别在 /config/users和/config/clients,
/config/users 存储 User or <user, client-id>的配额
/config/clients 存储client-id的配额
配额配置的优先顺序是:
-
/config/users//clients/
-
/config/users//clients/
-
/config/users/
-
/config/users//clients/
-
/config/users//clients/
-
/config/users/
-
/config/clients/
-
/config/clients/
2.8.4. 最后
- 配额是在broker维度配置的。每个客户端都可以在受到限流之前可以利用每个broker的此配额。因为在集群维度设置配额实现起来比较难,需要考虑在所有broker之间共享配额。
- 如果客户端受到配额限流,服务端并不会直接返回错误,而是会计算客户端需要静默的时间,然后服务端会静默客户端的链接,在此期间,服务端不会处理该链接的请求,同时,服务端会给客户端返回静默时间,客户端收到静默时间后,也不能给服务端发送请求。所以被限流的请求会被客户端和服务端同时block。
有一个计算延迟时间的公式:
* Basically, if O is the observed rate and T is the target rate over a window of W, to bring O down to T,
* we need to add a delay of X to W such that O * W / (W + X) = T. (为什么是W/(W+X))而不是A/(W+X),A是指W时间窗口内累计的值,因为O = A/W, 但是到这一步时,不知道A是多少,只知道O,所以要使用W
* 转换后的公式是 A/W * W/(W + X) = T = O * W / (W + X) = T
* Solving for X, we get X = (O - T)/T * W.
-
kafka会通过多个小窗口(比如30 个窗口,每个窗口持续 1 秒计算网络带宽和CPU使用率,而不是大窗口(比如1个窗口,每个窗口30秒)检查,因为小窗口可以更快速更准的检测出问题。大窗口容易导致流量激增,随后出现长时间延迟,降低用户体验。
-
如果要启用配额,需要启用kafka的用户认证机制
例子:
给user=youradminusername的用户设置配额的命令,producer_byte_rate=2048000000表示生产者的网络带宽,单位是字节(byte)
bin/kafka-configs.sh --zookeeper localhost:2181 --alter \
--add-config 'producer_byte_rate=2048000000,consumer_byte_rate=2048000000' \
--entity-type users --entity-name youradminusername
测试CPU 配额 40%,耗时170184毫秒,约2.8364分钟
bin/kafka-configs.sh --zookeeper localhost:2181 --alter \
--add-config 'producer_byte_rate=2048000000,consumer_byte_rate=2048000000,request_percentage=40' \
--entity-type users --entity-name youradminusername
测试CPU 配额 20%,耗时365862毫秒,约6分钟