背景说明
一体机中使用了单机模式的zookeeper(开机自启服务),一体机经常会遇到断电重启的场景,在运行过程中偶现无法开机启动问题,再次断电重新启动可以正常启动
前置知识
kill -0 pid 不发送任何信号,但是系统会进行错误检查。所以经常用来检查一个进程是否存在,存在返回0;不存在返回1
The signals listed below may be available for use with kill. When known constant, numbers and default behavior are shown.Name Num Action Description 0 0 n/a exit code indicates if a signal may be sent
根因分析
脚本阅读
查看脚本zkServer.sh
内容
case $1 in
start)
echo -n "Starting zookeeper ... "
if [ -f $ZOOPIDFILE ]; then
if kill -0 `cat $ZOOPIDFILE` > /dev/null 2>&1; then
echo $command already running as process `cat $ZOOPIDFILE`.
exit 0
fi
fi
nohup $JAVA "-Dzookeeper.log.dir=${ZOO_LOG_DIR}" "-Dzookeeper.root.logger=${ZOO_LOG4J_PROP}" \
-cp "$CLASSPATH" $JVMFLAGS $ZOOMAIN "$ZOOCFG" > "$_ZOO_DAEMON_OUT" 2>&1 < /dev/null &
if [ $? -eq 0 ]
then
if /bin/echo -n $! > "$ZOOPIDFILE"
then
sleep 1
echo STARTED
else
echo FAILED TO WRITE PID
exit 1
fi
else
echo SERVER DID NOT START
exit 1
fi
;;
判断pid文件是否存在,存在如下两种情况:
不存在则启动zookeeper服务
存在则读取PID号发送信号0判断进程号是否活着,
- 如果进程活着则啥也不做,打印日志
already running as process pid
- 如果进程死了则启动zookeeper服务,新进程号写入pid文件
查看脚本zkServer.sh
内容
stop)
echo -n "Stopping zookeeper ... "
if [ ! -f "$ZOOPIDFILE" ]
then
echo "no zookeeper to stop (could not find file $ZOOPIDFILE)"
else
$KILL -9 $(cat "$ZOOPIDFILE")
rm "$ZOOPIDFILE"
echo STOPPED
fi
exit 0
;;
判断pid文件是否存在,存在如下两种情况:
- 不存在则打印输出
no zookeeper to stop (could not find file $ZOOPIDFILE)
- 存在则
kill -9 pid
杀死进程并删除pid文件
查看脚本zkServer.sh
内容
restart)
shift
"$0" stop ${@}
sleep 3
"$0" start ${@}
;;
先执行
stop
再执行start
原因说明
假设当兵设备异常断电关机,此时zookeepr的进程号是9966,此时pid的文件内容为9966,当一体机开机自启动时,如果已经有其他进程的进程号为9966时,此时zookeepr的启动脚本发现pid文件存在,且9966进程活着,则认为zookeepr已经正常启动,此时启动脚本啥事也不做只打印日志already running as process pid
,此时zookeepr进程没有启动,紧接着skynet启动发现无法连接zookeeper,此时启动失败。
问题复现
- 启动
zookeepr
进程,然后kill -9
强杀进程 - 寻找一个存活的进程并把进程号写入
zookeeper
的pid
文件中 - 启动
zookeeper
进程,发现zookeeper
无法对外提供服务
通过以上步骤即可完成问题复现。
解决方案
一体机开机自启服务中使用restart命令即可。
单机模式
单机模式部署不需要新建myid
文件和zoo.cfg
配置项中添加
server.1=10.5.3.208:2888:3888
server.id=host:port:port : 表示了不同的zookeeper服务器的自身标识,作为集群的一部分,每一台服务器应该知道其他服务器的信息。用户可以从“server.id=host:port:port” 中读取到相关信息。在服务器的data(dataDir参数所指定的目录)下创建一个文件名为myid的文件,这个文件的内容只有一行,指定的是自身的id值。比如,服务器“1”应该在myid文件中写入“1”。这个id必须在集群环境中服务器标识中是唯一的,且大小在1~255之间。这一样配置中,zoo1代表第一台服务器的IP地址。第一个端口号(port)是从follower连接到leader机器的端口,第二个端口是用来进行leader选举时所用的端口。所以,在集群配置过程中有三个非常重要的端口:clientPort:2181、port:2888、port:3888。
这种模式有如下问题
- 额外占用2888和3888端口
- 虽然这种部署模式查询状态时仍然是
Mode: standalone
,但是逻辑上是集群模式
建议单机模式下不新建myid
文件并删除配置server.1
网友评论