zookeeper -- 搭建单机和集群环境

这篇文章需要你有一定的 zookeeper 知识

zookeeper 部署有两种模式:单机模式和集群模式。

单机模式

在 linux 服务器上解压 zookeeper 的压缩包,然后在安装目录创建一个 data 目录,用来配置 dataDir 配置项。

把 conf 目录中的 zoo_sample.cfg 文件复制一份改名为 zoo.cfg(zookeeper 默认配置文件名就是这个),然后修改 zoo.cfg 如下:

ini 复制代码
# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial 
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between 
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just 
# example sakes.
dataDir=/root/software/zookeeper/data
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the 
# administrator guide before turning on autopurge.
#
# https://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1
​
## Metrics Providers
#
# https://prometheus.io Metrics Exporter
#metricsProvider.className=org.apache.zookeeper.metrics.prometheus.PrometheusMetricsProvider
#metricsProvider.httpHost=0.0.0.0
#metricsProvider.httpPort=7000
#metricsProvider.exportJvmInfo=true

只要修改 dataDir 配置项即可,其他不变。

这里有个小插曲,启动 zookeeper 的时候报找不到 JAVA_HOME,但是检查一遍确实已经配置了 JAVA_HOME。

python 复制代码
$ sh zkServer.sh start
zkServer.sh: 73: /root/software/zookeeper/bin/zkEnv.sh: [[: not found
-p: not found
java is /root/software/jdk8/bin/java
Error: JAVA_HOME is not set and java could not be found in PATH.

这个问题是 zkEnv.sh 文件有个语法问题,参考:codeantenna.com/a/Y0ESznahn...,用 bash 代替 sh 来启动。

sql 复制代码
$ bash zkServer.sh start
ZooKeeper JMX enabled by default
Using config: /root/software/zookeeper/bin/../conf/zoo.cfg
Starting zookeeper ... FAILED TO START

这次没有报之前的错误了,但是还是启动失败,查看 zookeeper 的日志文件发现端口被占用了。

less 复制代码
2023-10-11 23:00:18,106 [myid:] - ERROR [main:o.a.z.s.ZooKeeperServerMain@86] - Unable to start AdminServer, exiting abnormally
org.apache.zookeeper.server.admin.AdminServer$AdminServerException: Problem starting AdminServer on address 0.0.0.0, port 8080 and command URL /commands
    at org.apache.zookeeper.server.admin.JettyAdminServer.start(JettyAdminServer.java:199)
    at org.apache.zookeeper.server.ZooKeeperServerMain.runFromConfig(ZooKeeperServerMain.java:155)
    at org.apache.zookeeper.server.ZooKeeperServerMain.initializeAndRun(ZooKeeperServerMain.java:113)
    at org.apache.zookeeper.server.ZooKeeperServerMain.main(ZooKeeperServerMain.java:68)
    at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(QuorumPeerMain.java:141)
    at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain.java:91)
Caused by: java.io.IOException: Failed to bind to /0.0.0.0:8080
    at org.eclipse.jetty.server.ServerConnector.openAcceptChannel(ServerConnector.java:349)
    at org.eclipse.jetty.server.ServerConnector.open(ServerConnector.java:310)
    at org.eclipse.jetty.server.AbstractNetworkConnector.doStart(AbstractNetworkConnector.java:80)
    at org.eclipse.jetty.server.ServerConnector.doStart(ServerConnector.java:234)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
    at org.eclipse.jetty.server.Server.doStart(Server.java:401)
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:73)
    at org.apache.zookeeper.server.admin.JettyAdminServer.start(JettyAdminServer.java:190)
    ... 5 common frames omitted
Caused by: java.net.BindException: 地址已在使用
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:438)
    at sun.nio.ch.Net.bind(Net.java:430)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:225)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.eclipse.jetty.server.ServerConnector.openAcceptChannel(ServerConnector.java:344)
    ... 12 common frames omitted
Unable to start AdminServer, exiting abnormally

从 zookeeper 3.5 开始,zookeeper 内嵌了一个 Jetty 服务器叫做 AdminServer,它默认监听 8080 端口,而我的服务器的 8080 端口已经被使用了,所以解决方案是修改 AdminServer 监听的端口号。在配置文件 zoo.cfg 中添加配置:

ini 复制代码
admin.serverPort=8888

AdminServer 相关配置项如下:

  • admin.enableServer:启用或禁用 AdminServer,默认启用
  • admin.serverAddress:Jetty 服务器监听的 IP 地址,默认是 0.0.0.0
  • admin.serverPort:Jetty 服务器监听的端口号,默认是 8080
  • admin.idleTimeout:连接在发送或接收数据之前可以等待的最大空闲时间
  • admin.commandURL:上下文路径,默认值 "/commands"

集群模式

zookeeper 的集群模式最少要三台服务器,相比与单机模式,集群模式需要额外添加少量配置,如果你只有一台服务器,推荐使用 Docker 来部署(使用 Docker 甚至不用考虑 AdminServer 端口占用的问题)。

首先创建一个 Dockerfile 文件构建 zookeeper 镜像:

bash 复制代码
# 我自己构建的基于 ubuntu 的包含 jdk 环境的镜像
FROM swr.cn-south-1.myhuaweicloud.com/monkeybrain/jdk-ubuntu:v2
​
# 拷贝 zookeeper 压缩包到镜像
COPY apache-zookeeper-3.9.1-bin.tar.gz /usr/zookeeper/
​
# 指定工作目录
WORKDIR /usr/zookeeper
RUN tar -zxvf apache-zookeeper-3.9.1-bin.tar.gz
RUN mv apache-zookeeper-3.9.1-bin zookeeper-3.9
​
# 设置匿名卷
VOLUME [ "/usr/zookeeper/zookeeper-3.9/data", "/usr/zookeeper/zookeeper-3.9/conf", "/usr/zookeeper/zookeeper-3.9/logs" ]
​
WORKDIR /usr/zookeeper/zookeeper-3.9/bin
# 这里注意要前台运行 zookeeper,不然 docker 容器会自动退出
CMD ["bash", "zkServer.sh", "start-foreground"]

构建镜像

shell 复制代码
$ docker build -t swr.cn-south-1.myhuaweicloud.com/monkeybrain/myzookeeper:v3 .

先启动单机 zookeeper 试一试,zoo.cfg 文件如下:

ini 复制代码
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/usr/zookeeper/zookeeper-3.9/data
clientPort=2181

启动容器

shell 复制代码
$ docker run --name zookeeper --rm -v /d/IT/docker/zookeeper/conf:/usr/zookeeper/zookeeper-3.9/conf -v /d/IT/docker/zookeeper/logs:/usr/zookeeper/zookeeper-3.9/logs -p 2181:2181 swr.cn-south-1.myhuaweicloud.com/monkeybrain/myzookeeper:v3

在本机运行 zkCli.cmd 连接 zookeeper 服务器

ruby 复制代码
$ zkCli.cmd

连接成功

csharp 复制代码
[zk: localhost:2181(CONNECTED) 1] ls /
[zookeeper]

然后开始部署 3 台服务器的 zookeeper 集群,使用 docker compose 来管理三个 zookeeper 容器,docker-compose.yml 文件如下:

bash 复制代码
version: '3'
​
services:
  zoo1:
    image: swr.cn-south-1.myhuaweicloud.com/monkeybrain/myzookeeper:v3
    container_name: zoo1
    ports:
      - "2181:2181"
      - "8081:8080"
    volumes:
      - /d/IT/docker/zookeeper/server1/conf:/usr/zookeeper/zookeeper-3.9/conf
      - /d/IT/docker/zookeeper/server1/data:/usr/zookeeper/zookeeper-3.9/data
      - /d/IT/docker/zookeeper/server1/logs:/usr/zookeeper/zookeeper-3.9/logs
    networks:
      - zookeeper
  
  zoo2:
    image: swr.cn-south-1.myhuaweicloud.com/monkeybrain/myzookeeper:v3
    container_name: zoo2
    ports:
      - "2182:2181"
      - "8082:8080"
    volumes:
      - /d/IT/docker/zookeeper/server2/conf:/usr/zookeeper/zookeeper-3.9/conf
      - /d/IT/docker/zookeeper/server2/data:/usr/zookeeper/zookeeper-3.9/data
      - /d/IT/docker/zookeeper/server2/logs:/usr/zookeeper/zookeeper-3.9/logs
    depends_on:
      - zoo1
    networks:
      - zookeeper
​
  zoo3:
    image: swr.cn-south-1.myhuaweicloud.com/monkeybrain/myzookeeper:v3
    container_name: zoo3
    ports:
      - "2183:2181"
      - "8083:8080"
    volumes:
      - /d/IT/docker/zookeeper/server3/conf:/usr/zookeeper/zookeeper-3.9/conf
      - /d/IT/docker/zookeeper/server3/data:/usr/zookeeper/zookeeper-3.9/data
      - /d/IT/docker/zookeeper/server3/logs:/usr/zookeeper/zookeeper-3.9/logs
    depends_on:
      - zoo2
    networks:
      - zookeeper
  
networks:
  zookeeper:
   external: true

这里我给每个 zookeeper 服务器都创建了一个文件夹,分别是 server1、server2、server3,里面的 conf 文件夹表示配置文件目录,data 文件夹表示存储快照目录,logs 文件夹表示日志文件目录。

在每个 conf 文件夹中创建 zoo.cfg 文件,其中 server1/conf/zoo.cfg 文件如下:

ini 复制代码
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/usr/zookeeper/zookeeper-3.9/data
clientPort=2181
​
server.1=0.0.0.0:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

server2/conf/zoo.cfg 文件如下:

ini 复制代码
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/usr/zookeeper/zookeeper-3.9/data
clientPort=2181
​
server.1=zoo1:2888:3888
server.2=0.0.0.0:2888:3888
server.3=zoo3:2888:3888

server3/conf/zoo.cfg 文件如下:

ini 复制代码
tickTime=2000
initLimit=5
syncLimit=2
dataDir=/usr/zookeeper/zookeeper-3.9/data
clientPort=2181
​
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=0.0.0.0:2888:3888

server.x 表示三个 zookeeper 服务器,它的值分三部分,其中第一部分表示 IP 地址,第二部分是一个端口号,表示 zookeeper 服务器之间交互的端口号,第三部分是一个端口号,表示 zookeeper 服务器之间选举时用的端口号。在 IP 地址部分,如果表示当前主机则用 0.0.0.0(别用 localhost),如果是其他的 zookeeper 服务器则用 docker-compose.yml 文件中 container_name 的值。

server.x 中的 x 用来标识服务器,server.x 中的 x 需要和 data/myid 文件内容一致,服务器启动时会到 data 目录下找到这个 myid 文件,然后就知道自己是 zoo.cfg 配置文件中的 server.x 列表中的哪台服务器了。

如在 server1/data/ 中创建 myid 文件,文件中的内容是 1;在 server2/data/ 中创建 myid 文件,文件中的内容是 2;在 server3/data/ 中创建 myid 文件,文件中的内容是 3。

一切准备就绪后,在 docker-compose.yml 所在目录下执行 docker compose up -d 启动整个项目。

因为我们映射了 AdminServer 的端口号到主机,所以可以用 AdminServer 来验证集群状态。在浏览器中访问 http://localhost:8081/commands 查看所有可用命令列表。

其中 voting_view 可以看到集群中参与投票的成员。

可以看到是三个,而且 IP 地址和 zoo.cfg 配置文件对的上。

参考: zookeeper.apache.org/doc/r3.9.1

相关推荐
苹果醋33 分钟前
AI大模型竞赛升温:百度发布文心大模型4.5和X1
java·运维·spring boot·mysql·nginx
网安INF8 分钟前
CVE-2020-1938源码分析与漏洞复现(Tomcat 文件包含/读取)
java·网络·web安全·网络安全·tomcat·漏洞复现
nenchoumi311919 分钟前
UE5 学习系列(九)光照系统介绍
java·学习·ue5
江梦寻22 分钟前
软件工程教学评价
开发语言·后端·macos·架构·github·软件工程
张乔2430 分钟前
spring boot项目整合mybatis实现多数据源的配置
java·spring boot·多数据源
GzlAndy34 分钟前
Tomcat调优
java·tomcat
美好的事情能不能发生在我身上37 分钟前
苍穹外卖Day11代码解析以及深入思考
java·spring boot·后端·spring·架构
辉辉健身中43 分钟前
Maven入门(够用)
java·maven
星火飞码iFlyCode1 小时前
【无标题】
java·前端·人工智能·算法
不良手残1 小时前
Redisson + Lettuce 在 Spring Boot 中的最佳实践方案
java·spring boot·redis·后端