zookeeper安装及使用
Last updated
Last updated
根据官方介绍,Zookeeper提供配置信息管理,命名,分布式协作任务和组服务的中心式服务。主要用在分布式的环境中,简化分布式开发协作任务,让开发人员主要关注业务。
Zookeeper从文件系统的API得到启发,并提供一组API。Zookeeper的文件树结构如下图所示:Zookeeper的文件树结构
上图中的节点称为znode,采用类似文件系统的层次的树状结构进行元数据的管理。并且可以创建,删除节点或者更新节点内容。Zookeeper提供了四种不同类型的znode。
持久persistent节点:持久节点是非常有用的节点,即使创建者不属于应用系统了,节点数据也不会丢失。节点只能通过删除才能清除。持久有序persistent-sequential节点:一个有序节点被分配一个唯一的单调递增的整数,当节点被创建时,会在路径后面追加一个序号。临时ephemeral节点:当创建此节点的客户端会话超时或者主动关闭时,节点会被删除。可以像持久节点一样被主动删除。临时有序ephemeral-sequential节点:一个有序节点被分配一个唯一的单调递增的整数,当节点被创建时,会在路径后面追加一个序号。但像临时节点一样超时或者主动关闭时,节点会被删除。Zookeeper使用监视和通知模式避免客户端轮询获取节点变更。我们创建一个监听,当阶段更新或者删除时,会通知客户端。
Zookeeper管理协作的关键数据,不适合管理海量的数据存储。我们应该把存储数据和协作数据分开管理,充分发挥zookeeper的优势。
Zookeeper有两种运行模式,一种是独立模式,另一种是仲裁模式。独立模式就是一个独立的服务器,就像一个单体系统一样。仲裁模式下,数据在各个服务器中进行复制。在仲裁模式下需要一个法人数量,就是使zookeeper能正常工作的最小服务器的数量。通常用多数原则,最小法人数量大于总数量的一半。
建议集群的数量为奇数,比如5个,法人数量为3,可以运行崩溃的服务器为2,如果集群为4,法人数量也是3,此时允许服务器崩溃的服务器为1个,系统会更脆弱。
Zookeeper会话,在客户端和服务器进行连接是需要创建一个会话,客户端和服务器的所有操作都建立在这个会话的基础之上。
客户端在创建一个zookeeper句柄时,就会建立一个会话,客户端通过TCP协议和服务器进行通信。当客户端连接的当前服务器故障时,会话会转移到其他服务器上,应用并不需要知道。
Apache官方最新版本为:3.4.8下载地址:http://mirrors.cnnic.cn/apache/zookeeper/zookeeper-3.4.8/zookeeper-3.4.8.tar.gz
启动服务/etc/systemd/system/zookeeper.service
ZooKeeper 在运行过程中会在事物日志目录下建立一个名字为version-2的子目录,该目录确定了当前ZooKeeper使用的事务日志格式版本号。也就足说,等到下次某个ZooKeeper版本对事务日志格式进行变更时,这个目录也会有所变更
日志写入
1.创建事物日志文件
当ZooKeeper服务器启动完成需要进行第一次事务日志的写入,或是上一个事务日志写满的时候,都会处于与事务日志文件断开的状态,即ZooKeeper服务器没有和任意一个日志文件相关联。因此,在进行事务日志写入前,Zookeeper首先会判断FileTxnLog组件是否已经关联了一个可写的事物日志文件。如果没有关联上事务日志文件,那么就会使用与该事务操作关联的ZXID作为后缀创建一个事物日志文件,同时构建事务日志文件头信息(包含魔数magic、事务日志格式版本version和dbid),并立即写入这个事物日志文件中去。
2.确定事务日志文件是否需要扩容(预分配)。
当检测到当前务日志文件剩余空间不足4096字节(4KB)时,就会开始进行文件空间扩容。在现行文件大小的基础上,将文件大小增加65536KB (64MB),然后使用“0”(\0)填充这些被扩容的文件空间。
那么ZooKeeper为什么要进行事务日志文件的磁盘空间预分配呢?对客户端的每一次事务操作,ZooKeeper都会将其写人事务日志文件中。因此,事物日志的写入性能直接决定了ZooKeeper服务器对事务请求的响应,也就是说,事务写入近似可以被看作是一个磁盘I/O的过程。严格地讲,文件的不断追加写入操作会触发底层磁盘I/O为文件开辟新的磁盘块,即磁盘Seek。因此,为了避免磁盘Seek的频率,提高磁盘I/O的效率,ZooKeeper在创建事物日志的时候就会进行文件空间“预分配”——在文件创建之初就向操作系统预分配一个很大的磁盘块,默认是64MB,而一旦已分配的文件空间不足4KB 时,那么将会再次“预分配”,以避免随着每次事物的写入过程中文件大小增长带来的Seek开销,直至创建新的事务日志。
3.事物序列化
事务序列化包括对事务头和事务体的序列化,分别是对TxnHeader(事务头)和Record (事务体)的序列化。其中事务体又可分为会话创建事务(CreateSessionTxn)、节点创建事务(CreateTxn)、节点删除事务(DeleteTxn)和节点数据更新事务 (SetDataTxn)等。
4.生成Checksum。
为了保证事务日志文件的完整性和数据的准确性,ZooKeeper在将事务日志写入文件前,会根据步骤3中序列化产生的字节数组来计算Checksum。ZooKeeper默认使用Adler32算法来计算Checksum值。
5.写入事务日志文件流。
将序列化后的事务头、事务体及Checksum值写入到文件流中去。此时由于 ZooKeeper使用的足BufferedOutputStream,因此写人的数据并非真正被写入到磁盘文件上。
6.事务日志刷入磁盘。
在步骤5中,已经将事务操作写人文件流中,但是由于缓存的原因,无法实时地写入磁盘文件中,因此我们需要将缓存数据强制刷入磁盘中,在步骤1中我们已经将每个事物日志文件对应的文件流放入streamsToFlush,因此这里会从 streamsToFlush 中提取出文件流,并调用FileChannel.force(boolean metaData)接口来强制将数据刷入磁盘文件中去。force接口对应的其实是底层的fsync接口,是一个比较耗费磁盘I/O资源的接口,因此ZooKeeper允许用户控制是否需要主动调用该接口,以通过系统属性zookeeper.forceSync来设置。
数据加载的整体流程
快照文件加载流程
应用通过客户端对zookeeper服务实现调用,应用程序通过客户端和zookeeper服务器之间进行交互。Zookeeper架构