Ubuntu 上 Zookeeper 故障排除技巧
一 快速定位流程
- 查看服务状态与进程:执行 zkServer.sh status;用 jps 检查是否存在 QuorumPeerMain。若 status 报错但进程不在,多半启动异常。
- 前台启动看实时输出:执行 zkServer.sh start-foreground,或查看 logs/*.out / zookeeper.out,优先从日志定位根因。
- 核对端口连通:默认 clientPort=2181,用 netstat -lnp | grep 2181 检查占用;客户端可用 telnet zookeeper-ip 2181 验证连通性。
- 配置与身份校验:确认 zoo.cfg 的 server.X 列表、clientPort、以及 dataDir 下 myid 文件与 server 编号一致;必要时调整防火墙放行相关端口。
- 版本与兼容性:客户端与服务端版本尽量匹配,避免因协议/特性差异导致连接异常。
二 常见故障与修复
- 端口被占用:日志或 netstat 显示 Address already in use / clientPort found: 2181。处理:kill 占用进程或修改 zoo.cfg 的 clientPort 为未占用端口,重启。
- 启动即返回 “STARTED” 但 status 报 “Error contacting service”:多为未真正拉起进程或 Java 环境异常。处理:前台启动观察输出;若见 “nohup: failed to run command ‘java’”,在 zkServer.sh 开头显式设置 JAVA_HOME,或将 nohup 行改为 “$JAVA_HOME/bin/java”。
- JAVA_HOME 未设置或 Java 找不到:zkServer.sh 报 “JAVA_HOME is not set …”。处理:在脚本或 ~/.bashrc / /etc/profile 中正确设置 JAVA_HOME 并生效。
- 下载包错误导致类找不到:出现 “Could not find or load main class org.apache.zookeeper.server.quorum.QuorumPeerMain”。处理:Zookeeper 3.5.5+ 需下载带 bin 的二进制包,源码包无法直接运行。
- 配置或数据目录问题:报 “Invalid config, exiting abnormally” 或启动后异常退出。处理:确保 dataDir/dataLogDir 目录已存在且可写;集群需为每个节点配置唯一 myid 并与 server.X 对应。
- 集群选主异常/个别节点状态异常:某节点 status 显示未运行但其他正常。处理:可先停掉异常节点,按顺序重启相关节点,再启动该节点以恢复 quorum。
三 配置与日志要点
- 关键配置示例(zoo.cfg):
- tickTime=2000,initLimit=10,syncLimit=5
- dataDir=/var/lib/zookeeper,dataLogDir=/var/log/zookeeper(确保目录存在且权限正确)
- clientPort=2181
- 集群示例:server.1=192.168.1.11:2888:3888,server.2=192.168.1.12:2888:3888,server.3=192.168.1.13:2888:3888
- myid 文件:在 dataDir 下创建,内容仅为一个数字(如 1、2、3),必须与对应 server.X 的 X 一致。
- 日志位置:安装目录 logs/ 下的 zookeeper.log 与 .out 文件最直观;若通过包管理器安装,配置文件可能在 /etc/zookeeper/,运行与日志路径可能由 /etc/zookeeper/conf/environment 或相应环境文件控制,需按实际环境核对。
四 网络与防火墙检查
- 本机端口检查:netstat -lnp | grep 2181(确认 clientPort 监听正常)。
- 跨机连通性:在客户端执行 ping 与 telnet zookeeper-ip 2181;不通时优先排查安全组/防火墙策略。
- 防火墙放行(UFW 示例):
- 放行单端口:sudo ufw allow 2181/tcp
- 放行区间:sudo ufw allow 2888:3888/tcp
- 策略生效后重测连通性。
五 一键排查脚本示例
- 用途:批量在集群节点上执行 start/stop/status,并快速查看 .out 日志尾部。
- 示例脚本(保存为 zk.sh):
- 用法:./zk.sh start | stop | status | tail
- 注意:将 HOSTS 与 ZK_HOME 替换为你的实际环境。
#!/usr/bin/env bash
HOSTS=("192.168.1.11" "192.168.1.12" "192.168.1.13")
ZK_HOME="/opt/zookeeper"
case "$1" in
start)
for h in "${HOSTS[@]}"; do
echo "=== $h 启动 ==="
ssh "$h" "source ~/.bashrc; $ZK_HOME/bin/zkServer.sh start"
done
;;
stop)
for h in "${HOSTS[@]}"; do
echo "=== $h 停止 ==="
ssh "$h" "source ~/.bashrc; $ZK_HOME/bin/zkServer.sh stop"
done
;;
status)
for h in "${HOSTS[@]}"; do
echo "=== $h 状态 ==="
ssh "$h" "source ~/.bashrc; $ZK_HOME/bin/zkServer.sh status"
done
;;
tail)
for h in "${HOSTS[@]}"; do
echo "=== $h 日志尾部 ==="
ssh "$h" "tail -n50 $ZK_HOME/logs/*.out"
done
;;
*)
echo "用法: $0 {start|stop|status|tail}"
exit 1
;;
esac
- 若脚本内 ssh 执行报 “nohup: failed to run command ‘java’”,可在远端 zkServer.sh 开头显式设置 JAVA_HOME,或将 nohup 行改为 “$JAVA_HOME/bin/java”。