zookeeper

一,前言

与redis的联系

redis 单实例,数据在内存-读取快

鉴于雪崩击穿等问题 ->复制到集群 HA sentinel 哨兵实现高可用

不是绝对的实时同步,可能连最终一致性都算不上

集群模式 分片

完成分布式 协调分布式锁

二,zookeeper(不要把zk当做数据库用)

主从集群 主是单点的(zk运行状态,1.可用状态,有主模型2.不可用状态,无主模型3.不可用状态恢复到可用状态,应该越快越好 200毫秒)

1.leader可能会挂

2.导致服务不可用

3.事实,zk集群及高可用

4.如果有一种方式可以快速的复制出一个leader

一个leader多个follower,客户端想连谁就连谁(每个客户端连接会有一个session,即临时节点)

zookeeper是一个目录结构-->不同目录即为一个节点,可以存数据,官方声明为1M->统一配置管理1.2.3.4.

持久节点

临时节点-->session

序列节点(序列化,要么是持久节点要么是临时节点)

1.统一配置管理<-1M数据

  分布式锁,临时节点

client代码实现

 

2.分组管理<--path结构

        

锁依托一个父节点,具备 -s

队列式事务锁

3.统一命名<--sequential

 

代表父节点下可以有多把锁

 

4.同步<--临时节点

HA 选主

 

 

 

 

 

担保

  • ZooKeeper非常快速且非常简单。但是,由于其目标是作为构建更复杂的服务(例如同步)的基础,因此它提供了一组保证。这些是:
  • 顺序一致性-来自客户端的更新将按照其发送顺序进行应用。
  • 原子性-更新成功或失败。没有部分结果。
  • 统一视图-无论客户端连接到哪个服务器,客户端都将看到相同的服务视图。
  • 可靠性-应用更新后,此更新将一直持续到客户端覆盖更新为止。
  • 及时性-确保系统的客户视图在特定时间范围内是最新的。

三 安装启动

  • 1.先安装jdk (下载,解压,配置环境变量)

export JAVA_HOME=/app/jdk1.8.0_231/

export CLASSPATH=.:$JAVA_HOME/lib.dt.jar:$JAVA_HOME/lib/tools.jar

export PATH=$PATH:$JAVA_HOME/bin

Java-version验证是否安装成功

  • 2.再zookeeper(下载,解压,配置环境变量)

export JAVA_HOME=/app/jdk1.8.0_231/

export CLASSPATH=.:$JAVA_HOME/lib.dt.jar:$JAVA_HOME/lib/tools.jar

export ZOOKEEPER_HOME=/app/zookeeper/apache-zookeeper-3.5.5-bin/

export PATH=$PATH:$JAVA_HOME/bin:$ZOOKEEPER_HOME/bin

输入zk按tab键验证是否成功

 

配置zk相关配置:

conf/zoo.cfg

#配置数据文件夹和日志文件夹

dataDir=/var/houkai/zk

dataLogDir=/var/houkai/zk/log

#配置集群  2888: leader接收writer请求用  3888:选主投票用

server.1=192.168.65.10:2888:3888

server.2=192.168.65.20:2888:3888

server.3=192.168.65.30:2888:3888

server.4=192.168.65.40:2888:3888

server.5=192.168.65.50:2888:3888

mkdir -p /var/houkai/zk

进入/var/houkai/zk文件夹

vi myid 文件中写自己的id号,即上面的.1.2.3.4.5

  • 3.启动
    • zkServer.sh help 查看帮助
    • zkServer.sh start-foreground
    • java.net.NoRouteToHostException: No route to host (Host unreachable)
    •   service iptables status 查看防火墙状态
    •   service iptables off
    •   service iptables stop 即时生效,重启后复原

chkconfig iptables off 永久关闭防火墙

  • zkServer.sh status 查看主机状态是主还是从
  • zkCli.sh 启动客户端
    • o ll显示节点
    • o create /newnode "" 创建新的(持久)节点,东西的话不报错但是不创建,所以带个字符串
    • o create -s /newnode  创建(顺序)节点,可以规避节点被覆盖
    • o create -e /newnode   创建(临时)节点
    • o create [-s] [-e] path data acl 其中,-s或-e分别指定节点特性,顺序或临时节点,若不指定,则表示持久节点;acl用来进行权限控制。
    • o create -s -e /newnode
    • o create/newnode/sonnode "koukay" 也可以创建多级节点,数据最大1M,二进制安全的
    • o get /newnode/sonnode 获取节点 因为节点相当于文件夹,所以名字前必须带/
    • o get -s /koukay 获取节点,显示数据参数
    • o set /newnode "hello"为节点设置值
    • o rmr /test 删除节点及数据

 

 

  • 参数解析

cZxid = 0x0

ctime = Thu Jan 01 08:00:00 CST 1970

mZxid = 0x0

mtime = Thu Jan 01 08:00:00 CST 1970

pZxid = 0x1469

cversion = 3

dataVersion = 0

aclVersion = 0

ephemeralOwner = 0x0

dataLength = 0

numChildren = 4

其中:

cZxid:节点创建时的zxid

ctime:节点创建时间

mZxid:节点最近一次更新时的zxid

mtime:节点最近一次更新的时间

cversion:子节点数据更新次数

dataVersion:本节点数据更新次数

aclVersion:节点ACL(授权信息)的更新次数

  • ephemeral Owner:如果该节点为临时节点,ephemeralOwner值表示与该节点绑定session id.如果该节点不是临时节点,ephemeralOwner值为0

dataLength:节点数据长度,本例中为hello world的长度

numChildren:子节点个数

netstat -napt |egrep '(2888|3888)'

 

四,paxos,ZAB(zk原子广播),watch,API -->zk client,callback-->reactive 编程 更充分的压榨os,hw资源,性能

  • zookeeper分布式协调扩展,可靠性,时序性,扩展性
  • 扩展性
    • o 框架架构-->角色

leader  

主节点

follower

从节点

observer

Observer与follower类似但不参与投票,只是简单的接收投票结果,因此我们增加再多的Observer,也不会影响集群的写性能

 

  • 读写分离 observer放大查询能力
    • 只有follower才能选举
    • zoo.cfg

server.1=192.168.65.10:2888:3888

server.2=192.168.65.20:2888:3888

server.3=192.168.65.30:2888:3888

server.4=192.168.65.40:2888:3888

server.5=192.168.65.50:2888:3888:observer

  • 可靠性
    • o 攘其外必先安其内(有主有从)
    • o 快速恢复leader
    • o 数据可靠,可用一致性
      • 攘其外  一致性?(先同步再提供服务)  最终一致性  过程中节点是否对外提供服务(zk挂了,停止服务,进行选举)
      • 分布式

https://www.douban.com/note/208430424/  (关于分布式的文章,更偏向于paxos)

Z(ZK)A(原子)B(广播) 作用在可用状态 有leader时

  • 分布式流程
    • 概念解释:
      • 原子:只有成功或失败,没有中间状态 (队列+2pc)
      • 广播:分布式多节点,全部收到消息(过半)
      • 队列:FIFO 顺序性
      • zk的数据状态在内存用磁盘保存日志
      • 一个leader两个follower ,每个follower和leader之间有个队列
        •  

client

 

follower

 

queue

leader

queue

 

follower

 

client

客户端

1客户端请求创建节点,请求到达follower

从节点

4-1-log队列将日志送达从节点

2从节点在主节点创建

3Zxid事务id

从节点在主节点创建

4-1-log队列将日志送达从节点

从节点

1客户端请求创建节点,请求到达follower

客户端

 

从节点返回创建状态OK

sync可选项

4-1-ok

从节点收到日志后返回OK到队列

主节点返回OK日志

4-1-ok

主节点返回OK日志

4-1-ok

从节点收到日志后返回OK到队列

sync可选项

从节点返回创建状态OK

 

  • 集群状态下如何选举leader
    • 两个场景
      • 场景一,第一次启动集群
      • 场景二,leader挂了后重启集群
      • 自己会有myid和Zxid 选举标准
        • 经验最丰富的的Zxid
        • Zxid相同就找比较大的myid
        • *,过半通过的数据才是真数据,你见到的可用的Zid ,4台机器,3台通过
        • 选举过程
          • 3888造成两两通信
          • 只要任何人投票,都会触发那个准leader发起自己的投票
          • 推选制,先比较zxid,如果zxid相同,再比较myid

 

  • watch(监控,观察)
    • o 统一目录结构
    • o 客户端1
    • o 客户端2
    • o 客户端1&客户端2
      • 客户端在统一目录结构创建节点,删除修改节点会有相应的事件,事件会触发回调函数将事件信息返回给另一个客户端
      • 客户端1与服务端连接在统一视图目录树结构中创建一个临时节点(node:  /oozz/a),建立连接,有一个session和ephemeralOwner(如果不是临时节点,该值为sessionid,如果是临时节点该值为1)
      • 客户端2可以通过get /ooxx/a获取该节点,也可以通过watch /ooxx/a监控该节点
      • 两个客户端之间也有通信,可以开启一个线程检测心跳

 

  • API demo

packagecom.koukay.zookeeper;

 

importorg.apache.zookeeper.*;

importorg.apache.zookeeper.data.Stat;

 

importjava.io.IOException;

importjava.util.concurrent.CountDownLatch;

 

publicclassApp{

publicstaticvoidmain(String[]args)throwsException{

System.out.println("HelloWorld");

 

//zk是有session概念的,没有连接池的概念的

//watch观察回调分为两类

//watch的注册只发生在读类型调用,get,exist

//第一类,newzk的时候,传入的watch,这个watchsession级别的,pathnode没有关系

CountDownLatchcd=newCountDownLatch(1);

ZooKeeperzk=newZooKeeper("192.168.65.10:2181,192.168.65.20:2181,192.168.65.30:2181,192.168.65.40:2181,192.168.65.50:2181"

,3000,

newWatcher(){

/**

*watch的回调方法

*@paramevent

*/

@Override

publicvoidprocess(WatchedEventevent){

Event.KeeperStatestate=event.getState();

Event.EventTypetype=event.getType();

Stringpath=event.getPath();

System.out.println("==========newzkwatch"+event.toString());

switch(state){

caseUnknown:

break;

caseDisconnected:

break;

caseNoSyncConnected:

break;

caseSyncConnected:

System.out.println("==================>connected");

cd.countDown();

break;

caseAuthFailed:

break;

caseConnectedReadOnly:

break;

caseSaslAuthenticated:

break;

caseExpired:

break;

caseClosed:

break;

}

switch(type){

caseNone:

break;

caseNodeCreated:

break;

caseNodeDeleted:

break;

caseNodeDataChanged:

break;

caseNodeChildrenChanged:

break;

caseDataWatchRemoved:

break;

caseChildWatchRemoved:

break;

}

}

});

cd.await();

ZooKeeper.Statesstate=zk.getState();

switch(state){

caseCONNECTING:

System.out.println("===========ing======================");

break;

caseASSOCIATING:

break;

caseCONNECTED:

System.out.println("===========ed======================");

break;

caseCONNECTEDREADONLY:

break;

caseCLOSED:

break;

caseAUTH_FAILED:

break;

caseNOT_CONNECTED:

break;

}

StringpathName=zk.create("/ooxx","olddata".getBytes(),ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);

Statstat=newStat();

byte[]node=zk.getData("/ooxx",newWatcher(){

@Override

publicvoidprocess(WatchedEventevent){

System.out.println("===========getDataWatch"+event.toString());

try{

//trueDefaultWatch被重新注册(newzk的那个watch)

zk.getData("/ooxx",true,stat);

}catch(KeeperExceptione){

e.printStackTrace();

}catch(InterruptedExceptione){

e.printStackTrace();

}

}

},stat);

System.out.println("=================="+newString(node));

//触发回调

Statstat1=zk.setData("/ooxx","newData".getBytes(),0);

//第二次还会触发吗

Statstat2=zk.setData("/ooxx","newData01".getBytes(),stat1.getVersion());

System.out.println("----------------asyncstart--------------");

zk.getData("/ooxx",false,newAsyncCallback.DataCallback(){

 

@Override

publicvoidprocessResult(intrc,Stringpath,Objectctx,byte[]data,Statstat){

System.out.println("----------------asyncover--------------");

System.out.println("----------"+ctx.toString());

System.out.println("----------"+newString(data));

}

},"123");

System.out.println("----------------asynccallback--------------");

Thread.sleep(2222222);

 

}

}

五,zookeeper分布式协调 配置 分布式锁

分布式配置

zookeeper配置数据data

客户端

get()

watch()

修改设置配置

触发回调

分布式锁

1,争抢锁,只有一个人能获得锁

2,获得锁的人出问题,临时节点(session)。

3,获得锁的人成功了。释放锁。

4,锁被释放、删除,别人怎么知道的?

4-1:主动轮询,心跳。。。弊端:延迟,压力

4-2:watch:  解决延迟问题。。  弊端:压力

4-3:sequence+watch:watch谁?watch前一个,最小的获得锁~!一旦,最小的释放了锁,成本:zk只给第二个发事件回调!!!!

原文地址:https://www.cnblogs.com/hikoukay/p/12112905.html