Zookeeper分布式

Zookeeper是一个分布式的协调服务,提供一致性、原子性、单一视图和可靠性等特性。本文介绍了Zookeeper的安装过程,包括JDK的安装、Zookeeper的下载配置,以及Zookeeper的基本数据模型和特性,如分布式锁、节点选举、ACL权限控制等。还详细讲解了Zookeeper集群的安装,包括单机伪分布式和完全分布式,并提供了基于Linux的ZK客户端命令行操作和原生Java API的客户端开发示例。
摘要由CSDN通过智能技术生成

zookeeper简介

顾名思义,zoo动物,keeper管理员,合称动物园管理员

ZooKeeper 是一个分布式的,开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。
Zookeeper是hadoop的一个子项目,其发展历程无需赘述。在分布式应用中,由于工程师不能很好地使用锁机制,以及基于消息的协调机制不适合在
某些应用中使用,因此需要有一种可靠的、可扩展的、分布式的、可配置的协调机制来统一系统的状态。Zookeeper的目的就在于此。

主要作用

  • 中间件,提供协调服务
  • 作用于分布式系统,发挥其优势,可以为大数据服务
  • 支持java,提供java和c语言的客户端api

什么是分布式系统

  • 很多计算机组成一个整体,一个整体一致对外并且处理同一请求
  • 内部的每台计算机都可以相互通信(rest/rpc远程调用)
  • 客户端到服务端的一次请求到响应结束会经历多台计算机

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SB4RPHtd-1574130425483)(assets/1569209106613.png)]

订单系统的案例…

分布式系统的瓶颈

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FJnUUXcR-1574130425486)(assets/timg.jpg)]

zookeeper的特性(面试的高频题 事务…)

**一致性:**数据一致性,数据按照顺序分批入库。

**原子性:**事务要么成功要么失败,不会局部化。

**单一视图:**客户端连接集群中任一zk节点,数据都是一致的。

**可靠性:**每次对zk的操作状态都会保存在服务端。

**实时性:**客户端可以读取到zk服务器的最新数据。

ZooKeeper安装

JDK的安装

  • 下载Linux的jdk1.8.tar,上传至Linux的服务器
  • 解压缩jdk,配置jdk
  • 测试:java -version 显示版本号

zookeeper下载、安装以及配置环境变量

JAVA_HOME=/usr/jdk8(java的安装位置)
ZOOKEEPER_HOME=/usr/local/zookeeper(zookeeper的安装位置)
CLASSPATH=%JAVA_HOME%/lib:%JAVA_HOME%/jre/lib
PATH= P A T H : PATH: PATH:JAVA_HOME/bin: J A V A H O M E / j r e / b i n : JAVA_HOME/jre/bin: JAVAHOME/jre/bin:ZOOKEEPER_HOME/jre/bin
export PATH CLASSPATH JAVA_HOME ZOOKEEPER_HOME

zookeeper文件夹主要目录介绍

bin:主要的一些运行命令

conf:存放配置文件,其中我们需要修改zk.cfg(zoo_sample.cfg主配置文件)

contrib:附加的一些功能(能够使用python操作zk,能够实现远程rest调用)

dist-maven:mvn编译后的目录

docs:文档

lib:平时依赖的jar包

recipes:案例demo代码

src:源码

zookeeper配置文件介绍,运行zk

tickTime:用于计算的单元时间。比如session超时:N*tickTime

initLimit:用于集群,允许从节点连接并同步到master节点的初始化连接时间,以tickTime的倍数来表示

syncLimit:用于集群,master主节点与从节点之间发送消息,请求和应答的时间长度(心跳机制)

dataDir:必须配置(存储相关数据,事务文件…数据)

dataDir=/usr/local/zookeeper/dataDir(必须手动创建)

dataLogDir:日志目录,如果不配置和dataDir公用

dataLogDir=/usr/local/zookeeper/dataLogDir(必须手动创建)

clientPort:连接服务器的端口,默认2181(在伪分布式的环境下是要变的)

ZooKeeper基本数据模型

  • 是一个树形结构,类似于前端开发中的tree.js组件
  • zk的数据模型可以理解为linux/unix的文件目录:/usr/local
  • 每一个节点都称之为znode,它可以有子节点,也可以有数据
  • 每个节点分为临时节点和永久节点,临时节点在客户端断开之后消失
  • 每个zk节点都有各自的版本号,可以通过命令行来显示节点的信息
  • 每个节点数据发生变化,那么该节点的版本号会累加(乐观锁),类似于svn的版本号
  • 删除或者修改过时的节点,版本号不匹配则会报错(乐观锁的存在)
  • 每个zk节点存储的数据不宜过大,几k即可,最大1M
  • 节点可以设置权限acl(权限控制列表),可以通过权限来限制用户的访问
  • zk客户端连接关闭服务端查看znode

客户端连接

./zkServer.sh restart 先要启动zk服务器

./zkCli.sh 启动客户端

查看znode结构

help 查看所有的命令

关闭客户端连接

ctrl+c

zookeeper的作用体现

节点选举

Master节点,主节点挂了之后,从节点就会接手工作
并且,保证这个节点是唯一的,这就是首脑模式,从而保证集群的高可用

统一配置文件管理

只需要部署一台服务器则可以把相同的配置文件,同步更新到其他所有服务器,

此操作在云计算中,用的特别多。比如,修改了redis统一配置

发布与订阅

类似消息队列MQ、amq、rmq,dubbo发布者把数据存在znode节点上,订阅者会读取这个数据

提供分布式锁

分布式环境中,不同进程之间争夺资源类似于多线程中的的锁

集群管理

集群中,保证数据的一致性

ZK基本特性与基于Linux的ZK客户端命令行学习

zookeeper常用命令行操作

  • 通过./zkCli.sh打开zk的客户端进行命令行后台

  • ls与ls2命令

    ls2=ls+stat

  • get与stat命令

    get可以获取节点的数据 stat只是查看节点的状态

  • create命令的使用

    create /ddm ange 创建持久节点

    create -e /ddm/temp pika 创建临时节点

    create -s /ddm/sort sort 创建顺序节点

  • set命令(乐观锁)

  • delete命令(乐观锁)

watcher事件

特性说明
一次性Watcher是一次性的,一旦被触发就会移除,再次使用时需要重新注册
客户端顺序回调Watcher回调是顺序串行化执行的,只有回调后客户端才能看到最新的数据状态。一个Watcher回调逻辑不应该太多,以免影响别的watcher执行
轻量级WatchEvent是最小的通信单元,结构上只包含通知状态、事件类型和节点路径,并不会告诉数据节点变化前后的具体内容;
时效性Watcher只有在当前session彻底失效时才会无效,若在session有效期内快速重连成功,则watcher依然存在,仍可接收到通知;
  • 创建父节点触发:NodeCreated

    stat /ddm watch ------> create /ddm

  • 修改父节点数据触发:NodeDataChanged

    get /ddm watch -----> set /ddm 123

  • 删除父节点触发:NodeDeleted

    get /ddm watch -----> delete /ddm

  • 创建和删除子节点触发:NodeChildrenChanged(修改子节点不会触发事件,需要把子节点当作父节点)

    ls /ddm watch —> create /ddm/temp 123

    ls /ddm watch —> delete /ddm/temp

watcher的使用场景

  • 统一资源配置

ACL(access control lists)权限控制

  • 针对不同的节点可以设置相关的读写等权限,目的为了保障数据安全性
  • 权限permissions可以指定不同的权限范围以及角色

ACL命令行

getAcl:获取某个节点的acl权限信息

setAcl:设置某个节点的acl权限信息

addauth:输入认证权限信息,注册时输入明文密码(登录),但在zk系统中,密码是以加密的形式存在的

ACL的构成

zk的acl通过[scheme🆔permissions]来构成权限列表

scheme:代表采用的某种权限机制

id: 代表允许访问的用户

permissions: 权限组合字符串

身份的认证有4种方式(scheme):

world:默认方式,相当于全世界都能访问
auth:代表已经认证通过的用户(cli中可以通过addauth digest user:pwd 来添加当前上下文中的授权用户)
digest:即用户名:密码这种方式认证,这也是业务系统中最常用的
ip:使用Ip地址认证

super:超级管理员权限

auth与digest的区别

前者是明文,后者是密文

setAcl /path auth:lee:lee:cdrwd与

setAcl /path digest:lee:BASE64(SHA1(password))cdrwa

是等价的,在通过addauth digest lee:lee 后都能操作指定节点的权限

权限字符串缩写 crdwa

create: 创建节点

read: 获取节点/子节点

write: 设置节点数据

delete: 删除子节点

admin: 设置权限

getAcl /ddm
setAcl /ddm world:anyone:crwa
delete /ddm/abc
通过auth设置
create /names ange
getAcl /names
setAcl /names auth:ange:ange:cdrwa
addauth digest ange:ange
setAcl /names auth:ange:ange:cdrwa
setAcl /names auth:rock:rock:cdrwa
getAcl /names
通过digest设置
setAcl /names digest:ange:密文:cdrwa
通过ip设置
setAcl /names/ip ip:127.0.0.1:cdrwa

ACL的应用场景

  • 开发/测试环境分离,开发者无权操作测试库的节点,只能看
  • 生产环境上控制指定的IP的服务可以访问相关节点,防止混乱

ZK四字命令

需要在zk3.4.6之后才能使用

具体参考:https://blog.csdn.net/u013673976/article/details/47279707

选举模式和ZooKeeper的集群安装

单机伪分布式安装zookeeper集群

zookeeper集群搭建注意点:

​ 配置数据文件myid1/2/3对应server.1/2/3

​ 通过zkCli.sh -server [ip]:[port]检测集群是否配置成功。

第一步:首先我们将我们之前已经搭建好的单机版的zk虚拟机进行克隆。

第二步:修改克隆后的虚拟机配置:https://www.cnblogs.com/haoliyou/p/9461844.html

第三步:复制zk

执行命令:cp zookeeper zookeeper02 -rf

第四步:修改拷贝的zk配置

41w.commands.whitelist=*

server.1=192.168.1.85:2888:3888

server.2=192.168.1.85:2889:3889

server.3=192.168.1.85:2890:3890

ip记得修改成自己的主机

(选举模式需要该配置)

然后需要到:dataDir目录下创建myid文件 ,在里边输入1。

以此创建其他的机器,但是要记得修改配置信息

server.A=B:C:D
A:表示集群中服务器的序号,需要唯一
B:表示服务器的IP
C:和集群中Leader交换数据的端口
D:进行Leader选举的端口
举例子
server.1=192.168.135.11:8881:8891
server.2=192.168.135.12:8881:8891
server.3=192.168.135.13:8881:8891
在这个集群中有三个服务器
序号分别为1、2、3;
IP分别为192.168.135.11,192.168.135.12,192.168.135.13,
和Leader通讯的端口均为8881,当然这里的通讯端口也可以不一样
进行Leader选举的端口均为8891,这里的选举端口也可以不一样

第五步:启动三个服务节点

./zkServer.sh restart

查看节点的模式和状态

第六步:启动客户端

执行: ./zkCli.sh -server localhost:2181 命令,尝试连接第一个节点

创建一个文件,看是否能够实现同步

完全分布式集群搭建

参考伪分布式搭建的方式(注意一定要关闭防火墙,今天困扰我三次了)

查看防火墙状态:systemctl status firewalld
关闭防火墙:systemctl stop firewalld
开启防火墙:systemctl start firewalld

查看默认防火墙状态(关闭后显示notrunning,开启后显示running)
systemctl status firewalld.service
关闭防火墙:
systemctl stop firewalld.service
开启防火墙:
systemctl start firewalld.service
永久关闭防火墙(可防止系统关机重启后防火墙自启动):
systemctl disable firewalld.service
永久开启防火墙:
systemctl enable firewalld.service

在连接客户端远程工具的时候记得启动zk的服务

使用ZooKeeper原生Java API进行客户端开发

# Configure logging for testing: optionally with log file
log4j.rootLogger=WARN, stdout
# log4j.rootLogger=WARN, stdout, logfile

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n

log4j.appender.logfile=org.apache.log4j.FileAppender
log4j.appender.logfile.File=target/spring.log
log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
<dependencies>
        <!-- https://mvnrepository.com/artifact/com.101tec/zkclient -->
        <!--<dependency>
            <groupId>com.101tec</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.8</version>
        </dependency>-->

        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.8</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

    </dependencies>
public class Test01 {
    private static final String HOST = "192.168.126.129";
    private static final int TIME_OUT = 2000;

    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException {

        ZooKeeper zooKeeper = new ZooKeeper(HOST, TIME_OUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                System.out.println(state);
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("123");
                    countDownLatch.countDown();
                }
            }
        });

        System.out.println("正在等待连接.....");
        countDownLatch.await();
        System.out.println("开始创建节点.....");



        String s = zooKeeper.create("/xintu", "duli".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
        System.out.println(s);
        //Thread.sleep(5000);
        zooKeeper.close();

        /**
         * 节点的四种类型:
         * 1.持久节点   PERSISTENT
         * 2.临时节点  会话关闭会自动删除
         * 3.持久有序节点
         * 4.临时有序节点
         *
         * 注意事项:不能递归创建节点
         */
    }
}

权限的设置

public class Test02 {
    private static final String HOST = "192.168.126.129";
    private static final int TIME_OUT = 2000;

    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException, NoSuchAlgorithmException {

        ZooKeeper zooKeeper = new ZooKeeper(HOST, TIME_OUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                System.out.println(state);
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("123");
                    countDownLatch.countDown();
                }
            }
        });

        System.out.println("正在等待连接.....");
        countDownLatch.await();
        System.out.println("开始创建节点.....");

        //创建权限
        Id id1 = new Id("digest", DigestAuthenticationProvider.generateDigest("admin:admin123"));
        ACL acl1 = new ACL(ZooDefs.Perms.ALL,id1);

        Id id2 = new Id("digest", DigestAuthenticationProvider.generateDigest("guest:guest123"));
        ACL acl2 = new ACL(ZooDefs.Perms.ALL,id2);

        ArrayList<ACL> acls = new ArrayList<>();
        acls.add(acl1);
        acls.add(acl2);

        String s = zooKeeper.create("/xintu", "duli".getBytes(), acls, CreateMode.PERSISTENT);
        System.out.println(s);
        //Thread.sleep(5000);
        zooKeeper.close();

        /**
         * 节点的四种类型:
         * 1.持久节点   PERSISTENT
         * 2.临时节点  会话关闭会自动删除
         * 3.持久有序节点
         * 4.临时有序节点
         *
         * 注意事项:不能递归创建节点
         */
    }
}

权限的访问

public class Test03 {
    private static final String HOST = "192.168.126.129";
    private static final int TIME_OUT = 2000;

    private static CountDownLatch countDownLatch = new CountDownLatch(1);
    public static void main(String[] args) throws IOException, KeeperException, InterruptedException, NoSuchAlgorithmException {

        ZooKeeper zooKeeper = new ZooKeeper(HOST, TIME_OUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                System.out.println(state);
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("123");
                    countDownLatch.countDown();
                }
            }
        });

        zooKeeper.addAuthInfo("digest","guest:guest123".getBytes());

        byte[] data = zooKeeper.getData("/xintu", null, new Stat());
        System.out.println(new String(data));
    }
}

使用zookeeper实现服务注册

package com.ddmzx.springboot_zk;

import org.apache.zookeeper.*;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;

import java.util.concurrent.CountDownLatch;

@Component
public class ApplicationRunnerImpl implements ApplicationRunner {
    private static final String HOST = "192.168.126.129";
    private static final int TIME_OUT = 2000;

    private static CountDownLatch countDownLatch = new CountDownLatch(1);

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

    @Override
    public void run(ApplicationArguments args) throws Exception {
        ZooKeeper zooKeeper = new ZooKeeper(HOST, TIME_OUT, new Watcher() {
            @Override
            public void process(WatchedEvent watchedEvent) {
                Event.KeeperState state = watchedEvent.getState();
                System.out.println(state);
                if (state == Event.KeeperState.SyncConnected) {
                    System.out.println("123");
                    countDownLatch.countDown();
                }
            }
        });

        System.out.println("正在等待连接.....");
        countDownLatch.await();
        System.out.println("开始创建节点.....");

        String parentPath = "/ddm";
        Stat exists = zooKeeper.exists(parentPath, null);
        if(exists==null){
            zooKeeper.create(parentPath,"/ddm".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
        }

        String path = "127.0.0.1:"+port;
        zooKeeper.create(parentPath+"/"+port,path.getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT);
        System.out.println("服务注册成功");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值