尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Kafka在Linux下的启动全攻略:从环境检查到一键管理脚本

发布时间:2026/9/18 12:11:26

资讯中心
01
ARTICLE

Kafka在Linux下的启动全攻略:从环境检查到一键管理脚本

Kafka在Linux下的启动全攻略:从环境检查到一键管理脚本
不废话直接说结论Kafka在Linux下的启动说难不难但说简单也绝不简单。我自己第一次在服务器上把Kafka跑起来时就栽在了一个很蠢的细节上——照着Windows教程想也没想就去找kafka-server-start.bat结果当然是找不到。后来又经历了几次窗口启动又秒退、jps看不到进程、日志刷了一屏不知道到底成功没有的折磨之后我干脆把整套启动流程写成了一个带start/stop/status的脚本。这篇就把完整脚本和启动链路里最容易踩的坑全部整理出来给同样从小白阶段起步的朋友照着做就行。1. 启动前检查这三样能避开九成报错Kafka启动失败绝大多数不是Kafka本身的问题而是启动之前的环境就没准备好。我每次在新机器上部署Kafka动手敲启动命令前都会按下面的顺序过一遍检查项总共就三样JDK、安装包、配置文件。1.1 JDK和jps先确认Java环境真的能用Kafka是JVM应用没有Java环境什么都白搭。检查JDK不要只看java -version能打印版本号就算完还要确认jps这个工具能用。jps来自JDK而不是JRE如果你装的是精简版JREjava -version没问题但jps会报command not found。而后面的启动和进程检查都要依赖jps或ps。java -version jps -l版本方面需要注意Kafka 2.x版本用JDK 8完全没问题Kafka 3.0之后的版本建议用JDK 11或17。尤其是Kafka 3.4以后的某些版本在JDK 8环境下运行会提示不支持。我自己的习惯是服务器上统一装JDK 11兼容性最稳。如果机器上已经装了多个JDK版本但默认版本不对可以通过update-alternatives --config java切换或者直接把JAVA_HOME和PATH写进/etc/profile。1.2 Kafka安装包选型和解压位置Kafka官网下载页面会看到类似kafka_2.13-3.6.0.tgz这样的包名前面的2.13是编译Kafka时使用的Scala版本后面的3.6.0才是Kafka本身的版本。我建议优先选最新的稳定版本号Scala版本选哪种影响不大只要不是特别老的项目2.13或2.12都行。下载之后解压推荐放到/usr/local/kafka或/opt/kafka这类统一目录并设置一个软链方便以后升级版本。tar -xzf kafka_2.13-3.6.0.tgz mv kafka_2.13-3.6.0 /usr/local/kafka这里顺带说一个解压的坑如果你拿到的是zip包并且在Windows上解压过一次再传到Linux经常会出现文件名乱码的问题。用unzip -O GBK xxx.zip能解决一部分乱码情况但最稳妥的办法还是直接用Linux上重新解压tar.gz包Kafka官方本来就推荐用tgz格式不会有这类问题。解压之后Kafka的所有启动脚本都在bin/目录下Windows下的.bat文件在bin/windows/目录下Linux下真正要用的是不带扩展名的.sh脚本。这一点很多新手会懵下面第3章会再展开。1.3 server.properties里必须亲手改的两个地方Kafka的配置文件在config/server.properties默认配置里有几个关键参数是启动前必须确认的否则启动后会出现各种看起来正常但连不上的诡异问题。第一是broker.id默认是0。单机部署不需要改但如果你要搭多节点集群每个节点这个值必须唯一。第二是listeners这是最容易被忽略的设置。如果保持默认值Kafka会以PLAINTEXT://:9092这样的格式监听本机所有网卡的9092端口。如果你只是在本机测试这个默认值没问题但如果你要在别的机器上访问这台Kafka就需要显式设置否则会碰到生产和消费都能跑通但远程客户端连不上的情况。broker.id0 listenersPLAINTEXT://0.0.0.0:9092 log.dirs/data/kafka-logs zookeeper.connectlocalhost:2181第三是log.dirs这是Kafka存放消息数据的位置默认在/tmp/kafka-logs。必须改掉因为/tmp目录在Linux重启后会被清空一旦清了Kafka所有数据都没了。我习惯改成独立的/data/kafka-logs并提前创建好目录、赋予当前用户写权限。mkdir -p /data/kafka-logs如果目录不存在或没有写权限Kafka启动会直接报错退出所以这一步提前做掉能少踩一个坑。2. 启动链路拆解先ZooKeeper后Kafka版本差异别搞混Kafka 2.x以及3.0到3.4之间常见的部署模式都依赖ZooKeeper来保存集群元数据。虽然Kafka 3.0开始引入了KRaft模式、可以去掉ZooKeeper但实际工作中接触到的老集群、老教程、大多数公司的生产环境仍然以ZooKeeper模式为主。所以这篇里我按最常见的模式来讲先启动ZooKeeper再启动Kafka。2.1 标准启动命令与成功标志启动ZooKeeper的命令在Kafka的bin目录下cd /usr/local/kafka bin/zookeeper-server-start.sh config/zookeeper.propertiesZooKeeper默认监听2181端口看到输出里有binding to port 0.0.0.0/0.0.0.0:2181基本就说明起来了。这个进程启动之后会一直占用当前终端所以实操中通常用nohup ... 或者后面给的脚本来后台运行。ZooKeeper起来之后再启动Kafkabin/kafka-server-start.sh config/server.propertiesKafka默认监听9092端口。如果配置没问题启动日志里会看到一条典型的成功标志。不同版本写法略有差异常见的有[KafkaServer id0] started (kafka.server.KafkaServer)或者新版[KafkaServer id0] Finished starting brokers and controllers看到这类信息基本就可以确定Kafka启动成功了。但启动成功不意味着Kafka立刻就能对外服务尤其是刚启动完那一两秒Kafka还在初始化日志恢复等内部流程如果你立刻跑生产消费命令偶尔会报LeaderNotAvailable或BrokerNotAvailable等几秒再试通常就正常了。2.2 如果能看懂启动日志排查会快很多新手看到Kafka启动时刷出一大屏日志往往就慌了其实只要关注几个关键点就行。第一是确认INFO级别日志里有没有ERROR或FATAL级别的异常堆栈。第二是确认最后那几行有没有出现started、Started、Finished这类词。第三是如果你改了端口确认日志里实际监听端口和配置一致。还有一个常见疑问为什么启动Kafka时日志明明刷了一大片INFO却没有结束因为Kafka本来就是常驻服务正常启动后日志停在started附近进程不会退出这不是卡住了。判断是否卡住最直接的方法是再开一个终端执行jps -l能看到QuorumPeerMainZooKeeper和Kafka两个进程就说明都在运行。jps -l # 输出示例 # 12345 kafka.Kafka # 12346 quorum.QuorumPeerMain有些发行版默认没装jps那就用ps -ef | grep kafka也一样。2.3 Windows教程的后遗症bat和sh的混用问题经常在技术群里看到有人发这种求助我按照教程输入了kafka-server-start.bat为什么提示找不到命令原因很简单.bat是Windows批处理文件Linux下根本没有这个可执行文件。Kafka发行包里带了bin/windows/目录里面才是给Windows用的脚本。在Linux下你应该找的是bin/kafka-server-start.sh bin/kafka-topics.sh bin/kafka-console-producer.sh bin/kafka-console-consumer.sh bin/kafka-consumer-groups.sh实际敲命令时bin/kafka-server-start.sh后面必须跟一个配置文件参数否则会报Missing required argument。这也是新手常踩的坑——拿着教程只复制了脚本名忘了后面的config/server.properties。理解了这条启动链路下面就可以直接上脚本了。3. Kafka启动脚本可直接复制支持start、stop、status把Kafka启动过程脚本化最大的价值不只是省事而是让它变得可控。手工启动时ZooKeeper和Kafka分别占两个终端关掉终端进程就没了你没法方便地停止、重启、查状态。用脚本统一管理PID和日志这些问题一次解决。3.1 脚本完整代码下面这个脚本我在多台机器上用过兼容Kafka 2.x和3.x的ZooKeeper模式你只需要改开头的KAFKA_HOME路径即可。#!/usr/bin/env bash # Kafka启停脚本适用于 Kafka 2.x / 3.x ZooKeeper 模式 # 用法: ./kafka-control.sh {start|stop|status|restart} set -u KAFKA_HOME${KAFKA_HOME:-/usr/local/kafka} ZK_CONFIG$KAFKA_HOME/config/zookeeper.properties KAFKA_CONFIG$KAFKA_HOME/config/server.properties LOG_DIR$KAFKA_HOME/logs PID_DIR${PID_DIR:-/tmp} is_running() { local pid_file$1 if [[ -f $pid_file ]]; then local pid pid$(cat $pid_file) if kill -0 $pid 2/dev/null; then return 0 fi rm -f $pid_file fi return 1 } write_pid() { local pid_file$1 local pid$2 echo $pid $pid_file } start_one() { local label$1 local pid_file$PID_DIR/${label}.pid local log_file$LOG_DIR/${label}.log shift 1 if is_running $pid_file; then echo [$label] 已在运行pid$(cat $pid_file) return 0 fi mkdir -p $LOG_DIR nohup $ $log_file 21 write_pid $pid_file $! sleep 2 if is_running $pid_file; then echo [$label] 启动成功pid$!日志: $log_file else echo [$label] 启动失败请查看日志: $log_file exit 1 fi } stop_one() { local label$1 local pid_file$PID_DIR/${label}.pid if is_running $pid_file; then local pid pid$(cat $pid_file) kill $pid echo [$label] 停止信号已发送pid$pid else echo [$label] 未在运行 fi } case ${1:-} in start) echo 启动 ZooKeeper start_one zookeeper $KAFKA_HOME/bin/zookeeper-server-start.sh $ZK_CONFIG echo 等待 ZooKeeper 就绪 sleep 5 echo 启动 Kafka start_one kafka $KAFKA_HOME/bin/kafka-server-start.sh $KAFKA_CONFIG ;; stop) echo 停止 Kafka stop_one kafka echo 停止 ZooKeeper stop_one zookeeper ;; status) if is_running $PID_DIR/kafka.pid; then echo Kafka: 运行中 (pid$(cat $PID_DIR/kafka.pid)) else echo Kafka: 未运行 fi if is_running $PID_DIR/zookeeper.pid; then echo ZooKeeper: 运行中 (pid$(cat $PID_DIR/zookeeper.pid)) else echo ZooKeeper: 未运行 fi ;; restart) $0 stop sleep 3 $0 start ;; *) echo 用法: $0 {start|stop|status|restart} exit 1 ;; esac使用方法chmod x kafka-control.sh ./kafka-control.sh start ./kafka-control.sh status ./kafka-control.sh restart ./kafka-control.sh stop3.2 逐段解读脚本里每个变量和函数都是干什么的很多人拿到脚本就直接用但一旦出问题就抓瞎所以我建议还是理解一下每个块的作用。开头的set -u表示变量如果没定义就报错而不是悄悄用空值这是脚本安全的基本习惯。KAFKA_HOME、ZK_CONFIG、KAFKA_CONFIG、LOG_DIR、PID_DIR这几个变量是脚本的基础配置改成适合自己环境的路径即可。我用${PID_DIR:-/tmp}这种写法意思是如果外面没有设置PID_DIR环境变量就默认用/tmp这样你可以在不修改脚本的情况下改PID目录。is_running函数是整个脚本的地基。它的逻辑是读PID文件里面的进程号然后用kill -0测试这个进程是否存在。kill -0不会真的发送信号只是探测进程可不可以被信号访问能访问就说明进程活着不能访问就说明进程已经死了。如果进程死了顺手把残留的PID文件删掉避免下次误判。用这个函数start时可以防止重复启动stop时也可以判断是否需要发送停止信号。start_one函数接收三个参数服务名zookeeper或kafka、启动脚本路径、配置文件路径。先判断是否已在运行在运行就提前返回然后用nohup把进程放到后台把标准输出和错误输出全部重定向到日志文件同时把新进程的PID写入PID文件。这里的sleep 2不是为了炫技是因为有些环境JVM启动需要一两秒马上探测PID可能还没写入会导致误判。nohup的必要性在于它能让进程在你关掉终端、退出SSH会话后继续运行否则你断开连接Kafka就跟着挂了。stop_one函数就简单多了先判断进程是否存活存活就发送kill信号。这里有个细节要注意kill默认发送的是TERM信号这属于优雅退出信号。Kafka和ZooKeeper收到TERM后会先做数据刷盘、清理资源等收尾工作然后再退出。所以停服时看到进程没有立刻消失不要急那是在正常退出。如果确实卡住很久再考虑用kill -9强制结束。最后的case分支就是命令分发逻辑。start分支里我在启动Kafka之前先sleep 5这个时间要重点说一下。Kafka启动时要去ZooKeeper注册broker数据和各种元信息如果ZooKeeper还没完全就绪就去启动Kafka会碰到连接拒绝或者元数据初始化异常表现就是Kafka进程启动失败或者启动日志里一堆Connection refused。如果你机器性能较差5秒不够可以适当调到10秒。3.3 将这个脚本放进PATH并使用脚本写好后每次使用都敲./kafka-control.sh虽然不麻烦但既然要长期用我建议把它放到/usr/local/bin下这样在任何目录都能直接用命令名调用sudo cp kafka-control.sh /usr/local/bin/kafka-control sudo chmod x /usr/local/bin/kafka-control之后你就可以直接执行kafka-control start kafka-control status如果你是那种同时管理多套Kafka环境的运维可以用环境变量KAFKA_HOME来切换不同安装目录脚本里已经支持了不需要维护多个副本KAFKA_HOME/usr/local/kafka-3.6.0 kafka-control start4. 启动失败的完整排查链路脚本不是万能的如果启动失败它只能告诉你启动失败请查看日志。所以我把实际过程中最常见的几类失败场景整理成一条完整排查链路按顺序走下去大部分问题都能定位。4.1 卡住不动的处理检查ZooKeeper是否真正就绪表现执行kafka-control start之后ZooKeeper提示启动成功但Kafka部分迟迟不输出启动成功最后还提示失败。首先确认ZooKeeper是不是真的能接受请求。看日志是最直接的tail -n 50 /usr/local/kafka/logs/zookeeper.log如果日志里有binding to port 0.0.0.0/0.0.0.0:2181说明ZooKeeper至少已经绑定了端口。但绑定端口不代表完全就绪你可以用netstat或ss再看一下ss -lntp | grep 2181如果确认ZooKeeper没问题再看Kafka日志tail -n 100 /usr/local/kafka/logs/kafka.log比较常见的报错是org.apache.zookeeper.KeeperException$ConnectionLossException这通常说明Kafka启动时连不上ZooKeeper。检查server.properties里的zookeeper.connect是不是配错了地址或端口。如果你改过ZooKeeper端口这里必须同步修改。还有一种容易被忽略的情况server.properties里zookeeper.connectlocalhost:2181但Kafka进程因为某些原因解析不了localhost。这种在容器或特殊网络环境下遇到得多最省事的办法是把localhost改成127.0.0.1或者直接改成机器内网IP。还有个新手必踩的坑主机名解析。Kafka或ZooKeeper启动时有时会尝试根据主机名做DNS解析如果机器没有配置合理的/etc/hosts会出现启动卡住很久然后超时。建议看看/etc/hostname和/etc/hosts确保本机主机名能够解析到本机IP。4.2 端口被占用和权限不足两个极易被忽视的元凶端口被占用时的报错通常是java.net.BindException: Address already in use这时候不要急着猜是谁占用的直接查ss -lntp | grep 9092如果发现有其他进程占了9092要么停掉它要么改Kafka的listeners端口。同理ZooKeeper的2181被占也会出现类似问题。实际工作中我还遇到过一种情况上一批Kafka进程没被完全杀掉端口被残留进程占着看着像新启动失败其实是老进程还活着。这时候清理僵尸进程比盲目重启更有用。权限不足的情况启动日志里通常会看到Exception in thread main java.io.IOException: No space left on device注意No space left on device不只是磁盘满了才会出现也可能是inode耗尽。用df -h看磁盘剩余用df -i看inode剩余。Kafka如果一直写日志磁盘满的概率还是不小的。另外日志目录和数据目录的写权限也要确认我之前在根目录部署时图省事没给log.dirs指向的目录授予正确权限结果Kafka每次启动都在初始化时失败报错却很隐晦找了半天才发现是权限问题。4.3 内存不足和JVM参数调优默认情况下Kafka的启动脚本会设置堆内存大小通常在bin/kafka-server-start.sh里能看到KAFKA_HEAP_OPTS-Xmx1G -Xms1G如果你机器本身内存不大比如只有1G内存启动时可能直接报Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory ...或者干脆Killed进程被OOM Killer干掉了。这时可以修改kafka-server-start.sh把堆内存调小。我一般这样改export KAFKA_HEAP_OPTS-Xmx512M -Xms512M注意修改时要先看脚本里KAFKA_HEAP_OPTS是在哪里被设置的。如果在脚本里写死了你export外部变量可能覆盖不了需要实际编辑对应脚本。ZooKeeper的JVM参数也有类似限制但通常默认值更保守问题不大。还有一个容易被忽略的内存坑Kafka消息本身存储在操作系统的页缓存Page Cache里而不是完全依赖JVM堆。所以如果你给JVM堆设了1G额外还需要一些内存来承载页缓存压力。实测中512M堆加上系统本身的开销在2G内存的云主机上跑单机Kafka是可行的但要注意别把系统内存全部交给JVM。5. 启动成功后用这几条命令检验Kafka真的能用很多人启动Kafka后看到日志里有started就以为万事大吉但进程活着和功能可用是两码事。我习惯启动后立刻用一条链路做验证创建topic、起一个生产者、起一个消费者把消息跑通。5.1 验证Topic创建和基础消息收发如果没有自动创建topic可以先手动创建一个建议先建一个1分区1副本的测试topicbin/kafka-topics.sh --bootstrap-server localhost:9092 --create --topic test-topic --partitions 1 --replication-factor 1提示如果用的是Kafka 2.x版本也可以用--zookeeper localhost:2181但新版本已经推荐用--bootstrap-server localhost:9092。如果你看到zookeeper is not a recognized option之类的报错说明你的Kafka版本已经移除了ZooKeeper相关参数。创建成功后再启动一个生产者bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test-topic这个命令启动后会进入交互模式光标停在空白行等你输入内容。输入几行文本后CtrlC退出。你可以看到这个命令启动后会一直运行不会自动退出这个问题我下面会单独讲。然后启动一个消费者从最早的消息开始读bin/kafka-console-consumer.sh --bootstrap-server localhost:9092 --topic test-topic --from-beginning如果配置没问题刚才在生产者那边输入的内容会一条条打出来。到这里Kafka的生产消费链路就验证通过可以放心使用。5.2 查看topic数据和消费组lag除了基础收发日常使用中还有几个高频排查命令。查看topic列表和详情bin/kafka-topics.sh --bootstrap-server localhost:9092 --list bin/kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic test-topic查看某个消费组的消费延迟lagbin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group your-consumer-group --describe消费组和lag是Kafka面试和日常运维的高频概念。简单理解lag就是生产者已经写入的消息数量减去消费者已经处理掉的消息数量lag数值越高说明消费者落后越多。网上很多人问Kafka能重复消费吗这背后其实是offset提交机制的问题消费者处理完一批消息后要提交offset但如果消费者在提交前就挂掉了重启后会根据上次提交的offset重新消费就出现了重复消费。排查这类问题时kafka-consumer-groups.sh --describe是必用的工具。注意很多教程里查询消费组会用--zookeeper参数但新版Kafka同样建议使用--bootstrap-server。如果你用的是比较老的Kafka版本--zookeeper才能查询到offset所以这个命令在不同版本之间行为差异较大使用时先确认你的版本。5.3 可选的图形化工具一条Docker命令拉起UI如果觉得命令行不方便想用图形界面看Kafka里的数据这里推荐一个很轻量的方案用Docker跑一个Kafka UI服务docker run -d --name kafka-ui -p 8080:8080 \ -e KAFKA_CLUSTERS_0_NAMElocal \ -e KAFKA_CLUSTERS_0_BOOTSTRAPSERVERSlocalhost:9092 \ -e KAFKA_CLUSTERS_0_ZOOKEEPERlocalhost:2181 \ provectuslabs/kafka-ui:latest然后浏览器访问http://服务器IP:8080就能看到broker信息、topic列表、消息内容。这个工具对排查问题帮助很大尤其是当你想快速确认一条消息有没有进入某个topic的时候不用在命令行里反复切命令。前提是Kafka的listeners地址能被这个UI容器访问到如果网络不通可能要调整KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS的地址。最后再说一个我在实际操作中的体会Kafka启动这个事一旦你用脚本把它管起来后面就再也不想裸敲命令了。因为裸敲命令的时候你永远不知道哪个进程还在背后运行哪个PID已经失效而脚本把start/stop/status/restart都收敛成一条命令状态一目了然。建议你把这篇里的脚本存好换机器部署Kafka时直接拿过来改掉路径就能用能省下不少重复折腾的时间。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。