资讯动态

Linux下ZooKeeper安装配置详解:从单机到集群与systemd托管

发布时间:2026/9/30 10:14:38 来源:尧图企业网站定制
很多人在学大数据的时候第一次遇到ZooKeeper不是因为它本身多复杂而是因为Hadoop、HBase、Kafka这些组件在HA、分布式协调、元数据管理上都指着它。于是教程看了一大堆真正在Linux上动手装的时候却发现光一个安装环节就能卡住半天。我见过不止一个同事下载的包不对导致启动报“找不到主类”或者JDK版本不对报UnsupportedClassVersionError再或者改完配置文件后发现dataDir写的是/tmp/zookeeper一重启数据全没了。这篇教程把我平时在Linux上装ZooKeeper的完整流程拆开来讲从环境准备、下载解压、zoo.cfg配置、启动验证到伪分布式和systemd托管每一步都有命令、有说明、有坑点适合刚接触分布式、准备搭Hadoop生态、或者只想在本地跑一个ZooKeeper做测试的读者。照着走一遍正常情况下十分钟就能把服务拉起来。1. 安装前先敲定三件事能避开大部分返工1.1 ZooKeeper对JDK版本有隐性要求很多人上来就装装到启动时才报错才回头补环境。ZooKeeper是跑在JVM上的Java程序JDK版本不对后面全是坑。不同版本的ZooKeeper对JDK的要求不一样这里直接给一个对照表。ZooKeeper版本最低JDK建议JDK3.4.xJDK 6JDK 83.5.x / 3.6.xJDK 8JDK 83.7.x / 3.8.xJDK 8JDK 8或113.9.xJDK 11JDK 11或17如果你只是学习测试直接装OpenJDK 8或11都可以这两个是LTS版本生态兼容性最好。检查当前环境java -version如果提示command not found说明JDK还没装。CentOS/RHEL系可以用yum装OpenJDKyum install -y java-1.8.0-openjdk java-1.8.0-openjdk-develDebian/Ubuntu系用aptsudo apt update sudo apt install -y openjdk-8-jdk装完确认一下JAVA_HOME因为ZooKeeper的启动脚本会去找这个变量。可以通过readlink定位真实路径readlink -f $(which java)常见的JAVA_HOME路径比如 /usr/lib/jvm/java-1.8.0-openjdk。如果JAVA_HOME还没设置先在shell里export具体写进哪个配置文件我后面会专门讲。还有一个容易忽略的小细节这里说的“ZooKeeper版本”是指从Apache官网下载的发布版不是某个发行版自带的旧版本。很多老教程还在用3.4.x新项目就别考虑那么老的版本了下面统一用3.7.x做示例。1.2 下载包必须认准bin后缀这是一个教训深刻的坑。Apache ZooKeeper从3.5.0开始官方分发了两种tar.gz包一种带“-bin”后缀一种不带。单看名字很多人分辨不出来随手点了一个不带bin的包下载解压、改配置、启动结果直接报错误: 找不到或无法加载主类 org.apache.zookeeper.server.quorum.QuorumPeerMain原因很简单不带bin后缀的包是源码包只包含源码和部分构建产物运行时需要的依赖jar全部缺失。记住一条结论下载名称里带“-bin”的tar.gz包比如apache-zookeeper-3.7.1-bin.tar.gz。下载地址我习惯用Apache官网的发布列表https://zookeeper.apache.org/releases.html里面会列出当前推荐的下载版本和镜像链接。也可以用archive.apache.org直接拉具体版本的包cd /usr/local/src wget https://archive.apache.org/dist/zookeeper/zookeeper-3.7.1/apache-zookeeper-3.7.1-bin.tar.gz下载完顺手验证一下文件完整性和官网发布的.sha512做对比sha512sum apache-zookeeper-3.7.1-bin.tar.gz把输出和官网提供的SHA512值比对一致再往下一步。这一步在离线环境或者走内网镜像时特别重要包损坏了解压能解出来但启动时会报一些莫名其妙的问题。1.3 部署形态想清楚再动手ZooKeeper可以单机运行也可以组成集群。安装前的部署形态决定了配置怎么写所以我建议先想清楚下面三种情况单机模式一个节点独立运行用于本地开发、学习、功能验证配置最简单。伪分布式一台机器上起多个ZooKeeper进程模拟多节点集群适合没有多台服务器但想体验集群效果的情况。集群模式三台及以上服务器各自跑一个ZooKeeper进程生产环境的标准形态。这三种形态的安装包、JDK、zoo.cfg模板都是同一套东西区别主要在配置文件的节点声明和dataDir/myid上后面我会分开讲。另外为了让服务更干净我习惯在Linux上创建一个专用系统用户来跑ZooKeeper不用root。这样即使服务被利用也不至于拿到root权限。命令很简单useradd -r -s /sbin/nologin zookeeper如果系统提示用户已存在就跳过。2. 解压与目录规划一开始就把路径理干净2.1 目录怎么规划很多第一次装的人喜欢直接解压到 /usr/local/zookeeper 之类的地方然后bin目录、data目录、日志目录全挤在一起。这样不是不能用只是后续维护和出问题排查时目录一乱效率很低。我习惯的目录结构是单独挂一个数据盘或分区规划如下/data/zookeeper/ ├── app # 解压后的程序目录 ├── data # 数据快照目录 └── logs # 事务日志和运行日志目录如果机器上没有 /data 目录创建并授权mkdir -p /data/zookeeper/{app,data,logs} chown -R zookeeper:zookeeper /data/zookeeper用独立数据盘的好处是即使系统盘出了问题ZooKeeper的数据和日志还保得住如果日志写满也不至于把系统盘塞爆。2.2 解压和软链接把刚才下载的包解压到 app 目录tar -zxvf /usr/local/src/apache-zookeeper-3.7.1-bin.tar.gz -C /data/zookeeper/app/解压后app目录里会出现一个 apache-zookeeper-3.7.1-bin 子目录。为了方便升级和维护我建议创建一个不带版本号的软链接ln -s /data/zookeeper/app/apache-zookeeper-3.7.1-bin /data/zookeeper/app/current后续所有脚本、配置、环境变量都指向这个 current下次升级换新版本时只需要解压新版、改一下软链接指向其他配置路径不用大动。如果解压后看到文件名乱码多半是zip包的中文文件名编码问题tar.gz包一般不会出现。如果真遇到zip包乱码可以用 unzip 的 -O GBK 参数解压tar.gz出现乱码先检查上传时的文件名编码别急着改服务器locale。2.3 环境变量统一放到profile.dZooKeeper命令本身在bin目录下你可以每次都写全路径但更省事的是配置环境变量。我推荐在 /etc/profile.d/ 下新建一个 zookeeper.shvi /etc/profile.d/zookeeper.sh内容如下export ZOOKEEPER_HOME/data/zookeeper/app/current export PATH$PATH:$ZOOKEEPER_HOME/bin如果JAVA_HOME之前没配置也一并加进去export JAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk export PATH$PATH:$JAVA_HOME/bin保存后让配置生效source /etc/profile.d/zookeeper.sh注意如果用的是独立用户 zookeeper 运行服务环境变量最好只在服务的启动脚本里显式指定不要依赖登录环境因为systemd或su切用户时不会自动加载/etc/profile.d。这点后面讲systemd时还会再强调。3. zoo.cfg看懂这几个参数安装就完成了一半3.1 三个必改参数和一个高危默认值ZooKeeper的配置文件是conf目录下的zoo.cfg第一次装会发现目录里只有一个zoo_sample.cfg需要自己复制一份cp /data/zookeeper/app/current/conf/zoo_sample.cfg /data/zookeeper/app/current/conf/zoo.cfg打开zoo.cfg核心就是三个参数加一个默认值tickTime2000 initLimit10 syncLimit5 dataDir/tmp/zookeeper clientPort2181逐项说tickTimeZooKeeper最基本的时间单元单位毫秒默认2000也就是2秒。集群中节点间的心跳、超时计算都基于这个值。initLimitFollower节点启动时连接Leader并完成数据同步的最大时间值是tickTime的倍数10就代表10个tickTime也就是20秒。syncLimitFollower与Leader之间正常通信的超时时间同样是tickTime的倍数5就是10秒。clientPort客户端连接端口默认2181通常不用改。dataDir高危默认值就在这。zoo_sample.cfg里默认写的是/tmp/zookeeper如果你不修改服务确实能启动但/tmp目录在部分系统上会被定期清理或重启后清空。一旦清理ZooKeeper的数据快照就没了节点上的元数据全部丢失。生产环境务必改成自己的数据目录。我把dataDir改掉同时加上dataLogDir把事务日志独立出来dataDir/data/zookeeper/data dataLogDir/data/zookeeper/logsdataLogDir这个参数可能有人忽略了它指定的是ZooKeeper事务日志的落盘目录。事务日志和快照日志分开放在不同磁盘上可以减少磁盘IO竞争如果只有一块盘至少目录分开后面维护也清楚。3.2 建议顺手调整的生产参数除了上面几个zoo.cfg里还有几个参数在zoo_sample.cfg中默认不出现或默认值不理想建议根据场景调整。maxClientCnxns0 autopurge.snapRetainCount3 autopurge.purgeInterval24 admin.serverPort8081 4lw.commands.whiteliststat,ruok,conf,cons,envi,mntrmaxClientCnxns单个客户端IP允许的最大连接数默认值是60。这个限制在HBase、Kafka这种客户端连接很多的场景下容易踩雷一个业务实例超过60个连接就被拒绝。测试环境直接设0表示不限制生产环境根据实际连接数评估。autopurge.snapRetainCount保留的快照文件数量默认3配合下面的清理间隔防止磁盘被历史快照和日志堆满。autopurge.purgeInterval自动清理快照和日志的间隔单位小时默认0表示不清理。设成24就是每天清理一次。admin.serverPortZooKeeper 3.5之后内置了一个AdminServer默认监听8080端口提供HTTP接口查看服务状态。这个8080很容易和应用端口冲突建议改掉比如这里改成8081。4lw.commands.whitelist四字命令白名单。新版本对四字命令做了白名单控制如果你要用ruok、mntr等命令需要在这里显式指定。改完保存先用命令确认配置文件能正常读取后面启动时报错概率会降低很多。3.3 日志文件去哪了ZooKeeper的运行日志默认输出到zookeeper.out位置取决于ZOO_LOG_DIR环境变量。如果不设置有可能写到当前工作目录下启动时在哪个目录执行命令日志就跑到哪找起来很麻烦。建议在启动脚本或systemd中显式指定export ZOO_LOG_DIR/data/zookeeper/logs如果你手动启动忘了export可以先看下默认日志落在了哪里然后把它移到规划的logs目录里避免以后排查时到处翻。要是发现日志膨胀得很厉害再去调conf里的logback.xml滚动策略安装阶段先把目录固定下来就好。4. 单机启动与安装验证进程、日志、客户端三步走4.1 首次启动建议先看前台日志配置文件搞定后第一次启动我强烈建议用前台模式跑而不是直接start这样可以在终端直接看到启动日志有问题能立刻定位cd /data/zookeeper/app/current/bin ./zkServer.sh start-foreground正常情况下你会看到类似下面的输出ZooKeeper JMX enabled by default Using config: /data/zookeeper/app/current/bin/../conf/zoo.cfg 2024-xx-xx 12:00:01,123 [myid:] - INFO [main:QuorumPeerMain139] - Starting quorum peer 2024-xx-xx 12:00:05,789 [myid:] - INFO [main:ServerCnxnFactory123] - Using org.apache.zookeeper.server.NettyServerCnxnFactory as server connection factory 2024-xx-xx 12:00:06,123 [myid:] - INFO [main:ZooKeeperServer456] - Started server看到“Started server”就说明服务已经起来了CtrlC停掉前台进程。确认没问题后再改用后台方式运行./zkServer.sh start输出会提示ZooKeeper JMX enabled by default Using config: /data/zookeeper/app/current/bin/../conf/zoo.cfg Starting zookeeper ... STARTED如果你看到 STARTED 但进程稍后就没了说明启动过程中崩了。不要反复重启马上看日志tail -100 /data/zookeeper/logs/zookeeper.out4.2 用jps和端口确认进程服务是否真的在跑判断标准不是“STARTED”这几个字母而是两个硬指标进程存在、端口监听。jps -l | grep QuorumPeerMain正常会输出一行带进程ID的QuorumPeerMain信息。如果jps没装可以用psps -ef | grep zookeeper再看端口ss -lntp | grep 2181能看到java进程监听在2181端口就对了。如果端口被其他服务占用改配置文件里的clientPort或者先解决端口冲突。4.3 客户端连接验证与基础读写进程和端口都OK还不够最好用客户端连一次确认数据读写链路完好。执行./zkCli.sh -server 127.0.0.1:2181进入客户端交互后依次执行ls / create /install-test ok get /install-test set /install-test success get /install-test delete /install-test quit每一步输出如果都正常说明ZooKeeper安装已经没问题了。这里create的是持久节点测试完delete掉别在根节点下留垃圾数据。4.4 四字命令验证运行状态ZooKeeper支持四字命令通过nc发送单词查询状态。先确认nc装了yum install -y nmap-ncat然后echo stat | nc 127.0.0.1 2181 echo ruok | nc 127.0.0.1 2181stat会返回节点角色、连接数、数据版本等关键信息ruok正常返回imok。如果这两个命令没反应先检查zoo.cfg里的4lw.commands.whitelist是否把stat和ruok加进去了。我上面给的配置已经包含这两项。5. 从单机升级到伪分布式和集群5.1 为什么生产环境不建议单机单机ZooKeeper部署简单但它有一个本质问题单点。ZooKeeper的作用是帮分布式系统做协调和选主如果它自己挂了整个上层系统都可能受影响。生产环境最少三节点原因是ZooKeeper的选主遵循多数派原则3个节点挂1个还能继续工作2个节点挂1个就无法形成多数派所以集群至少3台。如果你是学习环境只有一台机器可以配置伪分布式如果有三台服务器就直接按后面的跨机器集群方式配。5.2 伪分布式一台机器模拟三个节点伪分布式本质是同一个Linux主机上跑三个ZooKeeper实例每个实例有独立的dataDir、clientPort和集群通信端口。步骤如下。在/data/zookeeper/app/current/conf目录下准备三份配置文件zoo1.cfg、zoo2.cfg、zoo3.cfg。以zoo1.cfg为例tickTime2000 initLimit10 syncLimit5 dataDir/data/zookeeper/data/node1 dataLogDir/data/zookeeper/logs/node1 clientPort2181 maxClientCnxns0 autopurge.snapRetainCount3 autopurge.purgeInterval24 admin.serverPort8081 server.1127.0.0.1:2888:3888 server.2127.0.0.1:2889:3889 server.3127.0.0.1:2890:3890zoo2.cfg和zoo3.cfg类似区别在于clientPort分别改成2182、2183admin.serverPort改成8082、8083dataDir/dataLogDir改成node2、node3注意三份配置文件里的server.1、server.2、server.3声明要完全一致然后创建三个myid文件mkdir -p /data/zookeeper/data/node{1,2,3} echo 1 /data/zookeeper/data/node1/myid echo 2 /data/zookeeper/data/node2/myid echo 3 /data/zookeeper/data/node3/myidmyid文件的内容必须和zoo.cfg中对应server.X的数字一致这是集群识别节点的依据。启动时指定配置文件/data/zookeeper/app/current/bin/zkServer.sh start /data/zookeeper/app/current/conf/zoo1.cfg /data/zookeeper/app/current/bin/zkServer.sh start /data/zookeeper/app/current/conf/zoo2.cfg /data/zookeeper/app/current/bin/zkServer.sh start /data/zookeeper/app/current/conf/zoo3.cfg三个实例都启动后查看每个实例的状态/data/zookeeper/app/current/bin/zkServer.sh status /data/zookeeper/app/current/conf/zoo1.cfg /data/zookeeper/app/current/bin/zkServer.sh status /data/zookeeper/app/current/conf/zoo2.cfg /data/zookeeper/app/current/bin/zkServer.sh status /data/zookeeper/app/current/conf/zoo3.cfg正常情况下三台中一台是Leader两台是Follower。5.3 跨机器集群配置要点如果你有三台服务器配置更简单。每台机器zoo.cfg中增加server.1192.168.1.11:2888:3888 server.2192.168.1.12:2888:3888 server.3192.168.1.13:2888:3888server.X后面的两个端口分别用于集群内部数据同步和Leader选举默认2888和3888。三台机器的dataDir下分别写入1、2、3到myid文件其余配置保持一致。跨机器部署时最常遇到的不是配置错误而是防火墙。不同厂商的Linux管理方式不一样但思路都一样放通2181、2888、3888端口的入站流量或者只在特定网段/IP之间放行。如果集群内节点之间互相无法通信日志里会反复出现Cannot open channel to X at election address ...排查优先级先确认端口通不通telnet/IP再确认防火墙策略最后看SELinux是否拦截。6. 用systemd实现开机自启与异常重启6.1 手写一个干净的Unit文件生产环境里我不建议把zkServer.sh start塞到rc.local里做开机自启太粗糙。用systemd托管是更规范的做法还能获得异常退出自动重启的能力。在 /etc/systemd/system/zookeeper.service 写入[Unit] DescriptionApache ZooKeeper Server Documentationhttps://zookeeper.apache.org Afternetwork.target [Service] Typesimple Userzookeeper Groupzookeeper EnvironmentJAVA_HOME/usr/lib/jvm/java-1.8.0-openjdk EnvironmentZOO_LOG_DIR/data/zookeeper/logs ExecStart/data/zookeeper/app/current/bin/zkServer.sh start-foreground ExecStop/bin/kill -TERM $MAINPID Restarton-failure RestartSec10 LimitNOFILE65536 [Install] WantedBymulti-user.target这里有几个点要解释Typesimple配合start-foreground是最直接的托管方式服务进程保持在systemd监控下。不要用start命令配TypeforkingZooKeeper脚本fork后的子进程PID记录和systemd的依赖逻辑容易配合不好停止服务时可能出现进程残留。ExecStop用/bin/kill -TERM $MAINPID而不是zkServer.sh stop因为start-foreground方式下主进程就是当前这个Java进程直接用systemd的MainPID信号终止最干净。User/Group建议用你创建的zookeeper用户前提是数据目录和应用目录的属主都改成zookeeper。JAVA_HOME必须显式指定因为systemd环境不读取/etc/profile。LimitNOFILE调高文件描述符上限避免连接数大时出现too many open files。6.2 启用并验证systemctl daemon-reload systemctl enable --now zookeeper systemctl status zookeeper如果你之前手动启动过ZooKeeper记得先停掉再启用systemd。检查开机自启状态systemctl is-enabled zookeeper输出enabled说明开机自启已配置。然后重启机器验证一次重启后看进程是否自动拉起来。这一步虽然费几分钟但能避免服务器重启后服务没起导致的事故。还有一个容易踩的细节目录授权一定要在启systemd之前做好否则会看到权限不足的报错。如果之前手动启动已经生成了root属主的日志或PID文件执行一遍chown -R zookeeper:zookeeper /data/zookeeper再启动systemd。7. 安装期高频故障与排查实录我在帮同事排查ZooKeeper安装问题的时候发现很多情况反反复复就那么几个原因。下面把最常见的列出来每个都附上排查路径。现象根因排查/解决启动报“找不到或无法加载主类QuorumPeerMain”下载了不带bin的源码包重新下载apache-zookeeper-x.x.x-bin.tar.gz启动报UnsupportedClassVersionErrorJDK版本低于ZooKeeper要求java -version确认版本换成JDK8/11显示STARTED但进程消失配置或数据目录权限问题看zookeeper.out日志重点找ERROR/WARN端口被占用Address already in use2181或AdminServer的8080被占用ss -lntp确认占用进程改clientPort或admin.serverPort客户端一直Connection refused服务没起来或防火墙拦截先jps/ss确认本地状态再查防火墙策略/tmp/zookeeper目录下数据丢失用了默认dataDir修改dataDir到持久化目录已有数据迁移过去集群状态一直没Leader节点数不足或选举端口不通确认节点数3、防火墙放行2888/3888、myid正确快照文件堆积占用磁盘autopurge.purgeInterval0设置清理间隔保留最近几个快照客户端写数据报connection closedmaxClientCnxns超限视场景调整为0或适当放大挑两个细讲。7.1 显示STARTED但进程马上消失遇到这个先不要反复重启直接打开日志tail -200 /data/zookeeper/logs/zookeeper.out如果是3.7.x版本你可能会看到类似ERROR [main:ZooKeeperServerxxx] - Unable to load database from /data/zookeeper/data这类问题多半是之前异常退出导致快照和数据目录状态不一致或者目录里残留了异常文件。处理办法先备份data目录然后把dataDir下的version-2目录移走让ZooKeeper重新初始化。注意只有确认数据不重要或者已经从备份恢复之后才做这一步。7.2 客户端连接成功但一执行写操作就断连这个坑我在测试环境踩过后来查到是maxClientCnxns默认60的限制测试脚本批量建连接时会触发。日志里会出现大量连接被拒绝的记录。解决办法就是按前面配置改成0或者在zoo.cfg里明确写一个符合预期的连接上限。还有一个容易忽略的点如果你在conf目录下同时存在多个配置文件且用zkServer.sh时不指定文件名脚本默认加载的始终是zoo.cfg。伪分布式启动多个实例时一定记得在启动命令里把对应的配置文件路径带上否则三个实例启动的是同一个服务配置端口瞬间冲突。8. 安装完成后还要处理的三件事服务能跑起来、客户端能读写只能说明“安装完成”离“用得放心”还差几步。8.1 日志和快照清理策略要落地ZooKeeper运行时会在dataLogDir和dataDir下产生大量文件尤其是事务日志增长很快。依赖autopurge定期清理是一种方式但如果你不想在zoo.cfg里开自动清理比如想人工控制归档可以用crontab做统一调度。比如每天凌晨3点执行0 3 * * * find /data/zookeeper/logs -type f -name log.* -mtime 7 -delete /dev/null 21快照文件可以用zkCleanup.sh这个工具/data/zookeeper/app/current/bin/zkCleanup.sh /data/zookeeper/data 3保留最近3份快照多余的直接删掉。清理策略两条路至少选一条别让磁盘被历史文件堆满。8.2 把ZooKeeper纳入监控ZooKeeper的节点角色和连接数直接影响上层组件能不能正常选主建议至少把stat、mntr这些四字命令接入监控系统定期采集。比如手动看一次监控指标echo mntr | nc 127.0.0.1 2181输出里zk_server_state表示当前节点是leader还是followerzk_num_alive_connections表示连接数zk_outstanding_requests表示未处理请求数。这几个指标异常时要告警。很多公司把ZooKeeper装完就忘了等Kafka或HBase出问题才想起来看它那时候通常已经晚了。8.3 记录版本和变更信息把安装过程中用到的ZooKeeper版本包、JDK版本、配置文件改动点、数据目录、端口规划写成一个简短的部署文档。下次升级或者排查问题时这份记录比什么都有用。特别是端口规划单机、伪分布式、集群三套配置的端口不一样如果不记下来后面的人接手时很难搞清楚为什么同一台机器上有那么多218x端口。按照上面的流程走完单机、伪分布式、集群三种形态都能跑起来systemd自启也有了高频的坑也算提前帮你排了一轮。再到后面遇到ZooKeeper相关的问题排查链路的起点就不会是“装了个假ZooKeeper”了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑