一、安装

docker run -d --name zookeeper --privileged=true -p 2181:2181 -e TZ=“Asia/Shanghai” -v /opt/zookeeper/data:/data -v /opt/zookeeper/conf:/conf -v /opt/zookeeper/logs:/datalog zookeeper:3.5.7

检查服务状态

> docker exec -it zookeeper /bin/bash ./bin/zkServer.sh statusZooKeeper JMX enabled by default
Using config: /conf/zoo.cfg
Client port found: 2181. Client address: localhost.
Mode: standalone

使用本地客户端进入

docker exec -it zookeeper zkCli.sh
  • 注意关闭防火墙
> systemctl status firewalld.service● firewalld.service - firewalld - dynamic firewall daemonLoaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)Active: inactive (dead)Docs: man:firewalld(1)

二、推荐工具

  • PrettyZoo (https://github.com/vran-dev/PrettyZoo/releases)

三、编程实现

实现原理: 利用zk的临时顺序节点的特性,会随着后端服务的下线而自动剔除会话中的zk节点。第一步,程序启动成功后,手动注册到zk某个目录下;第二步、编写ZkListener,监听该zk目录下的节点的新增和移除事件;事件处理中,你需要把节点的内容解析出来,然后放到Map集合中,维护在线的节点列表。因为后面的代码中,很依赖于实时在线的节点列表。这里要求实时性,也就说,后端服务的下线,其他服务节点能够及时地捕捉得到,Map集合是动态且实时更新。

关于业务代码具体处理,在本文不会体现,后期会在websocket集群的实现中讲述到。

1、引入jar包

         <dependency><groupId>org.apache.curator</groupId><artifactId>curator-recipes</artifactId><version>4.0.1</version></dependency>

2、ZookeeperConfig配置

import lombok.extern.slf4j.Slf4j;
import org.apache.curator.RetryPolicy;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.CuratorFrameworkFactory;
import org.apache.curator.retry.ExponentialBackoffRetry;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Slf4j
@Configuration
public class ZookeeperConfig {@Value("${zk.url}")private String zkUrl;@Beanpublic CuratorFramework curatorFramework() {RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);CuratorFramework client = CuratorFrameworkFactory.newClient(zkUrl, retryPolicy);client.start();return client;}
}

application.yml

#ZK服务配置
zk:url: 192.168.80.226:2181

3、ZkListener 监听节点的变化(新增和删除)

import com.alibaba.fastjson.JSONObject;
import com.xxx.ws.test.util.ThreadUtils;
import com.xxx.ws.test.zookeeper.dto.ServerNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.ChildData;
import org.apache.curator.framework.recipes.cache.PathChildrenCache;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheEvent;
import org.apache.curator.framework.recipes.cache.PathChildrenCacheListener;
import org.springframework.stereotype.Service;import javax.annotation.PostConstruct;import static com.xhtech.ws.test.constants.Constants.MANAGE_PATH;@Slf4j
@Service
@RequiredArgsConstructor
public class ZkListener {private final CuratorFramework curatorFramework;@PostConstructpublic void init() throws Exception {// 订阅节点的增加和删除事件PathChildrenCache childrenCache = new PathChildrenCache(curatorFramework, MANAGE_PATH, true);PathChildrenCacheListener childrenCacheListener = new PathChildrenCacheListener() {@Overridepublic void childEvent(CuratorFramework client,PathChildrenCacheEvent event) throws Exception {ChildData data = event.getData();switch (event.getType()) {case CHILD_ADDED:processAdd(data);break;case CHILD_REMOVED:processRemove(data);break;case CHILD_UPDATED:break;default:log.debug("[PathChildrenCache]节点数据为空, path={}", data == null ? "null" : data.getPath());break;}}};childrenCache.getListenable().addListener(childrenCacheListener, ThreadUtils.getExecutor());log.info("Register zk watcher successfully!");childrenCache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);}/*** zk节点新增** @param data*/private void processAdd(ChildData data) {ServerNode serverNode = JSONObject.parseObject(data.getData(), ServerNode.class);log.info("监听器--新节点加入:{}", serverNode);}/*** zk节点删除** @param data*/private void processRemove(ChildData data) {ServerNode serverNode = JSONObject.parseObject(data.getData(), ServerNode.class);log.info("监听器--节点删除:{}", serverNode);}}

4、ZkService 节点的注册

import com.alibaba.fastjson.JSON;
import com.xxx.ws.test.zookeeper.dto.ServerNode;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.springframework.stereotype.Component;import java.nio.charset.StandardCharsets;
import java.util.List;import static com.xxx.ws.test.constants.Constants.MANAGE_PATH;
import static com.xxx.ws.test.constants.Constants.PATH_PREFIX;@Slf4j
@Component
@RequiredArgsConstructor
public class ZkService {private final CuratorFramework curatorFramework;public void registry(ServerNode serverNode) {try {//判断根节点是否存在if (this.checkNodeExists(MANAGE_PATH)) {this.createPersistentNode(MANAGE_PATH);}this.createNode(PATH_PREFIX, serverNode);} catch (Exception e) {log.error("操作zk出现异常", e);}}public boolean checkNodeExists(String path) throws Exception {Stat stat = curatorFramework.checkExists().forPath(path);return stat == null ? false : true;}public String createPersistentNode(String path) throws Exception {String pathRegistered = curatorFramework.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.PERSISTENT).forPath(path);return pathRegistered;}public String createNode(String prefix, ServerNode serverNode) throws Exception {byte[] payload = JSON.toJSONString(serverNode).getBytes(StandardCharsets.UTF_8);String pathRegistered = curatorFramework.create().creatingParentsIfNeeded().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(prefix, payload);return pathRegistered;}public List<String> listNodes(String path) throws Exception {List<String> nodeList = curatorFramework.getChildren().forPath(path);return nodeList;}public void removeNode(String path) throws Exception {curatorFramework.delete().forPath(path);}
}

5、ServerNode实体

import lombok.Builder;
import lombok.Data;@Data
@Builder
public class ServerNode {//worker 的macprivate String mac;//Netty 服务 IPprivate String host;//Netty 服务 端口private Integer port;}
  • 常量,定义zk节点的目录与临时节点的前缀。
    public static final String MANAGE_PATH = "/im/nodes";public static final String PATH_PREFIX = MANAGE_PATH + "/seq-";

测试入口

import cn.hutool.core.date.DateUtil;
import com.xxx.ws.test.zookeeper.ZkService;
import com.xxx.ws.test.zookeeper.dto.ServerNode;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;@RestController
@RequiredArgsConstructor
public class ZookeeperApiController {private final ZkService zkService;@GetMapping("/registry/{host}")public ResponseEntity<?> registry(@PathVariable(value = "host") String host) {zkService.registry(ServerNode.builder().host(host).build());return ResponseEntity.ok(DateUtil.now());}
}

四、测试结果

除了主动注册外,随着服务节点的下线,zk会自动删除节点。这里重点看ZkListener的增与删的方法。

这里以两个节点的启动为例。下面看到的日志所在节点是192.168.8.28,另外一个节点是192.168.8.18。

2023-04-18 17:31:14.277  INFO 26793 --- [           main] c.x.w.t.z.registration.ZkListener        : Register zk watcher successfully!// 因为zk目录下,已有一个节点,故在应用重启的时候,就检测到有新节点。
2023-04-18 17:31:14.465  INFO 26793 --- [pool-4-thread-2] c.x.w.t.z.registration.ZkListener        : 监听器--新节点加入:ServerNode(mac=null, host=192.168.8.18, port=8889)
2023-04-18 17:31:14.962  INFO 26793 --- [           main] c.x.ws.test.WebsocketTestApplication     : Started WebsocketTestApplication in 5.947 seconds (JVM running for 8.067)// 本节点作为新节点,加入到zk的目录下
2023-04-18 17:31:54.840  INFO 26793 --- [pool-4-thread-4] c.x.w.t.z.registration.ZkListener        : 监听器--新节点加入:ServerNode(mac=null, host=192.168.8.28, port=8889)// 接下来,测试另一个节点的停和启服务,可以看到,本节点都可以监听得到它的下线和上线。
2023-04-18 17:32:08.055  INFO 26793 --- [pool-4-thread-5] c.x.w.t.z.registration.ZkListener        : 监听器--节点删除:ServerNode(mac=null, host=192.168.8.18, port=8889)
2023-04-18 17:32:52.655  INFO 26793 --- [pool-4-thread-6] c.x.w.t.z.registration.ZkListener        : 监听器--新节点加入:ServerNode(mac=null, host=192.168.8.18, port=8889)

使用docker安装单节点zookeeper相关推荐

  1. Cloudera Manager安装之利用parcels方式安装单节点集群(包含最新稳定版本或指定版本的安装)(添加服务)(CentOS6.5)(四)...

    前期博客 Cloudera Manager安装之Cloudera Manager 5.3.X安装(三)(tar方式.rpm方式和yum方式) 说在前面的话(看清楚就好!!!) 我这篇博客,是两种方式都 ...

  2. K8S部署单节点zookeeper服务

    要使用Kubernetes (K8s) 部署单节点Zookeeper服务,需要执行以下步骤: 0.创建Zookeeper镜像 该镜像包含Zookeeper二进制文件和配置文件,使用Dockerfile ...

  3. HECO使用docker部署单节点的开发网

    文章目录 一. 编写说明 1.1 文档说明 1.2 配置信息 1.3 部署文档信息 二.heco开发网镜像生成 三.heco主链容器生成 3.1 配置文件编写 3.2 预先创建一个账户地址 3.3 创 ...

  4. etcd、flannel的安装---单节点

    etcd的安装和配置 [root@localhost zh]# yum install etcd[root@localhost zh]# service etcd start//因为我是单节点,所以没 ...

  5. openshift介绍及centos7安装单节点openshift、Redhat安装openshift集群完全教程

    Centos7中openshift_3.11单节点安装及配置开机自启详解 本次openshift安装使用最简单便捷的单节点安装,适用于本地开发及测试 openshift简介 OpenShift是红帽公 ...

  6. 肝了一晚帮她搭建完个人网站——利用Docker在单节点上实现内外网隔离网站部署(Nginx、Wordpress、MySQL)

    目录 1.前言 2.注册 3.重置服务器实例密码 4.配置安全规则 5.登录服务器 6.更新系统 7.安装Docker 8.创建Docker子网络 9.创建子网内的MySQL实例 10.创建子网内的W ...

  7. 【原】docker部署单节点consul

    docker下部署单节点的consul,最重要的是在run consul时,配置-bootstrap-expect=1 docker run --name consul1 -d -p 5902:850 ...

  8. docker搭建单节点mongodb

    查看需要安装的版本: # docker search mongo 下载镜像 # docker pull mongo 先以最简单方式启动镜像 # docker run --name="mong ...

  9. centos7安装单节点mysql(源码包安装)

    1.查看下面包是否安装,有安装的话卸载 # rpm -qa | grep mariadb # rpm -qa | grep postfix # rpm -ev postfix-2.10.1-6.el7 ...

最新文章

  1. vue实现文件上传功能
  2. 拉格朗日插值法的MATLAB源程序
  3. Head First JSP---随笔十(过滤器的威力)
  4. sql脚本对比工具_Java开发中用到的数据库迁移工具(flyway)
  5. python的flag是什么意思_网上老说的flag是什么意思
  6. 4.平凡之路-封装帮助类和加载属性文件
  7. Android 系统(174)---Android代码分析lint检查篇
  8. 开始研究WEKA,一个开源java的数据挖掘工具
  9. python定时器及数据库操作
  10. Python HTTP Error 403: Forbidden
  11. 80X86CPU独立编址方式的两种寻址方式——直接寻址直接写和间接寻址DX
  12. 懵圈了,面试官问一个 TCP 连接可发多少个 HTTP 请求?
  13. linux的系统监视器图片_Linux中一个高效的资源监控器Bpytop
  14. Spring源码全解析,帮你彻底学习Spring源码
  15. 网页内嵌多媒体 IE,Mozilla、Firefox、NetScape、Opera
  16. 构建五种机器学习模型作比较(某金融数据集)
  17. powerbi服务器无法显示报表,Power BI 报表中的页面显示设置 - Power BI | Microsoft Docs...
  18. Vbox虚拟机无法启动错误Mark
  19. 关于gradle项目中使用queryDsl生成Q类的问题的解决方式
  20. 软件工程项目基于java的wc实现

热门文章

  1. 惠普HP Color LaserJet CP6015 打印机驱动
  2. 25个典型的下一代互联网公司
  3. python-分割线
  4. 效能度量,打通研发管理闭环
  5. script标签问题
  6. C++入门——缓冲区溢出
  7. 钢铁电商行业方案:钢铁工业产品全生命周期管理解决方案
  8. 解决elasticsearch 中UNASSIGNED问题
  9. validate校验及自定义验证规则
  10. 前端Q面试类文章整理(文末送现金红包等礼品)