Spring Boot集成zookeeper快速入门Demo

news2024/11/24 15:03:30

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);
    }
}

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

代码仓库

  • https://github.com/Harries/springboot-demo

4.测试

启动Spring Boot应用

创建节点

  • 访问http://127.0.0.1:8088/createNode?path=/hblog&data=test
  • 访问http://127.0.0.1:8088/createNode?path=/hblog/node1&data=node1

查看创建的节点



 

5.引用

  • Spring Boot集成zookeeper快速入门Demo | Harries Blog™
  • ZooKeeper 介绍 — zookeeper入门 文档

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1669921.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

webAPIs第二天

事件监听 什么是事件&#xff1f; 事件是在编程时系统内发生的动作或者发生的事情 比如用户在网页上单击一个按钮 什么是事件监听&#xff1f; 就是让程序检测是否有事件产生&#xff0c;一旦有事件触发&#xff0c;就立即调用一个函数做出响应&#xff0c;也称为 绑定事件或者…

常用的30个linux命令总结

1、常用30个命令总结 2、具体参数用法参考网站&#xff1a; Linux命令大全(手册) – 真正好用的Linux命令在线查询网站

Linux提权--第三方软件MYSQL数据库提权(WEB+本地)

免责声明:本文仅做技术交流与学习,非法搞事后果自负... 目录 靶场镜像: 过程: 手工: 下载mysql udf poc 进行编译. 进入数据库进行UDF导出 下载(上传) 创建do_system函数调用 探针(./LinEnum.sh),查找suid权限. 配合使用find调用执行 工具: 过程: 外连不上? 隧道出…

【网络安全入门】你必须要有的学习工具(附安装包)零基础入门到进阶,看这一篇就够了!

工欲善其事必先利其器 在新入门网络安全的小伙伴而言。这些工具你必须要有所了解。本文我们简单说说这些网络安全工具吧&#xff01; Web安全类 Web类工具主要是通过各种扫描工具&#xff0c;发现web站点存在的各种漏洞如sql注入、xss等。从而获取系统权限&#xff0c;常用的…

Node.js版本管理工具nvm安装

1.下载nvm https://github.com/coreybutler/nvm-windows/releaseshttps://github.com/coreybutler/nvm-windows/releases 2.安装nvm 双击打开下载好的压缩包解压出的文件 目录中不要有中文 这个是配置切换node版本后的存储位置 然后一路下一步就行了 3.安装并使用node 安装…

vue uniapp 小程序 判断日期是今天(显示时分秒)、昨天、本周的周几、超出本周显示年月日

效果图&#xff1a; util.js /*** 转换时间*/ const messageFormat (datetime) >{ let result "";let currentTime new Date();if(isToday(datetime)){result datetime.substring(11,16);}else if(isYesterday(datetime)){result "昨天";}else if(…

代码随想录阅读笔记-动态规划【爬楼梯】

题目 假设你正在爬楼梯。需要 n 阶你才能到达楼顶。 每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢&#xff1f; 注意&#xff1a;给定 n 是一个正整数。 示例 1&#xff1a; 输入&#xff1a; 2输出&#xff1a; 2解释&#xff1a; 有两种方法可以爬到楼…

2024年小程序视频如何下载到手机

在2024年的数字时代&#xff0c;小程序已成为我们生活中不可或缺的一部分&#xff0c;它们如同星辰般点缀在我们的日常之中&#xff0c;为我们带来便捷与乐趣。然而&#xff0c;你是否曾因网络的不稳定而错失了那些精彩绝伦的小程序视频&#xff1f;是否曾在离线的时刻&#xf…

面试高频知识点:Java互联网大厂高频面试题(持续收录)

文章目录 前言一、Java基础题1、Java语言的三大特性2、JDK 和 JRE 有什么区别3、Java基本数据类型及其封装类4、说明一下public static void main(String args[])这段声明里关键字的作用5、java的数据结构有哪些&#xff1f;6、抽象类和接口的区别?7、 与 equals 的区别8、Str…

导航app为什么知道还有几秒变绿灯?

在使用地图导航app行驶至信号灯的交叉路口时&#xff0c;这些应用程序会贴心地告知用户距信号灯变化还有多少秒&#xff0c;无论是即将转为绿灯还是红灯。这一智能化提示不仅使得驾驶员能适时做好起步或刹车的准备&#xff0c;有效缓解了因等待时间不确定而产生的焦虑情绪&…

邮箱API发送邮件调试的方法?有哪些限制?

邮箱API发送邮件调试的好处&#xff1f;如何正确调试邮箱API&#xff1f; 使用邮箱API发送邮件是一个常见的需求。然而&#xff0c;当遇到发送失败、内容错误或格式问题时&#xff0c;如何进行有效的调试就显得尤为重要。本文将为您介绍一些邮箱API发送邮件调试的方法&#xf…

【联通官网及APP注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞 …

【2024】前端,该卷什么呢?

✅顺便推个机会&#xff0c;技术大厂&#xff0c;部门捞人&#xff0c;前后端可投。 2024ChatGPT 的炸裂式发展&#xff0c;很多大佬都亲自入场整活儿&#xff0c;你不得不说&#xff0c;人工智能时代的未来已来&#xff0c;大势所趋&#xff0c;不可阻挡。随着生成式AI的迅猛发…

红队攻防|拿下服务器root权限

0x00前言 分享一个简单的项目&#xff0c;小有坎坷但仍旧几乎畅通无阻的最终拿下root权限。 先说重要的事情&#xff1a; 如有漏码少码导致能定位目标请各位师傅手下留情&#xff0c;后台留言提醒必有红包重谢&#xff01; 0x01信息收集 过程略&#xff0c;收集到目标的主站…

[QT] 断点调试

目录 一 设置断点 二 调试窗口信息 2.1 默认窗口 2.2 详细窗口属性 三 调试方法和技巧 一 设置断点 在QtCreator中我们有两种方式添加断点。 用鼠标直接点击代码编辑窗口中的某一行按下F9添加/取消断点(操作的是当前鼠标光标所在的代码行) 二 调试窗口信息 2.1 默认窗…

Python深度学习基于Tensorflow(2)Tensorflow基础

文章目录 基本操作数据转换和数据生成操作形状数据提取和保存变量Numpy和Tensorflow的比较 计算图静态图动态图自动图 自动微分使用Tensorflow 实现回归 首先是Tensorflow的安装&#xff0c;由于可能会出现版本冲突&#xff0c;最好在conda环境安装&#xff0c;同时&#xff0c…

iOS 面试题总结(可能是最全的!!!)

如有错误 请及时在评论中指出 文章将不定期更新 1. objc_msgForward是干什么的&#xff0c;如果直接调用会发生什么&#xff1f; 作用&#xff1a;这个函数是IMP类型&#xff08;方法实现的内存地址也就是函数指针&#xff09;&#xff0c;用于消息转发&#xff0c;当向一个对…

【Linux】多线程相关第一篇:从进程谈起理解线程概念

文章目录 为什么需要线程初步认识Linux线程Linux操作系统的线程为什么要这么设计进程、线程关系梳理理解线程是CPU调度的基本单位简单认识多执行流如何划分代码 为什么需要线程 线程和进程的关系密不可分。 操作系统教材对于进程、线程的概念是这样描述的&#xff1a; 进程是…

Python-VBA函数之旅-super函数

目录 一、super函数的常见应用场景 二、super函数使用注意事项 三、如何用好super函数&#xff1f; 1、super函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、su…

JS解密之新js加密实战(二)

前言 上次发了一篇关于新加密的&#xff0c;只解了前边两层&#xff0c;这中间家里各种事情因素影响&#xff0c;没有继续进一步研究&#xff0c;今天百忙之中抽空发布第二篇&#xff0c;关于其中的一小段加密片段&#xff0c;我认为分割成多个小片段是更容易被理解的。逻辑相…