---
url: /diary/spring/zookeeper/index.md
description: Spring Cloud 学习笔记第二篇，使用 Docker 搭建 Zookeeper 服务注册中心，实现服务发现和注册。
---
## 1. docker搭建zookeeper

环境：centOS7

### a. 拉取 zookeeper 镜像

```shell
docker pull zookeeper	
```

### b. 部署

#### 1.将它部署在 `/usr/local/zookeeper` 目录下：

```
cd /usr/local && mkdir zookeeper && cd zookeeper
```

#### 2.创建data目录，用于挂载容器中的数据目录：

```shell
mkdir data	
```

#### 3.部署命令

```shell
docker run -d -e TZ="Asia/Shanghai" -p 2181:2181 -v $PWD/data:/data --name zookeeper --restart always zookeeper
```

```
-e TZ="Asia/Shanghai"   # 指定上海时区 
-d                      # 表示在一直在后台运行容器
-p 2181:2181            # 对端口进行映射，将本地2181端口映射到容器内部的2181端口
--name                  # 设置创建的容器名称
-v                      # 将本地目录(文件)挂载到容器指定目录；
--restart always        # 始终重新启动zookeeper
```

**查看容器启动情况：**

```shell
docker ps -a
```

#### 4.连接

**使用zk命令行客户端连接zk**

```shell
docker run -it --rm --link zookeeper:zookeeper zookeeper zkCli.sh -server zookeeper
```

说明：-server zookeeper是启动zkCli.sh的参数

#### 5.其他命令

```shell
# 查看zookeeper容器实例进程信息
docker top zookeeper

# 停止zookeeper实例进程
docker stop zookeeper

# 启动zookeeper实例进程
docker start zookeeper

# 重启zookeeper实例进程
docker restart zookeeper

# 查看zookeeper进程日志
docker logs -f zookeeper

# 杀死zookeeper实例进程
docker kill -s KILL zookeeper

# 移除zookeeper实例
docker rm -f -v zookeeper
```

### c. 集群方式安装

#### 1.安装docker-compose

```shell
curl -L https://github.com/docker/compose/releases/download/1.22.0/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
```

#### 2.配置docker-compose

编写配置文件，并将其命名为：`docker-compose.yml`（`docker-compose`默认配置文件名）

配置文件内容：

```yaml
version: '2'
services:
  zoo1:
    image: zookeeper
    restart: always
    container_name: zoo1
    ports:
      - "2181:2181"
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

  zoo2:
    image: zookeeper
    restart: always
    container_name: zoo2
    ports:
      - "2182:2181"
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888

  zoo3:
    image: zookeeper
    restart: always
    container_name: zoo3
    ports:
      - "2183:2181"
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888 server.2=zoo2:2888:3888 server.3=zoo3:2888:3888
```

> 此配置文件表示，Docker需要启动三个zookeeper实例，并将2181，2182，2183三个端口号映射到容器内的2181这个端口上。
> `ZOO_MY_ID`：表示zk服务的ID, 取值为1-255之间的整数，且必须唯一
> `ZOO_SERVERS`：表示zk集群的主机列表

#### 3.启动zookeeper集群

```shell
docker-compose up -d
```

> 该命令执行需要在`docker-compose`配置文件的目录下执行，结果如下：

```shell
[root@izbp13xko46hud9vfr5s94z conf]# docker-compose up -d 
Starting zoo1 ... done
Starting zoo2 ... done
Starting zoo3 ... done
[root@izbp13xko46hud9vfr5s94z conf]# 
```

#### 4.查看zookeeper集群实例

* **通过`docker ps`查看**

  ```shell
  [root@izbp13xko46hud9vfr5s94z ~]# docker ps
  CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  e53b4c838001 zookeeper "/docker-entrypoint.…" 4 minutes ago Up 44 seconds 2888/tcp, 0.0.0.0:2181->2181/tcp, 3888/tcp zoo1
  19282fb6f9b4 zookeeper "/docker-entrypoint.…" 4 minutes ago Up 44 seconds 2888/tcp, 3888/tcp, 0.0.0.0:2182->2181/tcp zoo2
  099b926fa2d3 zookeeper "/docker-entrypoint.…" 4 minutes ago Up 44 seconds 2888/tcp, 3888/tcp, 0.0.0.0:2183->2181/tcp zoo3
  ```

* **通过`docker-compose ps`查看**

  ```shell
  [root@izbp13xko46hud9vfr5s94z conf]# docker-compose ps 
  Name              Command               State                     Ports                   
  ------------------------------------------------------------------------------------------
  zoo1   /docker-entrypoint.sh zkSe ...   Up      0.0.0.0:2181->2181/tcp, 2888/tcp, 3888/tcp
  zoo2   /docker-entrypoint.sh zkSe ...   Up      0.0.0.0:2182->2181/tcp, 2888/tcp, 3888/tcp
  zoo3   /docker-entrypoint.sh zkSe ...   Up      0.0.0.0:2183->2181/tcp, 2888/tcp, 3888/tcp
  [root@izbp13xko46hud9vfr5s94z conf]# 
  ```

  > 注：这个命令需要在docker-compose配置文件下执行。

#### 5.管理docker-compose服务

```shell
# 停止docker-compose服务
docker-compose stop

# 启动docker-compose服务
docker-compose start 
# 重启docker-compose服务
docker-compose restart 
```

#### 6.查看zookeeper集群节点主从关系

```shell
[root@izbp13xko46hud9vfr5s94z conf]# docker exec -it zoo1 /bin/bash 
bash-4.4# ./bin/zkServer.sh status
ZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Mode: follower
bash-4.4#
```

## 2. 服务提供者子模块

### a. pom

```xml
<dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency><!-- 引入自己定义的api通用包，可以使用Payment支付Entity -->
            <groupId>org.mc.mycloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- SpringBoot整合zookeeper客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <!--先排除自带的zookeeper3.5.3-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加zookeeper3.4.9版本-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
```

### b. application.yml

```yaml
server:
  port: 8004

spring:
  application:
    name: cloud-provider-zookeeper
  cloud:
    zookeeper:
      connect-string: ***.***.***.***:2181 #zookeeper ip地址和端口号
```

### c. 主启动

```java
@SpringBootApplication
@EnableDiscoveryClient  //该注解 用于向使用consul 或者 zookeeper 作为注册中心时注册服务
public class ZookeeperMain8004 {
    public static void main(String[] args) {
        SpringApplication.run(ZookeeperMain8004.class, args);
    }
}
```

### d. 流程代码

```java
@RestController
@Slf4j
public class PaymentController {

    //查询8004 能不能进入到zookeeper 注册中心

    @Value("${server.port}")
    private String serverPort;


    @RequestMapping("/payment/zk")
    public String paymentZk() {
        return "springCloud whit zookeeper:" + serverPort + "\t" + UUID.randomUUID().toString();
    }
}
```

## 3. 消费者子模块

### a. pom

```xml
   <dependencies>
        <!-- SpringBoot整合Web组件 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- SpringBoot整合zookeeper客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
            <!--先排除自带的zookeeper-->
            <exclusions>
                <exclusion>
                    <groupId>org.apache.zookeeper</groupId>
                    <artifactId>zookeeper</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--添加zookeeper3.4.9版本-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.9</version>
        </dependency>
    </dependencies>
```

### b. application.yml

```yml
server:
  port: 80

spring:
  application:
    name: cloud-consumerzk-order

  cloud:
    zookeeper:
      connect-string: ***.***.***.***:2181 #zookeeper ip地址和端口号
```

### c. 主启动

```java
@SpringBootApplication
public class OrderZkMain80 {
    public static void main(String[] args) {
        SpringApplication.run(OrderZkMain80.class, args);
    }
}

```

### d. 开启负载均衡

```java
@Configuration
public class ApplicationContextConfig {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

}
```

### e. 流程代码

```java
@RestController
@Slf4j
public class OrderZkController {
    public static final String INVOKE_URI = "http://cloud-provider-zookeeper";


    @Resource
    private RestTemplate restTemplate;

    @GetMapping("consumer/payment/zk")
    public String paymentInfo() {
        String result = restTemplate.getForObject(INVOKE_URI + "/payment/zk", String.class);
        return result;
    }

}
```

## 4.总结

### a.zookeeper是临时还是持久节点？

零时

### b.版本依赖报错：

​ SpringBoot整合zookeeper客户端，先排除自带的zookeeper，再添加相应的版本。

```xml
<!-- SpringBoot整合zookeeper客户端 -->
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-zookeeper-discovery</artifactId>
    <!--先排除自带的zookeeper-->
    <exclusions>
        <exclusion>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<!--添加zookeeper3.4.9版本-->
<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.9</version>
</dependency>
```

### c.zookeeper和eureka的区别

单独的zookeeper配置，没有默认自我开启的保护机制。

配置相对eureka简单。

服务名称既spring配置文件的应用名称

```yml
spring:
  application:
    name: cloud-consumerzk-order #zookeeper和eureka 都使用此name作为服务名称
```
