Spring Boot集成zookeeper快速入门Demo

1.什么是zookeeper?

Zookeeper 是一个开源的分布式协调服务,目前由 Apache 进行维护。Zookeeper 可以用于实现分布式系统中常见的发布/订阅、负载均衡、命令服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能。它具有以下特性:

  • 顺序一致性:从一个客户端发起的事务请求,最终都会严格按照其发起顺序被应用到 Zookeeper 中;
  • 原子性:所有事务请求的处理结果在整个集群中所有机器上都是一致的;不存在部分机器应用了该事务,而另一部分没有应用的情况;
  • 单一视图:所有客户端看到的服务端数据模型都是一致的;
  • 可靠性:一旦服务端成功应用了一个事务,则其引起的改变会一直保留,直到被另外一个事务所更改;
  • 实时性:一旦一个事务被成功应用后,Zookeeper 可以保证客户端立即可以读取到这个事务变更后的最新状态的数据。

2.zookeeper环境搭建

docker-compose-zookeeper.yaml

复制代码
version: '3'
services:
  zookeeper:
    image: zookeeper:3.7.0
    container_name: zookeeper
    restart: unless-stopped
    volumes:
      - "./zookeeper/data:/data"
      - "./zookeeper/datalog:/datalog"
    ports:
      - "2181:2181"

  # webui
  zookeeper-webui:
    image: tobilg/zookeeper-webui
    container_name: zookeeper-webui
    restart: unless-stopped
    environment:
      ZK_DEFAULT_NODE: zookeeper:2181
    depends_on:
      - zookeeper
    links:
      - zookeeper
    ports:
      - "8089:8080"

run

复制代码
docker-compose -f docker-compose-zookeeper.yml -p zookeeper up -d

可视化界面访问地址:http://ip地址:8089 ,输入 {宿主主机ip}:2181/进入

桌面可视化工具PrettyZoo: GitHub - vran-dev/PrettyZoo: 😉 Pretty nice Zookeeper GUI, Support Win / Mac / Linux Platform

3.代码工程

实验目标:实现在zookeeper创建节点

pom.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>springboot-demo</artifactId>
        <groupId>com.et</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>zookeeper</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Apache Zookeeper-->
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.14</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    </dependencies>
</project>

zk配置类

复制代码
package com.et.zookeeper.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooKeeper;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.concurrent.CountDownLatch;
import java.util.logging.Logger;

@Configuration
@Slf4j
public class ZookeeperConfig {

    @Value("${zookeeper.address}")
    private String connectString;

    @Value("${zookeeper.timeout}")
    private int timeout;

    @Bean(name = "zkClient")
    public ZooKeeper zkClient() {
        ZooKeeper zooKeeper = null;
        try {
            final CountDownLatch countDownLatch = new CountDownLatch(1);
            //After the connection is successful, the watcher will be called back to monitor. This connection operation is asynchronous. After the new statement is executed, the subsequent code will be called directly.
            // Multiple service addresses can be specified: 127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183
            zooKeeper = new ZooKeeper(connectString, timeout, new Watcher() {
                @Override
                public void process(WatchedEvent event) {
                    if (Event.KeeperState.SyncConnected == event.getState()) {
                        //If the response event from the server is received, the connection is successful
                        countDownLatch.countDown();
                    }
                }
            });
            countDownLatch.await();
            log.info("【init zooKeeper connect....】={}", zooKeeper.getState());

        } catch (Exception e) {
            log.error("init ZooKeeper connect error....】={}", e);
        }
        return zooKeeper;
    }
}

zk客户端

复制代码
package com.et.zookeeper.api;

import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.List;

@Component
@Slf4j
public class ZkApi {

    @Autowired
    private ZooKeeper zkClient;

    /**
     * check node is exist
     *
     * @param path
     * @param needWatch
     * @return
     */
    public Stat exists(String path, boolean needWatch) {
        try {
            return zkClient.exists(path, needWatch);
        } catch (Exception e) {
            log.error("【 node exception】{},{}", path, e);
            return null;
        }
    }

    /**
     * check node is exist and set watcher
     * @param path
     * @param watcher
     * @return
     */
    public Stat exists(String path, Watcher watcher) {
        try {
            return zkClient.exists(path, watcher);
        } catch (Exception e) {
            log.error("【node  exception】{},{}", path, e);
            return null;
        }
    }

    /**
     * create persist node
     *
     * @param path
     * @param data
     */
    public boolean createNode(String path, String data) {
        try {
            zkClient.create(path, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            return true;
        } catch (Exception e) {
            log.error("【create persist node exception】{},{},{}", path, data, e);
            return false;
        }
    }

    /**
     * update persist node
     *
     * @param path
     * @param data
     */
    public boolean updateNode(String path, String data) {
        try {
            //The data version of zk starts counting from 0. If the client passes -1, it means that the zk server needs to be updated based on the latest data. If there is no atomicity requirement for the update operation of zk's data node, you can use -1.
            //The version parameter specifies the version of the data to be updated. If the version is different from the real version, the update operation will fail. Specify version as -1 to ignore the version check.
            zkClient.setData(path, data.getBytes(), -1);
            return true;
        } catch (Exception e) {
            log.error("【update persist node exception】{},{},{}", path, data, e);
            return false;
        }
    }

    /**
     * delete persist node
     *
     * @param path
     */
    public boolean deleteNode(String path) {
        try {
            //The version parameter specifies the version of the data to be updated. If the version is different from the real version, the update operation will fail. Specify version as -1 to ignore the version check.
            zkClient.delete(path, -1);
            return true;
        } catch (Exception e) {
            log.error("【delete persist node exception】{},{}", path, e);
            return false;
        }
    }

    /**
     * Get the child nodes of the current node (excluding grandchild nodes)
     *
     * @param path
     */
    public List<String> getChildren(String path) throws KeeperException, InterruptedException {
        List<String> list = zkClient.getChildren(path, false);
        return list;
    }

    /**
     * Get the value of the specified node
     *
     * @param path
     * @return
     */
    public String getData(String path, Watcher watcher) {
        try {
            Stat stat = new Stat();
            byte[] bytes = zkClient.getData(path, watcher, stat);
            return new String(bytes);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}

zk监听器

复制代码
package com.et.zookeeper.api;

import lombok.extern.slf4j.Slf4j;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;

@Slf4j
public class WatcherApi implements Watcher {

    @Override
    public void process(WatchedEvent event) {
        log.info("【Watcher event】={}", event.getState());
        log.info("【Watcher  path】={}", event.getPath());
        log.info("【Watcher type】={}", event.getType()); //  three type: create,delete,update
    }
}

application.yaml

复制代码
server:
  port: 8088
zookeeper:
  address: 127.0.0.1:2181
  timeout: 4000

controller

复制代码
package com.et.zookeeper.controller;

import com.et.zookeeper.api.ZkApi;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.Map;

@RestController
@Slf4j
public class HelloWorldController {
    @Autowired
    private ZkApi zkApi;

    @GetMapping(value = "createNode")
    public boolean createNode(String path, String data) {
        log.debug("ZookeeperController create node {},{}", path, data);
        return zkApi.createNode(path, data);
    }
}

以上只是一些关键代码,所有代码请参见下面代码仓库

代码仓库

4.测试

启动Spring Boot应用

创建节点

查看创建的节点

​

5.引用

相关推荐
code_slave(码畜)10 小时前
微服务架构落地:基础服务 —— 报表服务(中篇:元数据、查询引擎、缓存与权限落地)
spring boot·spring cloud·缓存·微服务·架构
ZealSinger11 小时前
Boot4挂起函数丢traceId怎么修
spring boot·kotlin·协程·可观测性
code_slave(码畜)11 小时前
微服务架构落地:基础服务 —— 报表服务(AI 集成篇:AI 增强报表能力)
人工智能·spring boot·spring cloud·微服务·架构
code_slave(码畜)12 小时前
微服务架构落地:公共中间件层总览——不承载业务,只承载稳定性
spring boot·spring cloud·微服务·中间件·架构
谢亮_vipxieliang14 小时前
Spring Boot 自动配置原理:从 @SpringBootApplication 到自定义 Starter
java·spring boot·后端
AI人工智能+电脑小能手15 小时前
Java 企业级工具类全家桶-68-HTTP请求工具类
spring boot·网络请求·http请求·resttemplate·jdk 17·java工具类·企业级开发
paopaokaka_luck17 小时前
非遗文物数字化小程序(AI非遗问答、ONNX图像识别、协同过滤推荐、ECharts数据分析、非遗知识浏览与互动、文创商城订单闭环、文化活动报名签到、社区交流)
javascript·spring boot·mysql·数据分析·echarts·mybatis
EatFan19 小时前
Spring Boot 4 迁移避坑清单:Jackson 3、starter 拆分与最低 JDK 口径核对(含若依/芋道/CRMEB 升级对照)
java·数据库·spring boot·spring boot 4·java 21·jakarta ee 11·jackson 3
ly768919 小时前
Spring Boot 集成 Redis 企业级实践:连接池、序列化与缓存穿透雪崩的工程化防御
spring boot·redis·缓存·缓存穿透·布隆过滤器·lettuce 连接池
Wx-bishekaifayuan20 小时前
springboot陨石鉴收系统96265-计算机课程设计、毕业设计
java·vue.js·spring boot·后端·python·spring·课程设计