zookeeper数据存储
1. zookeeper
客户端的Watcher
String就是节点的path,有三大类。
dataWatches:数据watcher
existWatches:节点是否存在的watcher
childWatches:节点的子节点个数变化,包括:0->1,1->2等等,只要数量变化就触发。
对于zk的watcher机制,有几个疑问?
三、ZK的通信协议
分两类:请求和响应协议。是基于TCP/IP的应用层协议,其实就是规定了应用层报文的格式,以及每个字段的含义。客户端和服务端双方都遵守这种约定,脱离了ZK,其他框架是无法识别这种通信协议的。
请求和响应报文格式,网上搜一下一大堆。这里不再赘述
那么回到什么是分布式协调呢?我们就以RPC这种场景来说:
比如我们可以理解上面的图,一半client是service角色,一半client是consumer角色,然后zk提供了这些client之间的协调 -- 充当consumer角色的client必须依赖于充当service角色提供的服务,这可不就是分布式协调的一种嘛(协调其中一半的client依赖另一半)。当然我们可以继续扩展:分布式配置中心Disconf,有个client它的角色可以是管理员(配置员),它是一个进程。它向zk某一个节点配置了XX数据,然后其他所有client同时收到最新配置。这可不就是另外一种协调了嘛(其他client依赖这个配置的值执行业务)。
ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master 选举、分布式锁和分布式队列等功能
乍一看这个定义挺抽象的,一时半会没理解。其实举个例子就容易理解的多,比如你有个资源,我们先简单把该资源当做一个本地文件或本地电影。你为了保证该资源的可靠性,你需要把该资源到3台机器上。那么这三个资源,在互联网上就会有三个url地址:机器1/xxx/xxx/xxx.pdf,机器2/xxx/xxx/xxx.pdf,机器3/xxx/xxx/xxx.pdf。请求方为了访问该资源,肯定不会把这三个地址硬编码到自己本地,这样不易拓展。所以这个时候,就需要一个统一命名服务来封装该资源的三个真实地址,对外只提供一个地址并且永远可以不变。那么这个统一命名服务,我们当然可以用http协议来实现,也可以用zk协议(ZAB协议)来实现。
现在理解了上面的内容,那么我们就容易拓展这个资源的定义了。上面所说的资源,我们可以拓展为一个服务 xxx.xxx.xxx.UserService,该服务的提供方可以有很多个,但是为了封装真实提供方,我们只能对外暴露一个地址那就是xxx.xxx.xxx.UserService。是不是很熟悉?Dubbo的ZK注册中心,就是这么干的。
理解定义我们就不说了,这个很好理解。实际案例咱们可以参考Dubbo的ZK,提供者发布或修改服务真实地址后,消费者可以实时收到变化的通知,然后再去ZK拉取最新数据。这可不就是ZK的发布与订阅嘛,通过Listener观察者模式来实现。应用场景很多:RPC服务发现,配置中心的配置分发等等。
所谓集群管理无在乎两点:是否有机器退出和加入、选举 Master。
不就是ZK的发布订阅嘛,没啥好说的。
这里的maser选举,可不是ZK内部的master选举(两者相差十万八千里)。这里的master选举,是指业务调用方,属于client角色的进程,进行选举。
业务master选举其实很简单,完全没必要像ZK内部选举那样,还要实现一套可靠的选举算法(paxos算法包含了一个提案选举,paxos算法可不止一个选举算法)。ZK本身提供了一个可靠创建唯一节点的API接口,这个接口保证了并发调用只会有一个成功。那么业务master选举,是不是可以转化为多个业务进程并发调用该API接口,谁创建唯一节点成功了,谁就是master了,其他进程就是slave。怎么感觉这么像分布式锁的实现呢?除了少了释放锁的通知操作。。。
软负载均衡也没啥好说的,就是注册与发现的变种,或者说发布与订阅的变种。获取统一命名服务的所有提供者列表,然后通过负载均衡算法在这一堆列表中选择一个,策略可以是随机选择,轮训选择,Hash一致性选择等等。。。Dubbo的负债均衡是实现在消费者调用逻辑里面的,并不在获取列表接口里面,ZK不做负载均衡,基于ZK的应用可以做。
和上面的数据发布与订阅 一模一样 ,不在赘述。
和上面说的Master选举很像,都是一堆client角色的业务调用方,调用创建某唯一节点的API。谁创建成功,谁就拿锁。只不过ZK的底层实现是严格按照顺序来的,所以必然是ZK接收请求的时候,谁第一个谁拿锁。注意可不是client谁先请求谁拿锁。client请求还要经过网络,同时请求是没法确定哪个client先到达的。
但是光创建唯一节点成功还不叫锁,锁天然包含了两个功能:可重入和释放锁唤醒其他等待的client节点。可重入ZK是实现不了,需要业务方自己实现。释放锁的唤醒ZK是通过Listener的通知唤醒的。
我们看下上面的所有应用场景,其实本质上都是调用zk的两个最核心的接口:创建节点和监听节点变化。
ZooKeeper 将数据保存在内存中,这也就保证了高吞吐量和低延迟 (但是内存限制了能够存储的容量不太大,此限制也是保持 znode 中存储的数据量较小的进一步原因)。ZK集群加机器可不能增加内存,为啥呢?因为ZK集群里面的所有数据,都是每台机器保存一份副本。整个集群内存最小的机器,决定整个集群的内存大小。
ZooKeeper 是高性能的。在“读”多于“写”的应用程序中尤其的高性能 ,因为“写”会导致所有的服务器间同步状态。(“读”多于“写”是协调服务的典型场景。)
ZooKeeper 底层其实只提供了两个功能:
2. zookeeper跟php结合做服务配置的处理 该怎么处理
Zookper: 一种分布式应用的协作服务
Zookper是一种分布式的,开源的,应用于分布式应用的协作服务。它提供了一些简单的操作,使得分布式应用可以基于这些接口实现诸如同步、配置维护和分集群或者命名的服务。Zookper很容易编程接入,它使用了一个和文件树结构相似的数据模型。可以使用Java或者C来进行编程接入。
众所周知,分布式的系统协作服务很难有让人满意的产品。这些协作服务产品很容易陷入一些诸如竞争选择条件或者死锁的陷阱中。Zookper的目的就是将分布式服务不再需要由于协作冲突而另外实现协作服务。
设计目标 Zookeeper是简易的
Zookeeper通过一种和文件系统很像的层级命名空间来让分布式进程互相协同工作。这些命名空间由一系列数据寄存器组成,我们也叫这些数据寄存器为znodes。这些znodes就有点像是文件系统中的文件和文件夹。和文件系统不一样的是,文件系统的文件是存储在存储区上的,而zookeeper的数据是存储在内存上的。同时,这就意味着zookeeper有着高吞吐和低延迟。
Zookeeper实现了高性能,高可靠性,和有序的访问。高性能保证了zookeeper能应用在大型的分布式系统上。高可靠性保证它不会由于单一节点的故障而造成任何问题。有序的访问能保证客户端可以实现较为复杂的同步操作。
Zookeeper是可重用的
ZooKeeper Service
image
组成Zookeeper的各个服务器必须要能相互通信。他们在内存中保存了服务器状态,也保存了操作的日志,并且持久化快照。只要大多数的服务器是可用的,那么Zookeeper就是可用的。
客户端连接到一个Zookeeper服务器,并且维持TCP连接。并且发送请求,获取回复,获取事件,并且发送连接信号。如果这个TCP连接断掉了,那么客户端可以连接另外一个服务器。
Zookeeper是有序的
Zookeeper使用数字来对每一个更新进行标记。这样能保证Zookeeper交互的有序。后续的操作可以根据这个顺序实现诸如同步操作这样更高更抽象的服务。
Zookeeper是高效的
Zookeeper的高效更表现在以读为主的系统上。Zookeeper可以在千台服务器组成的读写比例大约为10:1的分布系统上表现优异。
数据结构和分等级的命名空间
Zookeeper的命名空间的结构和文件系统很像。一个名字和文件一样使用/的路径表现,zookeeper的每个节点都是被路径唯一标识
ZooKeeper's Hierarchical Namespace
image
实现
下图显示了ZooKeeper服务的高级组件服务。除了请求处理器,Zookeeper服务器组的每个服务器复制他们自己的每个组件。
ZooKeeper Components
image
replicated database是一个存储在内存中的包含整个数据树的结构。所有的更新操作都做日志到硬盘上了。并且写操作在作用在数据库的时候会序列化存储到硬盘上。
每个ZooKeeper服务器都连接了许多个客户端。客户端连接到一个服务器来提交请求。
3. Zookeeper深入原理
Zookeeper 的视图结构是一个树形结构,树上的每个节点称之为数据节点(即 ZNode),每个ZNode 上都可以保存数据,同时还可以挂载子节点。并且Zookeeper的根节点为 "/"。
在 Zookeeper 中,每个数据节点都是有生命周期的,其生命周期的长短取决于数据节点的节点类型。在 Zookeeper 中有如下几类节点:
每个数据节点中除了存储了数据内容之外,还存储了数据节点本身的一些状态信息(State)。
在Zookeeper 中,事务是指能够改变 Zookeeper 服务器状态的操作,我们也称之为事务操作或更新操作,一般包括数据节点创建与删除、数据节点内容更新和客户端会话创建与失效等操作。对于每一个事务请求,Zookeeper 都会为其分配一个全局唯一的事务ID,用 ZXID 来表示,通常是一个 64 位的数字。每一个 ZXID 对应一次更新操作,从这些 ZXID 中可以间接地识别出 Zookeeper 处理这些更新操作请求的全局顺序。
ZXID 是一个 64 位的数字,其中低 32 位可以看作是一个简单的单调递增的计数器,针对客户端的每一个事务请求,Leader 服务器在产生一个新的事务 Proposal 的时候,都会对该计数器进行加 1 操作;而高 32 位则代表了 Leader 周期 epoch 的编号,每当选举产生一个新的 Leader 服务器,就会从这个 Leader 服务器上取出其本地日志中最大事务 Proposal 的 ZXID,并从该 ZXID 中解析出对应的 epoch 值,然后再对其进行加 1 操作,之后就会以此编号作为新的 epoch,并将低 32 位置 0 来开始生成新的 ZXID。
Zookeeper 中为数据节点引入了版本的概念,每个数据节点都具有三种类型的版本信息(在上面的状态信息中已经介绍了三种版本信息代表的意思),对数据节点的任何更新操作都会引起版本号的变化。其中我们以 dataVersion 为例来说明。在一个数据节点被创建完毕之后,节点的dataVersion 值是 0,表示的含义是 ”当前节点自从创建之后,被更新过 0 次“。如果现在对该节点的数据内容进行更新操作,那么随后,dataVersion 的值就会变成 1。即表示的是对数据节点的数据内容的变更次数。
版本的作用是用来实现乐观锁机制中的 “写入校验” 的。例如,当要修改数据节点的数据内容时,带上版本号,如果数据节点的版本号与传入的版本号相等,就进行修改,否则修改失败。
Zookeeper 提供了分布式数据的发布/订阅功能。一个典型的发布/订阅模型系统定义了一种一对多的订阅关系,能够让多个订阅者同时监听某一个主题对象,当这个主题对象自身状态变化时,会通知所有订阅者,使它们能够做出相应的处理。在 Zookeeper 中,引入了 Watcher 机制来实现这种分布式的通知功能。Zookeeper 允许客户端向服务端注册一个 Watcher 监听,当服务端的一些指定事件触发了这个 Watcher,那么就会向指定客户端发送一个事件通知来实现分布式的通知功能。
从上图可以看出 Zookeeper 的 Watcher 机制主要包括客户端线程、客户端WatchMananger 和 Zookeeper 服务器三部分。在具体工作流程上,简单地讲,客户端在向 Zookeeper 服务器注册 Watcher 的同时,会将 Watcher 对象存储在客户端的 WatchMananger 中。当 Zookeeper 服务器端触发 Watcher 事件后,会向客户端发送通知,客户端线程从 WatchManager 中取出对应的 Watcher 对象来执行回调逻辑。
Watcher是一个接口,任何实现了Watcher接口的类就是一个新的Watcher。Watcher内部包含了两个枚举类:KeeperState、EventType
注 :客户端接收到的相关事件通知中只包含状态及类型等信息,不包括节点变化前后的具体内容,变化前的数据需业务自身存储,变化后的数据需调用get等方法重新获取;
上面讲到zookeeper客户端连接的状态和zookeeper对znode节点监听的事件类型,下面我们来讲解如何建立zookeeper的watcher监听。在zookeeper中采用zk.getChildren(path, watch)、zk.exists(path, watch)、zk.getData(path, watcher, stat)这样的方式为某个znode注册监听。
下表以node-x节点为例,说明调用的注册方法和可监听事件间的关系:
Zookeeper 中提供了一套完善的 ACL(Access Control List)权限控制机制来保障数据的安全。
ACL 由三部分组成,分别是:权限模式(Scheme)、授权对象(ID)和权限(Permission),通常使用“scheme: id:permission”来标识一个有效的ACL 信息。下面分别介绍:
1.7.4、ACL 超级管理员
zookeeper的权限管理模式有一种叫做super,该模式提供一个超管可以方便的访问任何权限的节点
假设这个超管是:super:admin,需要先为超管生成密码的密文
那么打开zookeeper目录下的/bin/zkServer.sh服务器脚本文件,找到如下一行:
这就是脚本中启动zookeeper的命令,默认只有以上两个配置项,我们需要加一个超管的配置项
那么修改以后这条完整命令变成了
之后启动zookeeper,输入如下命令添加权限
在服务器集群初始化阶段,我们以 3 台机器组成的服务器集群为例,当有一台服务器server1 启动的时候,它是无法进行 Leader 选举的,当第二台机器 server2 也启动时,此时这两台服务器已经能够进行互相通信,每台机器都试图找到一个 Leader,于是便进入了 Leader 选举流程。
在zookeeper运行期间,leader与非leader服务器各司其职,即便当有非leader服务器宕机或新加入,此时也不会影响leader,但是一旦leader服务器挂了,那么整个集群将暂停对外服务,进入新一轮leader选举,其过程和启动时期的Leader选举过程基本一致。
假设正在运行的有server1、server2、server3三台服务器,当前leader是server2,若某一时刻leader挂了,此时便开始Leader选举。选举过程如下:
observer角色特点:
为了使用observer角色,在任何想变成observer角色的配置文件中加入如下配置:
并在所有server的配置文件中,配置成observer模式的server的那行配置追加:observer,例如:
4. zkparking数据库配置程序
摘要 这边给您查询分析到每台机器的应用程序都需要连接数据库,而数据库的配置信息(连接信息),这时候放在机器本地的话不方面(机器多,需要一个个改配置信息),这就用到Zookeeper,把数据库的配置信息放到配置中心,利用Zookeeper节点可以存储数据的特性,然后各台机器可以使用JavaAPI去获取Zookeeper中数据库的配置信息。每一个应用都在Zookeeper节点注册监听器,一旦节点信息改变,各台机器就获取信息,使用最新的信息连接数据库,这样优点一是方便了管理(只放置一份数据在配置中心,没必要放到多个机器上去),二是一旦配置改了,就做一个发布的动作即可。