• Zookeeper集群搭建以及python操作zk


    一、Zookeeper原理简介

    转:https://www.cnblogs.com/xiao987334176/p/10103619.html

    ZooKeeper是一个开放源码的分布式应用程序协调服务,它包含一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命名服务等。

    Zookeeper设计目的

    • 最终一致性:client不论连接到那个Server,展示给它的都是同一个视图。
    • 可靠性:具有简单、健壮、良好的性能、如果消息m被到一台服务器接收,那么消息m将被所有服务器接收。
    • 实时性:Zookeeper保证客户端将在一个时间间隔范围内获得服务器的更新信息,或者服务器失效的信息。但由于网络延时等原因,Zookeeper不能保证两个客户端能同时得到刚更新的数据,如果需要最新数据,应该在读数据之前调用sync()接口。
    • 等待无关(wait-free):慢的或者失效的client不得干预快速的client的请求,使得每个client都能有效的等待。
    • 原子性:更新只能成功或者失败,没有中间状态。
    • 顺序性:包括全局有序和偏序两种:全局有序是指如果在一台服务器上消息a在消息b前发布,则在所有Server上消息a都将在消息b前被发布;偏序是指如果一个消息b在消息a后被同一个发送者发布,a必将排在b前面。

    Zookeeper工作原理

    1、在zookeeper的集群中,各个节点共有下面3种角色和4种状态:

    角色:leader,follower,observer
    状态:leading,following,observing,looking

    Zookeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议(ZooKeeper Atomic Broadcast protocol)。Zab协议有两种模式,它们分别是恢复模式(Recovery选主)和广播模式(Broadcast同步)。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和Server具有相同的系统状态。

    为了保证事务的顺序一致性,zookeeper采用了递增的事务id号(zxid)来标识事务。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64位的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch,标识当前属于那个leader的统治时期。低32位用于递增计数。

    每个Server在工作过程中有4种状态:

    LOOKING:当前Server不知道leader是谁,正在搜寻。

    LEADING:当前Server即为选举出来的leader。

    FOLLOWING:leader已经选举出来,当前Server与之同步。

    OBSERVING:observer的行为在大多数情况下与follower完全一致,但是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。

    Zookeeper集群节点

    • Zookeeper节点部署越多,服务的可靠性越高,建议部署奇数个节点,因为zookeeper集群是以宕机个数过半才会让整个集群宕机的。
    • 需要给每个zookeeper 1G左右的内存,如果可能的话,最好有独立的磁盘,因为独立磁盘可以确保zookeeper是高性能的。如果你的集群负载很重,不要把zookeeper和RegionServer运行在同一台机器上面,就像DataNodes和TaskTrackers一样。
     

    实验环境

    操作系统 docker镜像 docker ip zookeeper版本
    ubuntu-16.04.5-server-amd64 ubuntu:16.04 172.168.0.2 3.4.13
    ubuntu-16.04.5-server-amd64 ubuntu:16.04 172.168.0.2 3.4.13
    ubuntu-16.04.5-server-amd64 ubuntu:16.04 172.168.0.2 3.4.13

    由于机器有限,本文在一台服务器上面,开启了3个docker容器。

    使用网桥连接3个docker容器。这样,就可以模拟3台服务器了!

    创建网桥

    bridge有以下好处:

    1. 好的隔离性和互操作性:连到同一自定义的bridge的各个容器默认相互之间曝露所有端口,并且不对外部曝露

    2. 自动提供容器之间的DNS解析服务:连到同一自定义的bridge的各个容器不用做特殊DNS配置,可直接通过hostname访问

    3. 运行中容器联网配置:可对运行中的容器配置自定义或取消配置自定义bridge

    4. bridge之间相互独立:用户可创建N多个bridge,且连接于不同的bridge之上的容器相互独立

    创建自定义bridge,名字叫br1

    docker network create --driver=bridge --subnet=172.168.0.0/16 br1

    语法解释:

    --driver=bridge 表示使用桥接模式

    --subnet 表示网络地址

    为容器配置静态IP,可以使用以下命令

    docker run -it --network my-net --ip 172.18.0.250 imageID bash

    Zookeeper核心要点

    1. Zookeeper节点必须是奇数

    2. 修改zoo.cfg

    末尾增加3行参数。表示有3个zk节点!

    server.X=A:B:C
    server.X=A:B:C
    server.X=A:B:C

    官方解释

     View Code

    蹩脚翻译

     View Code

    大概意思

    复制代码
    server.X=A:B:C
    
    X-代表服务器编号
    
    A-代表ip
    
    B和C-代表端口,这个端口用来系统之间通信
    复制代码

    3. 创建ServerID标识

    除了修改zoo.cfg配置文件外,zookeeper集群模式下还要配置一个myid文件,这个文件需要放在dataDir目录下。

    这个文件里面有一个数据就是A的值(该A就是zoo.cfg文件中server.A=B:C:D中的A),在zoo.cfg文件中配置的dataDir路径中创建myid文件

    二、Zookeeper安装

    Zookeeper运行需要java环境,需要安装jdk,注:每台服务器上面都需要安装zookeeper、jdk。

    基于docker安装

    新建空目录

    mkdir /opt/zookeeper_cluster

    dockerfile

    复制代码
    FROM ubuntu:16.04
    # 修改更新源为阿里云
    ADD sources.list /etc/apt/sources.list
    ADD zookeeper-3.4.13.tar.gz /
    ADD zoo.cfg / 
    # 安装jdk
    RUN apt-get update && apt-get install -y openjdk-8-jdk --allow-unauthenticated && apt-get clean all &&  
        cd /zookeeper-3.4.13 && 
        mkdir data log && 
        mv /zoo.cfg conf
    
    EXPOSE 2181
    # 添加启动脚本
    ADD run.sh .
    RUN chmod 755 run.sh
    ENTRYPOINT [ "/run.sh"]
    复制代码

    run.sh

    复制代码
    #!/bin/bash
    
    if [ -z "${SERVER_ID}" ];then
        echo "SERVER_ID 变量缺失"
        exit 1
    fi
    
    if [ -z "${ZOOKEEPER_CONNECT}" ];then
            echo "ZOOKEEPER_CONNECT环境变量缺失"
            echo "比如: 192.168.1.1,192.168.1.2,192.168.1.3"
            exit 2
    fi
    
    # 配置集群
    # 写入server.X对应的X
    echo $SERVER_ID > /zookeeper-3.4.13/data/myid
    
    # 写入文件zoo.cfg
    id=0  # 初始值
    hosts_array=(${ZOOKEEPER_CONNECT//,/ })  # 以逗号来切割,转换为数组
    for ip in ${hosts_array[@]};do
        ((id++))  # id自增1
        echo "server.$id=$ip:2888:3888" >> /zookeeper-3.4.13/conf/zoo.cfg
    done
    
    # 启动zookeeper
    cd /zookeeper-3.4.13/
    bin/zkServer.sh start
    
    tail -f /zookeeper-3.4.13/conf/zoo.cfg
    复制代码

    注意:此脚本需要2个变量,否则会直接退出。它会在zoo.cfg写入3行内容!

    除了修改zoo.cfg配置文件外,zookeeper集群模式下还要配置一个myid文件,这个文件需要放在dataDir目录下

    /zookeeper-3.4.13/data/myid 这个文件的数值,待会由docker启动时,传入进去。

     sources.list

    复制代码
    deb http://mirrors.aliyun.com/ubuntu/ xenial main
    deb-src http://mirrors.aliyun.com/ubuntu/ xenial main
    
    deb http://mirrors.aliyun.com/ubuntu/ xenial-updates main
    deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates main
    
    deb http://mirrors.aliyun.com/ubuntu/ xenial universe
    deb-src http://mirrors.aliyun.com/ubuntu/ xenial universe
    deb http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
    deb-src http://mirrors.aliyun.com/ubuntu/ xenial-updates universe
    
    deb http://mirrors.aliyun.com/ubuntu/ xenial-security main
    deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security main
    deb http://mirrors.aliyun.com/ubuntu/ xenial-security universe
    deb-src http://mirrors.aliyun.com/ubuntu/ xenial-security universe
    复制代码

    zoo.cfg

    复制代码
    tickTime=2000
    initLimit=10
    syncLimit=5
    dataDir=/zookeeper-3.4.13/data
    dataLogDir=/zookeeper-3.4.13/log
    clientPort=2181
    复制代码

    initLimit 这个配置项是用来配置zookeeper接受客户端(这里所说的客户端不是用户连接zookeeper服务器的客户端,而是zookeeper服务器集群中连接到leader的follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。

    syncLimit 这个配置项标识leader与follower之间发送消息,请求和应答时间长度,最长不能超过多少个tickTime的时间长度,总的时间长度就是5*2000=10秒。

    注意:上面的2行红色部分参数,一定要加。否则会导致启动zookeeper失败,因为启动时,它会尝试连接server.X=A:B:C。有多少个,都会连接。

    如果连接失败数大于集群总数一半,会认为集群不可用。

    那么配置这2个参数之后,就会有时间缓解一下。因为我不是闪电侠,我不能在一瞬间同时启动3个zookeeper。而且你还得确保,zookeeper检查其他节点时,其他节点运行是正常的!

    因此,只要你在10秒内,启动3个zookeeper,就可以了!

    此时,目录结构如下:

    复制代码
    ./
    ├── dockerfile
    ├── run.sh
    ├── sources.list
    ├── zoo.cfg
    └── zookeeper-3.4.13.tar.gz
    复制代码

    生成镜像

    docker build -t zookeeper_cluster /opt/zookeeper_cluster

    启动docker

    在启动之前,请确保已经创建了网桥br1

    启动第一个docker

    docker run -it -e SERVER_ID=1 -e ZOOKEEPER_CONNECT=172.168.0.2,172.168.0.3,172.168.0.4 -p 2181:2181 --network br1 --ip=172.168.0.2 zookeeper_cluster

    启动第二个docker

    docker run -it -e SERVER_ID=2 -e ZOOKEEPER_CONNECT=172.168.0.2,172.168.0.3,172.168.0.4 -p 2182:2181 --network br1 --ip=172.168.0.3 zookeeper_cluster

    启动第二个docker

    docker run -it -e SERVER_ID=3 -e ZOOKEEPER_CONNECT=172.168.0.2,172.168.0.3,172.168.0.4 -p 2183:2181 --network br1 --ip=172.168.0.4 zookeeper_cluster

    注意红色部分,是需要修改的,其他的参数都是一样的!

    三、Zookeeper集群查看

    查看每个节点状态

    先来查看一下docker进程

    复制代码
    root@jqb-node128:/opt/zookeeper_cluster# docker ps
    CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
    217e012c9566        3f3a8090dcb6        "/run.sh"           15 hours ago        Up 15 hours         0.0.0.0:2183->2181/tcp   gallant_golick
    3b4861d2fef9        3f3a8090dcb6        "/run.sh"           15 hours ago        Up 15 hours         0.0.0.0:2182->2181/tcp   jovial_murdock
    ed91c1f973d2        3f3a8090dcb6        "/run.sh"           15 hours ago        Up 15 hours         0.0.0.0:2181->2181/tcp   dazzling_hamilton
    复制代码

    查看每个节点状态,使用命令 zkServer.sh status 查看

    复制代码
    root@jqb-node128:~# docker exec -it 217e012c9566 /zookeeper-3.4.13/bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /zookeeper-3.4.13/bin/../conf/zoo.cfg
    Mode: follower
    root@jqb-node128:~# docker exec -it 3b4861d2fef9 /zookeeper-3.4.13/bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /zookeeper-3.4.13/bin/../conf/zoo.cfg
    Mode: leader
    root@jqb-node128:~# docker exec -it ed91c1f973d2 /zookeeper-3.4.13/bin/zkServer.sh status
    ZooKeeper JMX enabled by default
    Using config: /zookeeper-3.4.13/bin/../conf/zoo.cfg
    Mode: follower
    复制代码

    可以发现,第二台,也就是id为3b4861d2fef9 的容器,就是leader模式。其它容器是follow模式

    四、Zookeeper集群连接

     Zookeeper集群搭建完毕之后,可以通过客户端脚本连接到zookeeper集群上面,对客户端来说,zookeeper集群是一个整体,连接到zookeeper集群实际上感觉在独享整个集群的服务。

    指定第一台节点

    docker exec -it 217e012c9566 /zookeeper-3.4.13/bin/zkCli.sh -server 172.168.0.2:2181

    使用ls / 查看根节点,默认只有一个zookeeper节点。

    WatchedEvent state:SyncConnected type:None path:null
    [zk: 172.168.0.2:2181(CONNECTED) 0] ls /
    [zookeeper]
    [zk: 172.168.0.2:2181(CONNECTED) 1] 

    五、使用python操作zookeeper

    kazoo 介绍

    zookeeper的开发接口以前主要以java和c为主,随着python项目越来越多的使用zookeeper作为分布式集群实现,python的zookeeper接口也出现了很多,现在主流的纯python的zookeeper接口是kazoo。因此如何使用kazoo开发基于python的分布式程序是必须掌握的。

    安装kazoo

    pip3 install kazoo

    基本操作

    from kazoo.client import KazooClient
    zk = KazooClient(hosts='192.168.91.128:2181')    #如果是本地那就写127.0.0.1
    zk.start()    #与zookeeper连接
    zk.stop()    #与zookeeper断开

    创建节点

    复制代码
    from kazoo.client import KazooClient
    zk = KazooClient(hosts='192.168.91.128:2181')    #如果是本地那就写127.0.0.1
    zk.start()    #与zookeeper连接
    #makepath=True是递归创建,如果不加上中间那一段,就是建立一个空的节点
    zk.create('/abc/JQK/XYZ/0001',b'this is my house',makepath=True)
    node = zk.get_children('/')  # 查看根节点有多少个子节点
    print(node)
    zk.stop()    #与zookeeper断开
    复制代码

    执行输出:

    ['abc', 'zookeeper']

    注意:空节点的值不能用set修改,否则执行报错!

    删除节点

    如果要删除这个/abc/JQK/XYZ/0001的子node,但是想要上一级XYZ这个node还是存在的,语句如下:

    复制代码
    from kazoo.client import KazooClient
    zk = KazooClient(hosts='192.168.91.128:2181')    #如果是本地那就写127.0.0.1
    zk.start()    #与zookeeper连接
    #recursive=True是递归删除,就是无视下面的节点是否是空,都干掉,不加上的话,会提示子节点非空,删除失败
    zk.delete('/abc/JQK/XYZ/0001',recursive=True)
    node = zk.get_children('/')  # 查看根节点有多少个子节点
    print(node)
    zk.stop()    #与zookeeper断开
    复制代码

    执行输出:

    ['abc', 'zookeeper']

    更改节点

    现在假如要在0001这个node里更改value,比如改成:"this is my horse!",

    由于上面节点已经被删除掉了,需要先创建一次。

    语句如下:

    复制代码
    from kazoo.client import KazooClient
    zk = KazooClient(hosts='192.168.91.128:2181')    #如果是本地那就写127.0.0.1
    zk.start()    #与zookeeper连接
    zk.create('/abc/JQK/XYZ/0001',b'this is my house',makepath=True)
    zk.set('/abc/JQK/XYZ/0001',b"this is my horse!")
    node = zk.get('/abc/JQK/XYZ/0001')  # 查看值
    print(node)
    zk.stop()    #与zookeeper断开
    复制代码

    执行输出:

    (b'this is my horse!', ZnodeStat(czxid=4294967449, mzxid=4294967452, ctime=1544598301273, mtime=1544598308267, version=1, cversion=0, aversion=0, ephemeralOwner=0, dataLength=17, numChildren=0, pzxid=4294967449))

    注意!set这种增加节点内容的方式是覆盖式增加,并不是在原有基础上增添。而且添加中文的话可能在ZooInspecter里出现的是乱码

    查看节点

    由于所有节点,都是在/ 节点上面的,直接查看根节点,就可以知道所有节点了

    复制代码
    from kazoo.client import KazooClient
    zk = KazooClient(hosts='192.168.91.128:2181')    #如果是本地那就写127.0.0.1
    zk.start()    #与zookeeper连接
    node = zk.get_children('/')
    print(node)
    zk.stop()    #与zookeeper断开
    复制代码

    执行输出:

    ['abc', 'zookeeper']

    一键清空zookeeper

    有些时候,需要将zookeeper的数据全部清空,可以使用以下代码

    复制代码
    from kazoo.client import KazooClient
    zk = KazooClient(hosts='192.168.91.128:2181')    #如果是本地那就写127.0.0.1
    zk.start()    #与zookeeper连接
    jiedian = zk.get_children('/')  # 查看根节点有多少个子节点
    print(jiedian)
    for i in jiedian:
        if i != 'zookeeper':  # 判断不等于zookeeper
            print(i)
            # 删除节点
            zk.delete('/%s'%i,recursive=True)
    zk.stop()    #与zookeeper断开


  • 相关阅读:
    生产型企业原材料采购及入库的处理
    OpenERP财务管理若干概念讲解
    OE context 传参数
    Openerp 中打开 URL 的三种 方法
    view xml 中的 button 调用web客户端事件
    一招解决OpenERP8.0安装旧版模块报错
    ubuntu server激活即时通讯IM服务 Instant Messaging is not activated on this server
    error: command 'gcc' failed with exit status 1 while installing eventlet
    OpenERP函數字段的應用
    Doker容器之间连接
  • 原文地址:https://www.cnblogs.com/wapn/p/10560494.html
Copyright © 2020-2023  润新知