Kafka实战速记:核心原理、高频命令与线上故障排查指南
最近在带一个刚接触消息中间件的同学,Kafka相关的问题翻来覆去地问:“生产消费命令启动一次会一直运行吗?”“消息延迟高怎么查?”“OOM了怎么办?”“topic里的数据怎么一条条看?”我干脆把这几年倒腾Kafka沉淀下来的东西整理成一份速记,从Kafka的核心原理、安装部署、生产消费命令,到消息延迟、OOM、数据重复这些线上高频场景,一次性理清楚。
这份速记不端着教科书的架子,就是实际用Kafka时哪些点最重要、哪些命令最常用、哪些坑最容易踩。不管你是刚开始学Kafka,还是在准备Kafka面试题,或者是被线上消息堆积折磨得头大的开发者、运维,里面应该都有你用得上的东西。
1. Kafka解决的三个问题,以及它凭什么快
很多人学Kafka上来就看架构图,图看得懂,但心里没底,遇到问题还是不知道从哪下手。我先说它到底解决了什么问题,再一个个概念串起来,最后讲性能的核心机制。
1.1 削峰、解耦、异步:消息队列的三角关系
消息队列存在的意义,翻来覆去就是三件事:削峰填谷、系统解耦、异步处理。
削峰填谷最好理解。做个电商活动,流量突然冲到每秒几万次请求,订单后端服务如果直接扛这个量,数据库分分钟被打爆。把请求先丢到Kafka,消费者按自己的节奏去处理,流量高峰就被削平了,低谷期又可以继续消费,像水库一样。这个场景面试的时候一定要能自己讲出来,光记“削峰填谷”四个字没用,得能展开说,最好带上具体的技术指标。
系统解耦是指生产者和消费者之间不需要互相知道对方存在。下单服务只管把“订单创建”事件发到topic里,积分服务、短信服务、推荐系统各自订阅这个topic,各改各的。如果哪天积分服务下线了,下单服务完全不受影响,消息还在Kafka里躺着,等积分服务恢复后接着消费。没有消息队列的时候,下单服务可能得硬编码调用所有下游系统的接口,新增下游要改代码,下线下游也要改代码,耦合得死死的。改成Kafka之后,下游系统的增减对上游完全透明。
异步处理更直白。用户下单后,如果同步等待短信、积分、风控各个系统的响应,接口响应时间可能从200毫秒飙到2秒。改成异步,下单服务把消息发出去立刻返回,其他服务慢慢处理,用户体验和吞吐量都上来了。
理解了这三件事,再去看Kafka官方定义里的“分布式流处理平台”这句话,就不会觉得它只是在讲技术空壳,而是用分布式的存储和计算能力去支撑这三件事。
1.2 核心概念:用“图书馆”把名词串起来
Kafka里的核心概念其实不多,但每个都是高频考点。我用一个朴素的比喻帮你把它们串起来,这个比喻在跟同事讲原理时特别管用。
Topic是消息的分类,相当于图书馆里的书架。你可以建一个orders书架,一个logs书架,不同业务写不同的书架。Producer是往书架里放书的人,Consumer是从书架里拿书读的人。
Partition是topic的分区,相当于把一本大书拆成多册,放在不同书架上。为什么要拆?为了并行。一个topic如果只能一个消费者读,吞吐上限就锁死了。拆成多个分区后,多个消费者可以各读各的分区。这里要记住一个关键约束:每个分区在同一时刻只能被一个消费者读,所以分区数限制了消费者的并行上限。
Offset是偏移量,相当于书签记录读到第几页。消费者每读完一条消息,书签往前挪一格,下次接着读。如果消费者挂了,重新启动后从书签位置继续读,不会从头再读一遍。
Broker是Kafka服务节点,相当于图书馆的各个分馆,多个Broker组成集群。Producer和Consumer实际上都是和Broker打交道。
Consumer Group(消费组)是最容易绕晕的概念。同一个group里的消费者共同消费一个topic,每条消息只会被group里的一个消费者处理;不同group之间的消费进度互不干扰。打个比方,一个topic里的订单消息,“订单处理组”把每条消息都消费一遍,“数据分析组”也把每条消息都消费一遍,两边各自维护自己的书签,互不影响。但“订单处理组”内部如果有3个消费者,那每条消息只会被其中一个处理。这个区别面试官特别喜欢问,我后面还会再讲。
1.3 分区和副本:吞吐量和可靠性的底层逻辑
分区和副本是理解Kafka性能和可靠性的分水岭,也是面试中拉开差距的地方。
先看吞吐量为什么高。Kafka的消息是追加写入日志文件,磁盘顺序写比随机写快几个数量级,这是高性能的基础。再加上操作系统页缓存机制,写入操作很多时候直接落在内存里就返回了,消费者读的时候如果命中页缓存,根本不需要走磁盘。还有一个零拷贝技术,消息在网络传输时避免了内核态和用户态之间多次数据拷贝,省掉了大量CPU开销。这几个机制叠加,单Broker也能支撑很高的吞吐。
再看副本机制。每个分区可以有多个副本,副本分为Leader和Follower。生产者和消费者只跟Leader交互,Follower异步拉取Leader的数据保持同步。Leader挂了,ISR集合里的Follower有机会被选为新的Leader。ISR是“同步中副本集合”,这里记住一点:如果Follower落后太多,比如长时间没拉数据,会被踢出ISR,只有追上才能重新加入。
副本数决定了Broker挂掉时数据是否还能找回,也引出了生产端最核心的参数acks。acks=0,发送即返回,不管Broker是否收到,延迟最低但数据最容易丢;acks=1,Leader写入成功即返回,但Leader挂掉时Follower可能还没同步;acks=all或-1,所有ISR副本都写入成功才返回,最可靠但延迟最高。具体选哪个,看业务对数据丢失的容忍度。
2. 安装部署:单机、Docker、集群的实操记录
环境搭不起来,后面全是纸上谈兵。这一节把单机、Docker、集群三种常用部署方式的要点和坑都过一遍。
2.1 单机版:server.properties里几项必改
不少新手照网上的教程下载Kafka压缩包,解压后直接启动,结果各种报错。问题多半出在配置文件没改对。
先强调一下版本选择的背景。现在Kafka新版本(3.x以后)已经支持KRaft模式,可以不依赖Zookeeper。但大量存量环境还是Zookeeper模式,而且很多教程也没更新,所以我以Zookeeper模式讲主路线。如果你用的是最新版,可以切换到KRaft模式,配置更简单,但元数据存储和Controller的概念要自己补齐。
单机版server.properties里几项必改的配置,我列个表:
| 配置项 | 含义 | 本地建议值 |
|---|---|---|
| broker.id | Broker唯一标识 | 0 |
| listeners | 服务监听地址 | PLAINTEXT://localhost:9092 |
| advertised.listeners | 对外通告的地址(重点) | 跟listeners保持一致 |
| log.dirs | 日志存储目录 | 改成独立的磁盘路径,别放系统盘 |
| zookeeper.connect | ZK地址 | localhost:2181 |
advertised.listeners是新手踩坑重灾区。客户端连接的是advertised.listeners,不是listeners,两者含义不同。listeners是Broker进程真正监听和绑定的地址,advertised.listeners是Broker告诉客户端“你可以用这个地址来连我”的地址。如果你这台机器有多块网卡,或者部署在Docker里,这里配置不对,客户端会拿到错误地址然后连接失败。本地单机的话,两者保持一致就好。
启动命令Linux和Windows不一样。Linux下是:
Windows下注意,脚本在bin\windows目录里,命令是:
很多人把脚本路径和配置文件路径写颠倒。注意是先脚本后配置文件,像热词里那种“kafka-server-start.bat d:/rk/zy/kafka/kafka_2.13-3.0.0/config/server.properties”的写法就是正确的范式,脚本后面跟config文件绝对路径。路径里尽量不要有中文和空格,Windows下盘符路径一般没问题,但有些老版本脚本对带空格路径处理不好。
启动时看到日志里出现“started (kafka.server.KafkaServer)”就说明成功了。启动失败的话,优先看logs/server.log,里面记录的错误比控制台输出全得多。我看过太多人在控制台刷日志,刷不到关键信息就慌了,其实server.log里写得明明白白。
2.2 Windows Docker安装Kafka:内外地址必须对齐
在Windows上用Docker跑Kafka非常常见,但坑也不少。最常见的问题是:容器明明起来了,宿主机上却连不上9092端口。
问题的根源是容器内部的Broker对自身地址的认知,和宿主机客户端对地址的预期不一致。Docker容器内,Broker如果只配置了容器内的监听地址,启动后它会把容器内网IP通告给客户端,客户端拿着这个IP去访问,当然访问不到宿主机。
用docker-compose的方式,给一个能跑通的参考配置。这里用KRaft模式,不依赖Zookeeper,适合本地快速起:
几个细节必须说清楚。
第一,KAFKA_CFG_ADVERTISED_LISTENERS=PLAINTEXT://localhost:9092是宿主机客户端能连上的关键。你如果把它改成容器内网IP或者Kafka容器名,宿主机上的命令行工具和Java客户端就全部连不上了。这不是玄学,就是因为客户端拿到的通告地址不对。
第二,Windows下Docker Desktop基于WSL2,默认内存有限。Kafka是JVM进程,如果WSL2分到的内存不够,Kafka可能频繁GC甚至OOM。建议在Docker Desktop的Settings -> Resources里给WSL2至少4G内存,同时预留足够磁盘空间,因为虚拟磁盘文件会占实际磁盘。
第三,数据持久化一定做。把/bitnami/kafka挂到volume里,不然容器一删,topic和消息全没了,本地开发数据丢失会让你怀疑人生。
启动后用docker compose up -d拉起,进容器验证:
提示:如果看到老教程里用wurstmeister/kafka镜像,注意这个镜像维护已经不太活跃,版本比较老。建议直接用bitnami/kafka或官方的apache/kafka镜像,踩坑少。
2.3 集群搭建:三件事做不对,后面全是坑
单机跑通之后,很多人想搭个真正的集群。集群的意义在于高可用和横向扩展,但搭集群比单机麻烦得多,而且很多坑是集群环境独有的。我总结一下最容易出问题的三个点。
第一,broker.id必须全局唯一。集群里每个Broker的broker.id就是它的身份证,重复的话注册元数据时会冲突,实际表现非常诡异:明明两台机器都启动成功了,消息却总是发到其中一台,或者消费的时候偏移量错乱。给每台机器提前规划好id再动手。
第二,advertised.listeners必须让集群中其他机器和客户端都能正确访问。生产环境常有双网卡、内外网并存的情况,这里最容易踩坑。通常做法是配置内网地址,让集群内部走内网通信,外部客户端按实际网络环境走网关或负载均衡。如果一个Broker的advertised.listeners配成客户端无法访问的地址,其他Broker建连失败,ISR永远凑不齐,acks=all的生产请求就会一直超时。
第三,内部topic的副本因子要提前设好。Kafka里有几个内部topic,比如__consumer_offsets、__transaction_state,它们的副本因子不会自动跟业务topic一致。如果不显式设置,在只有一台Broker的集群里,这些内部topic的副本因子就是1,一旦那台Broker挂掉,整个集群的消费组管理和事务服务就瘫了。在server.properties里加:
此外,生产环境里的Zookeeper或KRaft Controller至少要有3个节点,否则它们自身没有高可用,Kafka集群再健康也会被控制面拖垮。很多公司开发环境图省事只搭一个ZK节点,生产环境千万不要这么干。
多Broker启动没有严格的顺序要求,但习惯上先把所有Zookeeper(或Controller)启动就绪,再逐台启动Kafka Broker。启动完成后,用kafka-topics.sh --describe看看副本分布,确认每个分区的Leader和Replicas分散在不同Broker上,这是最直观的健康检查。
3. 生产和消费命令:被反复搜索的问题一次说清
命令行工具是Kafka使用频率最高的操作入口,也是面试现场容易翻车的地方。这一节把几个高频问题一次说清楚。
3.1 生产消费命令启动一次会一直运行吗
答案是:会,除非你用Ctrl+C手动终止,或者主动设置超时退出。这个问题被反复搜索,因为很多刚接触的人把Kafka的命令行工具当成了“执行一条命令就完事”的普通命令。
kafka-console-producer.sh启动后,进程进入前台阻塞状态,不断从标准输入读数据。你敲一行回车,它就发一条消息,不敲它就一直等着;它不是执行完就退出的批处理。kafka-console-consumer.sh更明显,启动后会持续订阅topic,一直监听新的消息。即使当前没有消息,进程也挂着不动。这正是消息队列“异步”特性的体现:消费者要持续在线,等着生产者随时投递消息。
所以写自动化脚本的时候,别直接执行这两个命令然后指望它自己返回。要控制退出,有几种做法。
带--max-messages参数,消费N条消息后自动退出:
用timeout命令包一层,到达指定秒数后强制杀掉:
后台执行的话,nohup加末尾的&就可以实现,注意日志重定向。
这里还得区分一个概念:你在生产环境用nohup启动kafka-server-start.sh,这个进程也会一直运行,那是正常现象——Broker本来就是常驻服务进程。常驻进程和一次性命令的区别,面试官问到时要主动说清楚。
3.2 查看Topic数据:--from-beginning不是唯一选项
很多人查topic数据,只会用一条命令:
这个命令确实能把历史数据从头到尾打一遍,但细节上有几个坑。
第一,如果不加--from-beginning,消费者默认从latest开始消费,也就是只消费命令执行之后新产生的消息。很多新手接了个group参数想查历史数据,发现终端什么都没输出,以为配置错了,其实只是offset起点不对。
第二,如果显式指定了--consumer-property group.id=xxx,Kafka会记住这个组的消费位点。下次再用同一个group消费同一个topic,它会从上次记录的位置继续,而不是从头开始。这常是“为什么我重新执行命令却看不到数据”的真正原因。
第三,生产环境查看历史消息要谨慎。如果topic数据量很大,--from-beginning会把所有历史消息全部拉下来,瞬间产生很大网络流量和内存占用。我的习惯是先看topic的详细信息和消息量,再决定是否全量拉取。
查看topic信息,用kafka-topics.sh:
它会输出每个分区的Leader、Replicas、ISR列表,一眼看出分区数量和副本分布。
查看消费者组消费到哪了、有没有堆积,用:
输出里的LAG列就是消费积压的消息数。线上排查消息延迟时,这是第一个要执行的命令,后面我会细讲。
3.3 命令背后的面试考点
命令行工具看着简单,有经验的面试官能从中引出一堆底层问题。我自己被问过这几个,拿出来说说。
第一个是消费组和offset的关系。为什么同一个consumer group重复消费同一topic,第二次不从头开始?因为offset提交到了Kafka内部的__consumer_offsets topic里,Broker会记录每个Group在每个分区上的消费位点。这里有个经典面试点:offset的存储位置,0.9版本前在Zookeeper,0.9之后在Kafka自己内部,__consumer_offsets默认50个分区。
第二个是auto.offset.reset的语义。earliest和latest两个选项,决定了一个没有提交过offset的新消费组第一次消费时从哪里开始。earliest相当于--from-beginning,latest是只消费新消息。这个参数经常配合“新增消费者组如何消费历史数据”的场景出题。
第三个是Rebalance。同一个group里的消费者数量变化,或者订阅的topic分区数变化,都会触发分区重新分配,这个过程叫Rebalance。它保证group内多个消费者的负载均衡,但Rebalance期间整个group的消费会暂停。如果一个group里消费者频繁加入、退出,就会造成Rebalance风暴,表现为消费吞吐量骤降、延迟飙升。这个问题在线上非常常见,下一节我会细讲。
4. 生产环境三大杀手:延迟、OOM、数据重复
这一节是整篇速记里最值钱的部分,全部来自真实踩坑和排查经历。
4.1 消息延迟高的完整排查链路
消息延迟高,指的是消息从生产到被消费的时间间隔变大。这个问题在Kafka运维里几乎天天遇到。先记住一条原则:不要上来就调参数,先确定瓶颈在哪个环节。整个链路是Producer -> Broker -> Consumer,延迟可能在任何一段。
排查的起点是看消费积压的量化数据。用命令看每个消费者组的LAG:
LAG很大,说明消费者消费速度跟不上生产速度,问题大概率在消费端。LAG为0但消息延迟依然高,说明问题在生产端或者Broker端。
消费端的延迟,最常见的原因有三个。
一是消费者处理逻辑太慢。消费一条消息要查数据库、调外部接口,单条处理要200毫秒,就算你起了10个线程,吞吐量也只有50条/秒。优化思路是增大消费者实例数,或者提高单消费者的并发能力,但这里有个关键约束:同一个分区只能被group中的一个消费者消费。如果topic只有3个分区,consumer实例加到10个,也有7个是闲置的。要提升并行度,根本办法是增加topic分区数。
二是poll循环设置不合理。Kafka消费者是拉模式,用poll()拉取消息。如果max.poll.interval.ms设得太短,而poll()里处理一批消息的时间超过了这个值,消费者会被判定为“失联”,触发Rebalance,分区被重新分配。处理大数据量批次时尤其容易触发。典型症状是日志里频繁出现心跳失败、Rebalance失败之类的内容。
三是Consumer被Rebalance风暴拖垮。判断方法是查看group里的实例是否频繁增减,或者分区是否频繁变化。如果监控里看到“New consumer group joined”之类的日志刷屏,基本就是了。
生产端的延迟,重点看两个参数。acks如果配成all,每条消息都要等所有ISR副本写成功才确认,吞吐量会下降一截。但这通常不是延迟高的主要原因,更大的嫌疑是linger.ms和batch.size设置不合理。linger.ms是生产者在发送前等待更多消息进入批次的时间,默认是0,有消息就立刻发。为了加大批次而把linger.ms调得很大,消息在客户端就被“憋住”了,延迟会明显上升。batch.size太小则会导致批次频繁发送,网络往返次数增加。
Broker端的延迟,先看磁盘I/O,再看网络,然后看分区数和副本同步。磁盘写满或随机写压力大,会拖慢消息落盘;网络带宽打满,消息传输自然变慢;副本同步跟不上,acks=all的生产请求会一直等超时。
最后说一个实际技巧:排查消息延迟,一定要看指标变化趋势而不是单点值。至少关注生产速率、消费速率、分区数这三个指标的关系,延迟是结果,速率对比才是原因。别拍脑袋调参,收益很低。
4.2 OOM:Kafka的堆内存和页缓存要分清楚
Kafka的OOM问题和普通Java服务不太一样。很多人一看到OutOfMemoryError就加堆内存,结果越加越糟。先给结论:Kafka是JVM进程,但它的IO性能核心在于充分利用操作系统的页缓存,而不是把内存全塞给堆。
Kafka的JVM堆默认只有1GB,这是官方刻意为之的。消息数据本身不放在堆里,而是通过页缓存读写。堆内存主要存消息索引、副本状态、各类缓存对象。所以,如果你发现系统内存很充裕但Kafka性能上不去,先别急着加堆,检查是不是把页缓存空间挤占了。页缓存占用的是文件系统内存,JVM堆占用的是堆内内存,两者互相竞争。一个常见错误是:为了“充分利用”内存,把KAFKA_HEAP_OPTS设成-Xmx16G,结果留给页缓存的内存少了,Kafka读写性能反而下降。
真正的OOM分两种场景。
第一种是JVM堆溢出,日志里会出现java.lang.OutOfMemoryError: Java heap space。常见诱因是topic和分区数量过多导致元数据对象膨胀,或者消费者一次拉取量过大把缓冲区撑爆。处理方式先用jstat看GC频率和堆占用,再决定是加堆还是优化代码。注意,加堆前建议先做GC日志分析,堆加太大反而让Full GC时间变长,触发消费者超时、Rebalance这些连锁问题。
第二种是操作系统层OOM,进程可能直接被Kill。这种要查系统日志:
如果看到“Out of memory: Kill process”,说明是操作系统OOM Killer把Kafka进程干掉了。原因通常是宿主机内存不足:JVM堆、页缓存、其他进程合起来超过了物理内存。这时候要么加物理内存,要么减少同机进程,要么限制堆大小。
容易被误认为OOM的还有一种:文件描述符耗尽。打开文件句柄超过系统限制后,Kafka会出现各种IO异常,日志里有“Too many open files”。这不是内存问题,调大ulimit -n就行。我见过有人折腾半天内存参数,最后发现是这个问题。
4.3 数据重复的三个来源和幂等保障
Kafka并不是天生不重复的,实际上它连“不丢失”都需要正确配置才能做到,“不重复”更是需要业务侧配合。数据重复的本质原因无非三个:生产者重试导致的重复、消费者提交位移失败导致的重复、下游重放导致的重复。
先看生产者。Producer发送消息时,如果网络超时或Broker返回临时错误,客户端会重试,一条消息可能被写入多次,消费者就会看到重复数据。Kafka从0.11版本开始支持幂等性,开启方式如下:
开启后,Producer会给每条消息加一个序列号,Broker端按序列号去重,同一批次内的重复写入不会被重复保存。注意,幂等性只保障单个分区内的精确一次,跨分区的重复(比如事务场景)需要配合事务机制。
再看消费者。消费者的模式是“拉消息 -> 处理消息 -> 提交offset”。如果处理成功但提交offset失败,比如进程刚处理完就挂了,下次启动后会从旧offset重新消费,这批消息被再处理一遍,就重复了。这是消费端出现重复数据最主要的原因。
解决思路分两层。第一层是尽量保证提交时机准确,比如处理完再提交,用同步提交而不是异步提交。但这只能缩小窗口,不能根治。第二层就是业务幂等,最实用的方案是给消息加一个唯一业务键,消费时查询数据库是否处理过,没有则插入,有则跳过;或者用数据库唯一索引硬性约束,让重复数据插不进去。这种思路跟数据库防重设计的套路是一样的。
最后说事务场景。Kafka的exactly-once语义需要Producer开启事务,消费者设置isolation.level=read_committed,再配合幂等开启。这套方案能实现端到端精确一次消费,但性能和复杂度都上升,生产环境里能不用就不用。绝大多数业务的重复消费,通过业务幂等就能扛住,不必折腾事务。
补充提醒:如果用了ELK链路,最好在下游也做幂等键。Kafka去重只是减少了重复消息进入,但Logstash或Elasticsearch重放时还可能重复写入。
5. 可视化工具与ELK衔接的实操经验
命令行功能强大,但看监控、查问题、调topic时,可视化工具能省下大量时间。我把自己用过的几款工具做个对比,再说说和ELK配合时容易踩的坑。
5.1 常用可视化工具对比
| 工具 | 项目状态 | 核心能力 | 适用场景 |
|---|---|---|---|
| Kafka UI(provectus/kafka-ui) | 活跃 | topic管理、消费组查看、消息浏览、配置展示 | 日常开发排障首选 |
| Offset Explorer(原Kafka Tool) | 桌面端 | 多集群管理、消息查看、偏移量管理 | 本地图形化操作 |
| Kafdrop | 轻量Web | 查看topic、分区、消费组、消息 | 快速看全局 |
| CMak(原Kafka Manager) | 维护较慢 | 集群监控、topic管理、分区重分配 | 老牌集群管理 |
我的个人选择是Kafka UI。它可以直观看到每个topic的分区Leader、ISR列表,也能直接查看消息内容,还支持发送测试消息。跟命令行工具配合使用,日常效率高很多。部署也简单,Docker拉一个容器,配置好集群地址就行:
如果你的习惯是桌面客户端,Offset Explorer依然能打,多集群配置和视图对熟悉传统MQ工具的人比较友好。但它的消息查看功能没有Kafka UI那么灵活。
这里有一个安全提示:这些工具本身也是Kafka客户端,连接时同样要处理advertised.listeners的地址问题。如果Kafka没有开启加密和认证,不要把工具端口暴露到公网,至少给工具加一层访问控制。
5.2 与ELK配合时的三个注意点
ELK(Elasticsearch + Logstash + Kibana)和Kafka组合,几乎是日志平台的标准架构。常见链路是Filebeat或应用直连Kafka,Kafka做日志缓冲,Logstash从Kafka拉数据写入Elasticsearch,Kibana做检索展示。Kafka在中间的角色是缓冲池加削峰,避免下游Elasticsearch被突发流量打挂。
整合时最容易忽视的是三个问题。
第一个是topic分区数规划。Elasticsearch的吞吐能力决定了Kafka下游的消费速度。如果topic只有1个分区,Logstash起了10个线程,也只有1个线程在真正消费,吞吐上不去。建议按下游消费能力把分区数规划成8、16、32这类值,方便扩展。但分区数创建后虽然可以增,改动offset和管理成本都不小,所以一开始要有前瞻性。
第二个是消息大小的上限。默认的message.max.bytes是1MB,如果日志消息里带了大字段,超过了这个值,生产端直接报错。ELK场景里,日志带大堆栈或大JSON很常见,需要把Broker端的message.max.bytes、Logstash的相应配置、消费者端的fetch.max.bytes一起调大。单独改一头没用,这是最典型的配置不一致问题。
第三个是消费组隔离。日志场景和业务场景如果共用同一个Kafka集群,务必为Logstash配置独立且稳定的consumer group,并保证该group的offset提交正常。如果这个group频繁Rebalance或offset丢失,日志采集会断断续续,而业务侧完全无感知,排查起来很痛苦。
6. 面试速记:高频考题的极简答案
热词里刷着Kafka面试题,我就把最有价值的几个考点整理成速记表格。每条都是可以直接答出口的知识点,但最好自己把背后的道理也过一遍。
6.1 高频考点速记表
| 问题 | 速记答案 |
|---|---|
| Kafka为什么快 | 顺序写磁盘 + 页缓存 + 零拷贝 + 批量处理。消息追加写入,读写几乎不走随机IO。 |
| 如何保证消息不丢失 | 生产者:acks=all + enable.idempotence;Broker:副本因子>=3,ISR健康;消费者:处理完再提交offset。各层守各层的防线。 |
| 如何保证消息有序 | 单一分区内严格有序。同一业务键的消息进同一个分区,用自定义Partitioner按业务key哈希取模。 |
| 为什么消费者数超过分区数会闲置 | 一个分区同一时刻只能被group中的一个消费者消费,超出部分没有分区可消费,一直空闲。 |
| 重复消费怎么解决 | 根本原因是offset提交与业务处理的时序问题。解法是业务幂等(唯一键、去重表)加尽量精确提交offset。 |
| Offset存在哪里 | 0.9之前存Zookeeper,之后存在Kafka内部topic:__consumer_offsets,默认50个分区。 |
| Rebalance是什么 | 消费者组内消费者数量变化或分区变化时,分区重新分配的过程。期间组内消费暂停,频繁Rebalance会导致吞吐下降。 |
| 分区数和副本数怎么选 | 分区数取决于吞吐需求,但必须匹配消费者组并行度;副本数追求高可用最少3,配合ISR和acks=all使用。 |
| 消费组和广播的关系 | 不同group各自维护offset,天然形成发布订阅;同group内消息只被消费一次,形成点对点。 |
6.2 分区数与消费者数:一个算术题
再说一个容易被问懵的分区数设计题。假设topic要承受每秒5000条消息,消费者单实例每秒能处理1000条,那至少需要5个消费者实例才能跟上。由于一个分区只能被一个消费者消费,分区数至少也得5个,否则多出来的消费者没有分区可消费。如果考虑某台机器故障的情况,建议再加点余量,分区数定成8或16比较稳妥。这里分区数、消费者数、吞吐量三位一体,是生产环境设计最常见的算术题。
还有几个细节面试官喜欢追问:消费者实例数增加时,Rebalance会触发全组暂停;Kafka的消息默认会保留7天,cleanup.policy可以改;topic的partitions和replication-factor在创建时就要想清楚。这些点其实在整篇速记里都已经提到了。
最后再分享一个我实践下来最有用的学习方法:学Kafka不要按部就班啃文档,先把三个问题想明白——消息从哪来、存到哪里、谁在消费。然后亲手搭一个单机环境,把命令行工具的常用参数都敲一遍,再对照监控指标看数据变化。这套流程走下来,你对Kafka的理解会比看十篇教程都深。遇到问题的时候,回到“消息往哪走、offset在哪、消费者状态如何”这三个角度去排查,大部分坑都能自己跳出来。
相关推荐
基于Python+Open CV的手势识别算法设计
伴随着人工智能时代的到来,人机交互的领域也逐渐成为研究的一大方向;其中,手势识别是人机交互领域的一项关键技术,自此手势识别也迎来了一波高潮,近几年无论是在消费领域、电子领域、数码领域、家电领域甚至汽车领域上,都能或多或少的见到手势识别的身影。 手势识别在设计智能高效的人机界面方面具有至关重要的作用, 目前手势识别已应用到手语识别、智能监控、到虚拟现实等各个领域,手势识别的原理都是利用各种传感器(例如红外、摄像头等)对手部的形态进行捕捉并进行建模,形成一个模型信息的序列帧,而后将这些信息序列转换为机器能够识别的相对应指令(例如打开、切换菜单、移动等)来完成控制。 采用Python的集成开发环境Pycharm进行本次课程设计,在Pycharm中进行需要库(模块)的下载,调取电脑摄像头,按帧读取摄像头采集到的头像,形态学处理,图像旋转(由于摄像头采集到的图像是镜像,需要用cv2.flip将摄像头采集到的图像进行处理),选取图片中固定位置作为手势输入,用红线画出手势识别框,基于hsv的肤色检测,进行高斯滤波,找出轮廓,求出图像中手势的凹凸点,手指间角度求取。
ROS-CV-ImageConverter:将ROS图像转换为OpenCV(cv :: Mat)类型的图像
ROS-CV图像转换器 依存关系 cv_bridge(ROS软件包)
计算机视觉图像处理-CV2与图像插值算法
用最近邻插值与双线性插值原理完成图像缩放 最近邻插值,是指将目标图像中的点,对应到源图像中后,找到最相邻的整数点,作为插值后的输。缺点:使用最近邻插值算法处理图像放大时,在图象中可能出现明显的块状效应 双线性插值,在两个方向上做三次线性插值。使用双线性插值算法处理图像放大时,在图象中可能出现马赛克 代码 import cv2 img = cv2.imread(’./xiabang.jpg’, cv2.IMREAD_UNCHANGED) #缩放比例 scale_percent = 0.3 width = int(img.shape[1] * scale_percent) height = int
基于水平集CV模型的图像分割(Matlab代码)
基于水平集CV模型的图像分割(Matlab代码),全套代码
导向滤波(guide_filter)的python实现
导向滤波(guide_filter)的python实现,可以结合暗通道;理论实现比较好的图像去噪效果。

