zookeeper
第二章、zookeeper的基础
1、解压 tar -zxvf zookeeper-3.4.5.tar.gz ; 打包 tar -czvf *.tar.gz dirname
2、修改conf中zoo_sample.cfg名字为zoo.cfg
3、启动zookeeper服务端zkServer.sh
1)服务端常用命令
- 1. 启动ZK服务: sh bin/zkServer.sh start-foreground
- 2. 查看ZK服务状态: sh bin/zkServer.sh status
- 3. 停止ZK服务: sh bin/zkServer.sh stop
- 4. 重启ZK服务: sh bin/zkServer.sh restart
2) ./zkServer.sh start出现错误:
[email protected]:/data/zookeeper-3.3.6/bin$ ./zkServer.sh start
JMX enabled by default
Using config: /data/zookeeper-3.3.6/bin/../conf/zoo.cfg
Starting zookeeper ... ./zkServer.sh: 103: ./zkServer.sh: cannot create /tmp/zookeeper/zookeeper_server.pid: Directory nonexistent
FAILED TO WRITE PID
解决方法:以上的启动过程发生了一个错误,说是无法创建/tmp/zookeeper/zookeeper_server.pid,zookeeper启动后,该文件中保存进程id,我们可以手动创建该目录。
在zookeeper目录下输入命令 mkdir -p tmp/zookeeper
如果要创建目录A并创建目录A的子目录B,没有用-p的情况下是mkdir 2次 如果用-p 可以直接创建2个目录 mkdir -p 目录A/子目录B就可以
4、启动zookeeper服务端zkServer.sh
1)客户端常用命令
- 1. 显示根目录下、文件: ls / 使用 ls 命令来查看当前 ZooKeeper 中所包含的内容
- 2. 显示根目录下、文件: ls2 / 查看当前节点数据并能看到更新次数等数据
- 3. 创建文件,并设置初始内容: create /zk "test" 创建一个新的 znode节点“ zk ”以及与它关联的字符串
- 4. 获取文件内容: get /zk 确认 znode 是否包含我们所创建的字符串
- 5. 修改文件内容: set /zk "zkbak" 对 zk 所关联的字符串进行设置
- 6. 删除文件: delete /zk 将刚才创建的 znode 删除
- 7. 退出客户端: quit
- 8. 帮助命令: help
2)创建节点操作然后删除
ls /查看当前zk中的内容
create /workers "" 空字符串不希望在这个节点保存数据
delete /workders
ls /
quit
5、会话的状态及状态的转换
6、zookeeper单机集群配置
解压Zookeeper的安装包到/opt目录下,这里用三个目录来代表三个Zookeeper实例,分别是/opt/zookeeper1,/opt/zookeeper2和/opt/zookeeper3.
1). 首先编辑每个Zookeeper目录下的conf/zoo.cfg文件。三个配置配置文件的内容分别如下
- $ cat /opt/zookeeper1/conf/zoo.cfg
- tickTime=2000
- dataDir=/opt/zookeeper1/data
- clientPort=2181
- initLimit=10
- syncLimit=5
- server.1=127.0.0.1:2881:3881
- server.2=127.0.0.1:2882:3882
- server.3=127.0.0.1:2883:3883
- $ cat /opt/zookeeper2/conf/zoo.cfg
- tickTime=2000
- dataDir=/opt/zookeeper2/data
- clientPort=2182
- initLimit=10
- syncLimit=5
- server.1=127.0.0.1:2881:3881
- server.2=127.0.0.1:2882:3882
- server.3=127.0.0.1:2883:3883
- $ cat /opt/zookeeper3/conf/zoo.cfg
- tickTime=2000
- dataDir=/opt/zookeeper3/data
- clientPort=2183
- initLimit=10
- syncLimit=5
- server.1=127.0.0.1:2881:3881
- server.2=127.0.0.1:2882:3882
- server.3=127.0.0.1:2883:3883
其中有几点需要注意
* dataDir: 三个Zookeeper实例的dataDir目录要区别开,这里分别指定到各个Zookeeper实例目录下的data目录。
* clientPort: 定义Zookeeper客户端连接Zookeeper服务端时使用的端口,这里因为是在一台机器上做的集群,所以三个实例的端口要区分开。服务的监听端口。
* server.: 定义Zookeeper集群的各个实例的的ip和端口,这里因为是在一台机器上做的集群,所以IP都定义的是127.0.0.1,但是后面的端口要区分开。
initLimit:多少个心跳时间内,允许其他server连接并初始化数据,如果ZooKeeper管理的数据较大,则应相应增大这个值
dataDir:用于存放内存数据库快照的文件夹,同时用于集群的myid文件也存在这个文件夹里(注意:一个配置文件只能包含一个dataDir字样,即使它被注释掉了。)
dataLogDir:用于单独设置transaction log的目录,transaction log分离可以避免和普通log还有快照的竞争
syncLimit:多少个tickTime内,允许follower同步,如果follower落后太多,则会被丢弃。
2).创建data目录和实例id文件
- mkdir /opt/zookeeper1/data
- mkdir /opt/zookeeper2/data
- mkdir /opt/zookeeper3/data
- echo 1 > /opt/zookeeper1/data/myid 建立新文件并且内容为1
- echo 2 > /opt/zookeeper2/data/myid
- echo 3 > /opt/zookeeper3/data/myid
这里要注意需要在每个Zookeeper的dataDir目录下创建myid文件,内容是记录各个Zookeeper的实例ID。
3) 启动Zookeeper服务
分别进入各个Zookeeper的bin目录,然后运行“./zkServer.sh start”来启动一个Zookeeper服务。
4) 客户端连接
随便进入一个Zookeeper的bin目录,然后运行下面的命令来分别连接Zookeeper服务。
- ./zkCli.sh -server 127.0.0.1:2181
- ./zkCli.sh -server 127.0.0.1:2182
- ./zkCli.sh -server 127.0.0.1:2183
在其中的一个client上创建一个znode节点
- create /mykey myvalue
然后在别的client上查看新创建zonde节点
- get /mykey
5)查看Zookeeper状态
启动Zookeeper之后,由于Zookeeper自己会有一套leader的选举算法,所以此时如果想知道那个Zookeeper是leader可以在各个Zookeeper的bin目录运行“./zkServer.sh status”命令来查看。
如果是Leader
- $ ./zkServer.sh status
- JMX enabled by default
- Using config: /opt/zookeeper1/bin/../conf/zoo.cfg
- Mode: leader
如果不是Leader
- $ ./zkServer.sh status
- JMX enabled by default
- Using config: /opt/zookeeper3/bin/../conf/zoo.cfg
- Mode: follower
此时可以把leader的那个节点停了,然后再看查看其它两个Zookeeper实例,此时剩下的两个Zookeeper实例就会再选举出一个leader。
6)主从模式例子实现
1)create -e /master "master1.example.com.2223" -e标识临时节点
2)stat命令可以得到一个zode节点的属性,并允许我们在已经存在的zode节点上设置监视点,通过在路径后面设置参数true来添加监视点;state /master true
当节点崩溃时显示:WatchedEvent state:SyncConnected type:NodeDeleted path /master
3)从节点,任务,分配
主节点会监视/works,/task节点的数据变化 :ls /works true; ls /task true通过true参数,可以设置对应zode的子节点变化的监视点
从节点要通知主节点,告知从节点可以执行任务,可以在从节点通过创建/works的子节点进行通知
从节点创建一个 /assign/work1.example.com来接受任务分配,并通过参数true的ls命令来监视这个节点的变化
4)客户端:向系统提交任务
create -s /task/task - "cmd"
Create /tasks/task-00000000000
由于主节点监听了/task,会检查这个新的任务,获取可用的从节点,将任务分配给从节点
create /assign/worker1.example.com/task-0000000000
从节点会收到通知,确认该任务是否是分配给自己的,一旦从节点完成任务的执行,它就会在/tasks中添加一个状态zode
create /tasks/task-00000000/status "done"
客户端接到一个通知 get /tasks/task-0000000000 status
第三章、zookeeper客户端的使用
1、客户端连接服务的命令:
./zkCli.sh -timeout(心跳时间毫秒) 0 -r(只读) -server ip(服务ip):port(端口)
如: ./zkCli.sh -timeout 5000 -server 127.0.0.1:2181
2、输入h可以查看客户端有哪些命令
3、在其中的一个client上创建一个znode节点
1)create /mykey dsfsdf
2)get /mykey
zookeeper对节点数据的修改都认为是一次事务,每次事务都需分配个事务id,
cZxid:该节点创建时的事务id
ctime:该节点创建的时间
mZxid:该节点最后一次更新的事务id
mtime:该节点修改时间
pZxid:该节点的子节点列表修改的事务id(添加子节点,删除子节点,不包括修改子节点的内容)
cversion:子节点的版本号
dataVersion:数据版本号
aclVersion:权限版本号
ephemeralOwner :创建该临时节点的事务id,如果为持久节点,则默认为0x0
dataLength:节点存放数据的长度
numChildren:子节点的个数
3)ls2 /mykey
4)stat /mykey 查看节点的状态信息
5)create [-s](顺序节点) [-e] (临时节点)path data acl
顺序节点如截图,可以用于分布式的主键生成器
6)quit退出客户端
7)set path value 修改节点的数值,版本号dataversion增加
8)delete删除指定节点(只能删除没有字节点的节点) rmr命令递归删除
9 )setquota -n|-b val path 设置节点的配额(子节点的数量或者数据的长度)
超出配额只会在日志里有警告信息,不会抛出异常
10)列出节点的配额 listquota path
-1表示没有限制
11)删除节点的配额 delquota [-n|-b] path
12)history 显示对应的编号和命令
redo cmdno 重新执行命令编码
13)acl权限控制
ACL aclIp = new ACL(Perms.READ,new Id("ip","192.168.1.105")); ACL aclDigest = new ACL(Perms.READ|Perms.WRITE,new Id("digest",DigestAuthenticationProvider.generateDigest("jike:123456"))); ArrayList<ACL> acls = new ArrayList<ACL>(); acls.add(aclDigest); acls.add(aclIp); //zookeeper.addAuthInfo("digest", "jike:123456".getBytes()); String path = zookeeper.create("/node_4", "123".getBytes(), acls, CreateMode.PERSISTENT); System.out.println("return path:"+path);
如果不是192.168.1.105连接服务,获取节点信息失败,因为没有权限
所以要注册权限信息 addauth digest jeke:123456
创建一个有权限的节点
第四章、开始使用Zookeeper的API
(源码下载: https://github.com/apache/zookeeper)
(idea导入zookeeper:http://www.tuicool.com/articles/vE7bIf)
应用命名服务
顾名思义,就是提供名称的服务,例如数据库表格ID,一般用得比较多的有两种ID,一种是自动增长的ID,一种是UUID(9291d71a-0354-4d8e-acd8-64f7393c64ae),两种ID各自都有缺陷,自动增长的ID局限在单库单表中使用,不能在分布式中使用,UUID可以在分布式中使用但是由于ID没有规律难于理解,我们可以借用ZK来生成一个顺序增长的,可以在集群环境下使用的,命名易于理解的ID
1、zookeeper的api围绕zookeeper句柄而构建,这个句柄代表与zookeeper之间的一个会话。如果与一个服务器的会话断开,这个会话就会迁移到另一台zookeeper服务器上。
2、创建句柄的构造函数
Zookeeper( String connectString, int sessionTimeout, Watcher watcher)
connectString:主机名字和端口
sessionTimeout:一般设置超时时间为5到10秒,即:5000到10000
Watcher:客户端使用Watcher接口来监控与zookeeper之间的会话的健康状况
3、程序结束后,默认是到了超时时间,服务器才会结束会话。需要调用Zookeeper.close()方法会销毁Zookeeper对象实例所表示的会话。这是使会话立即消失的方式
注意:请不要试着自己去管理客户端的连接,客户端会监控与服务之间的连接,不仅会告诉我们连接发生的问题,还会主动尝试重新建立连接。
4、获取管理权(由于没太读懂,略):在群兽选举的算法中,所有潜在的主节点进程尝试创建/master节点,但只有一个成功,这个成功的进程成为主节点
我们将会在程序中添加
String serverId=Integer.toHexString(random.nexInt());
void runForMaster(){
zk.create("/master",serverId.getBytes(),OPEN_ACL_UNSAFE,CreateMode.EPHEMERAL);
}
创建会产生两种异常,KeeperException(ConnectionLossException)和InterruptedException,当处理ConnectionLossException异常时,我们需要找出那个进程创建的/master节点,如果进程是自己的,就开始成为群首角色。我们通过getData方法来处理
byte[] getData(String path,bool watch,Stat stat)
5、异步获取管理权
create方法的异步调用,调用返回前不会等待create命令完成,所以无需关心异常
void create(String path,List<ACL> acl,CreateMode createMode,AsyncCallback.StringCallback cb,Object ctx)
比同步的方法多了2个参数:提供回调方法的对象,用户指定上下文信息
回调函数实现只有一个方法的StirngCallback接口:
void processResult(int rc,String path,Object ctx,String name)
rc:返回调用的结构,返回ok或者异常对应的编码
path:路径
ctx:上下文
name:节点名称
6、注册从节点
第五章、zookeeper选举
master节点对应的服务器宕机,或者zk与服务器之间的网络不稳定,都会导致主节点被删除,从而发生master选举,优化的策略是判断最近一次的master是自己吗,优先让最近一次的master争选为master,防止资源的迁移导致系统的开销
第六章、运行zookeeper
1、基本配置参数
clientPort:客户端所连接的服务器所监听的TCP端口
tickTime:心跳时间,单位为毫秒
leaderServer:配置yes或者no,指示群首服务器是否为客户端提供服务
2、日志
1)事务日志
事务日志指zookeeper系统在正常运行过程中,针对所有的更新操作,在返回客户端“更新成功”的响应前,zookeeper会保证已经将本次更新操作的事务日志已经写到磁盘上,只有这样,整个更新操作才会生效。在datalog/目录下存在一个文件夹version-2,该文件夹中保存着事物日志文件,日志文件的命名规则为log.**,文件大小为64MB,**表示写入该日志的第一个事务的ID,十六进制表示。
2)快照日志
zookeeper的数据在内存中是以树形结构进行存储的,而快照就是每隔一段时间就会把整个DataTree的数据序列化后存储在磁盘中,这就是zookeeper的快照文件。zookeeper快照日志的存储路径同样可以在zoo.cfg中查看,如上文截图所示。访问dataDir路径可以看到version-2文件夹,zookeeper快照文件的命名规则为snapshot.**,其中**表示zookeeper触发快照的那个瞬间,提交的最后一个事务的ID。
3)log4j日志
zk采用slf4j库(java简易日志门面)作为日志的抽象层,默认使用log4j进行实际的日志记录功能,conf目录下的log4j.properties,bin目录下的zookeeper.out输出