基本 *** 作:
create /xxx abc: 创建持久节点,值为abc create -e /xxx: 创建临时节点 create -s /xxx: 创建持久序号节点 create -s -e /xxx: 创建临时序号节点 create -c /xxx: 创建容器节点,当容器中没有任何子节点,该容器会被定期删除(60s) ls / : 获得所有结点 ls /xxx: 获得xxx的子节点 ls -R /xxx : 递归查询,获得xxx所有的子孙节点 get /xxx: 获得xxx的数据 get -s /xxx: 获得xxx的详细数据 //删除 delete /xxx: 删除xxx //乐观锁删除 delete -v [version] /xxx : 删除xxx
zk的数据持久化
zk的数据使运行在内存中,zk提供了两种持久化机制:
- 事务日志
zk把执行的命令以日志形式保存在dataLogDir指定的路径中的文件中
**- 数据快照 **
zk会在一定的时间间隔内做一次内存数据的快照,把该时刻的内存数据保存在快照文件中
zk在恢复数据时,先恢复快照文件中的数据到内存中,再用日志文件中的数据做增量恢复
权限设置:注册当前会话的账号和密码:
addauth digest xiaowang:123456
创建结点并设置权限:
create /test-node abc auth:xiaowang:123456:cdwra
在另一个会话中,必须先使用账号密码,才能拥有 *** 作该节点的权限
Curator客户端的使用Curator是一套zookeeper客户端框架,封装了大部分zookeeper的功能,比如leader选举、分布式锁…
1、maven引入依赖
org.apache.curator curator-framework2.12.0 org.apache.curator curator-recipes2.12.0 org.apache.zookeeper zookeeper//若不冲突可不加 org.slf4j slf4j-log4j123.7.0
配置文件
curator.retryCount=5 curator.elapsedTimeMs=5000 curator.connectString=192.168.132.129:2181 curator.sessionTimeoutMs=60000 curator.connectionTimeoutMs=5000
配置类:
@Data @Component @ConfigurationProperties(prefix = "curator") public class WrapperZK { private int retryCount; private int elapsedTimeMs; private String connectString; private int sessionTimeoutMs; private int connectionTimeoutMs; }
@Configuration public class CuratorConfig { @Autowired WrapperZK wrapperZK; @Bean(initMethod = "start") public Curatorframework curatorframework(){ return CuratorframeworkFactory.newClient( wrapperZK.getConnectString(), wrapperZK.getSessionTimeoutMs(), wrapperZK.getConnectionTimeoutMs(), new RetryNTimes(wrapperZK.getRetryCount(),wrapperZK.getElapsedTimeMs()) ); } }
test类
@Slf4j @SpringBootTest public class test { @Autowired Curatorframework curatorframework; @Test void createNode() throws Exception{ //添加持久结点 String path1 = curatorframework.create().forPath("/curator-node","abc".getBytes()); //添加临时序号节点 // String path2 = curatorframework.create().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath("/curator-node","abc".getBytes()); System.out.println(String.format("curator create node :%s successfully,",path1)); System.in.read(); } @Test void testGetData() throws Exception { byte[] bytes = curatorframework.getData().forPath("/curator-node"); System.out.println(new String(bytes)); } @Test void testSetData() throws Exception { curatorframework.setData().forPath("/curator-node","changed".getBytes()); byte[] bytes = curatorframework.getData().forPath("/curator-node"); System.out.println(new String(bytes)); } @Test void testCreatWithParent() throws Exception{ String pathWithParent = "/node-parent/sub-node-1"; String path = curatorframework.create().creatingParentsIfNeeded().forPath(pathWithParent); System.out.println(String.format("curator create node :%s successfully,",path)); } @Test void testDelete() throws Exception{ String pathWithParent = "/node-parent"; curatorframework.delete().guaranteed().deletingChildrenIfNeeded().forPath(pathWithParent); } }zk实现分布锁 1.zk中锁的种类:
读锁:大家都可以读。要想上读锁的前提:之前的锁没有写锁。
写锁: 只有得到写锁才能写。要想上写锁的前提:之前没有任何锁。
2.zk如何上读锁
创建一个临时序号节点,节点的数据是read,表示是读锁
获取当前zk中序号比自己小的所有节点
判断最小节点是否是读锁:
如果不是读锁的话,则上锁失败,为最小结点设置监听。阻塞等待,zk的watch机制会当最小节点发生变化时通知当前节点,于是再执行第二步的流程
如果是读锁,则上锁成功
创建一个临时序号节点,节点的数据是write,表示是写锁获取当前zk中的所有节点判断自己是否是最小的节点:
- 如果是,则上写锁成功如果不是,说明前面还有锁,则上锁失败,监听最小的节点,如果最小节点有变化,则返回第二步
如果用上述的上锁方式,只要有节点发生变化,就会触发其他节点的监听事件,这样对zk的压力非常大,–羊群效应。
可以调整为链式监听,解决这个问题。
zk的watch机制:
把watch理解为注册在特定Znode上的触发器。当这个Znode发生改变,也就是调用了create,delete,setData方法的时候,将会触发Znode上注册的对应事件,请求watch的客户端会接收到异步通知。
具体交互过程如下:
**get -w /xxx **
2.zkCli客户端使用watch
create /test xxx get -w /test 一次性监听节点 ls -w /test 监听目录,创建和删除子节点会收到通知。子节点中新增节点不会收到通知 ls -R -w /test 对于子节点中子节点的变化,但内容的变化不会收到通知
3.Curator使用watch
@Test public void addNodeListener() throws Exception { NodeCache nodeCache = new NodeCache(curatorframework, "/curator-node"); nodeCache.getListenable().addListener(new NodeCacheListener() { @Override public void nodeChanged() throws Exception { log.info("{} path nodeChanged:","/curator-node"); printNodeData(); } }); nodeCache.start(); System.in.read(); } public void printNodeData() throws Exception { byte[] bytes = curatorframework.getData().forPath("/curator-node"); log.info("data:{}",new String(bytes)); }5.Curator实现读写锁 1)获取读锁
@Test public void testGetReadLock() throws Exception { //读写锁 InterProcessReadWriteLock interProcessReadWriteLock = new InterProcessReadWriteLock(curatorframework,"/lock1"); //获取读锁对象 InterProcessLock interProcessLock = interProcessReadWriteLock.readLock(); System.out.println("等待获取读锁对象!"); //获取锁 interProcessLock.acquire(); for (int i = 0; i < 100; i++) { Thread.sleep(3000); System.out.println(i); } //释放锁 interProcessLock.release(); System.out.println("等待释放锁"); }2)获取写锁
@Test public void testGetWriteLock() throws Exception { //读写锁 InterProcessReadWriteLock interProcessReadWriteLock = new InterProcessReadWriteLock(curatorframework,"/lock2"); //获取读锁对象 InterProcessLock interProcessLock = interProcessReadWriteLock.writeLock(); System.out.println("等待获取写锁对象!"); //获取锁 interProcessLock.acquire(); for (int i = 0; i < 100; i++) { Thread.sleep(3000); System.out.println(i); } //释放锁 interProcessLock.release(); System.out.println("等待释放锁"); }zk集群 1.zk集群角色:
leader:处理集群的所有事务请求,集群只有一个leaderfollower:只能处理读请求,参与leader选举observer:只能处理读请求,提升集群读的性能,但不能参与leader选举 2.集群搭建
1)创建4个节点的myid,并设值
2)在conf文件中创建4个zoo.cfg
其中zoo1.cfg配置如下:
# The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/opt/zookeeper/zkdata/zk1 # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1 server.1=192.168.132.129:2001:3001 server.2=192.168.132.129:2002:3002 server.3=192.168.132.129:2003:3003 server.4=192.168.132.129:2004:3004:observer
3)启动服务器
[root@192 bin]# ./zkServer.sh start ../conf/zoo1.cfg [root@192 bin]# ./zkServer.sh start ../conf/zoo2.cfg [root@192 bin]# ./zkServer.sh start ../conf/zoo3.cfg [root@192 bin]# ./zkServer.sh start ../conf/zoo4.cfg
4)查看集群状态
[root@192 bin]# ./zkServer.sh status ../conf/zoo1.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo1.cfg Client port found: 2181. Client address: localhost. Mode: follower [root@192 bin]# ./zkServer.sh status ../conf/zoo2.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo2.cfg Client port found: 2182. Client address: localhost. Mode: leader [root@192 bin]# ./zkServer.sh status ../conf/zoo3.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo3.cfg Client port found: 2183. Client address: localhost. Mode: follower [root@192 bin]# ./zkServer.sh status ../conf/zoo4.cfg ZooKeeper JMX enabled by default Using config: ../conf/zoo4.cfg Client port found: 2184. Client address: localhost. Mode: observer
可见zk2为leader,zk4为observer,其他为follower
5)连接Zookeeper集群
./bin/zkCli.sh -server 192.168.132.129:2181,192.168.132.129:2182,192.168.132.129:2183
3.ZAB协议1)什么是ZAB协议?
zk作为非常重要的分布式协调组件,需要进行集群部署,集群中会以一主多从的形式进行部署。zk为了保证数据的一致性,使用了ZAB协议,这个协议解决了zk的崩溃恢复和主从数据同步的问题。
2)ZAB协议定义的四种节点状态
Looking:选举状态Following:Follower节点所处状态Leading:Leader节点所处状态Observing:观察者节点所处状态
3)集群上线时的Leader选举过程:
4)崩溃恢复时的Leader选举过程:
leader建立完后,leader周期性不断向follower发送心跳(ping命令,没有内容的socket)。当leader崩溃后,follower发现socket通道已关闭,于是follower开始进入到looking状态,重新回到上一节中的leader选举状态,此时集群不能对外提供服务。
5)主从服务器之间的数据同步:
6)NIO和BIO的应用
NIO:
用于被客户端连接的2181端口,使用的是NIO模式与客户端建立连接
客户端开启Watch时,也使用NIO,等待Zookeeper服务器的回调
BIO:
集群在选举时,多个节点之间的投票通信端口,使用BIO进行通信
CAP理论 1.CAP定理:一个分布式系统最多只能同时满足一致性,可用性和分区容错性这三项中的两项。
一致性
更新 *** 作成功并返回客户端完成后,所有节点在同一时间的数据完全一致。
可用性
服务一直可用,而且是正常响应时间。
分区容错性(必须)
分布式系统在遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务。——避免单点故障,就要进行冗余部署,冗余部署相当于是服务的分区,这样的分区就具有容错性。
2.base理论base理论是对CAP理论的延申,核心思想是即使无法做到强一致性(CAP理论中的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性。
基本可用
基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。
电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现。
软状态
允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。mysql replication 的异步复制就是一种体现。
最终一致性
系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。
满足一致性或可用性的服务。——避免单点故障,就要进行冗余部署,冗余部署相当于是服务的分区,这样的分区就具有容错性。
2.base理论base理论是对CAP理论的延申,核心思想是即使无法做到强一致性(CAP理论中的一致性就是强一致性),但应用可以采用适合的方式达到最终一致性。
基本可用
基本可用是指分布式系统在出现故障的时候,允许损失部分可用性,即保证核心可用。
电商大促时,为了应对访问量激增,部分用户可能会被引导到降级页面,服务层也可能只提供降级服务。这就是损失部分可用性的体现。
软状态
允许系统存在中间状态,而该中间状态不会影响系统整体可用性。分布式存储中一般一份数据至少会有三个副本,允许不同节点间副本同步的延时就是软状态的体现。mysql replication 的异步复制就是一种体现。
最终一致性
系统中的所有数据副本经过一定时间后,最终能够达到一致的状态。弱一致性和强一致性相反,最终一致性是弱一致性的一种特殊情况。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)