Zookeeper

简单介绍

Apache Zookeeper是开发和维护开源服务器的服务,它能够实现高度可靠的分布式协调。

安装Zookeeper(无需安装)


  1. wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.10/zookeeper-3.4.10.tar.gz
  2. tar zxvf zookeeper-3.4.10.tar.gz

安装Zookeeper C扩展支持


  1. cd zookeeper-3.4.8/src/c
  2. ./configure --prefix=/usr/
  3. make
  4. make install

安装php的zookeeper扩展


  1. wget https://pecl.php.net/get/zookeeper-0.6.2.tgz
  2. tar zxvf zookeeper-0.6.2.tgz
  3. cd zookeeper-0.6.2
  4. phpize
  5. ./configure --with-libzookeeper-dir=/usr/
  6. $ make
  7. $ make install

启动zookeeper server


  1. # {zookeeperserver}代表你zookeeper解压的目录
  2. mkdir -p /project/zookeeper/demo/data
  3. #zoo.conf 是默认启动所加载的配置文件
  4. cp /{zookeeperserver}/conf/zoo_sample.cfg /{zookeeperserver}/conf/zoo.cfg
  5. /{zookeeperserver}/bin/zkServer start

zookeeper client 测试


  1. /{zookeeperserver}/bin/zkCli.sh -server 127.0.0.1:2181
  2. # [zk: 127.0.0.1:2181(CONNECTED) x] 客户端连接信息shell
  3. [zk: 127.0.0.1:2181(CONNECTED) 3] ls /
  4. [zookeeper]
  5. [zk: 127.0.0.1:2181(CONNECTED) 4] create /test qkl001
  6. Created /test
  7. [zk: 127.0.0.1:2181(CONNECTED) 5] create /zgq zgq002
  8. Created /zgq
  9. [zk: 127.0.0.1:2181(CONNECTED) 6] ls /
  10. [zookeeper, test, zgq]
  11. [zk: 127.0.0.1:2181(CONNECTED) 5] delete /zgq
  12. Created /zgq
  13. [zk: 127.0.0.1:2181(CONNECTED) 7] quit

PHP下实践

zookeeper类信息


  1. Zookeeper Zookeeper
  2. -- Zookeeper::addAuth 指定应用程序凭据
  3. -- Zookeeper::connect 创建与Zookeeper沟通的句柄
  4. -- Zookeeper::__construct 创建与Zookeeper沟通的句柄
  5. -- Zookeeper::create 同步创建节点
  6. -- Zookeeper::delete 同步删除Zookeeper中的一个节点
  7. -- Zookeeper::exists 同步检查Zookeeper节点的存在性
  8. -- Zookeeper::get 同步获取与节点关联的数据。
  9. -- Zookeeper::getAcl 同步地获取与节点关联的ACL
  10. -- Zookeeper::getChildren 同步列出节点的子节点
  11. -- Zookeeper::getClientId 返回客户端会话ID,仅在连接当前连接时才有效(即最后观察者状态为ZooOnCeleDelphi状态)
  12. -- Zookeeper::getRecvTimeout 返回此会话的超时,如果连接当前连接(只有上次观察者状态为ZooOnCeleTytStand状态)才有效。此值可能在服务器重新连接后发生更改。
  13. -- Zookeeper::getState 获取Zookeeper连接的状态
  14. -- Zookeeper::isRecoverable 检查当前的Zookeeper连接状态是否可以恢复
  15. -- Zookeeper::set 设置与节点关联的数据
  16. -- Zookeeper::setAcl 同步设置与节点关联的ACL
  17. -- Zookeeper::setDebugLevel 设置库的调试级别
  18. -- Zookeeper::setDeterministicConnOrder 启用/禁用仲裁端点顺序随机化
  19. -- Zookeeper::setLogStream 设置库用于日志记录的流
  20. -- Zookeeper::setWatcher 设置观察函数

客户端操作


  1. zkCli.cmd
  2. # output 表示连接成功
  3. WatchedEvent state:SyncConnected type:None path:null
  4. [zk: localhost:2181(CONNECTED) 0]
  5. # 以下是操作命令
  6. ls /
  7. create /ztest 1

获取节点信息(Zookeeper::get)


  1. # get.php
  2. $zoo = new Zookeeper('192.168.1.45:2181');
  3. $r = $zoo->get( '/ztest');
  4. var_dump($r);

获取节点信息(Zookeeper::get)并设置watcher


  1. # get.php
  2. class ZookeeperDemo extends Zookeeper
  3. {
  4. public function watcher($type, $state, $key)
  5. {
  6. var_dump($type);
  7. var_dump($state);
  8. var_dump($key);
  9. if ($type == 3) {
  10. var_dump($this->get('/zgetw'));
  11. // Watcher gets consumed so we need to set a new one
  12. $this->get('/zgetw', array($this, 'watcher'));
  13. }
  14. }
  15. }
  16. $zoo = new ZookeeperDemo('192.168.1.45:2181');
  17. $zoo->get('/zgetw', [$zoo, 'watcher']);
  18. while (true) {
  19. echo '.';
  20. sleep(1);
  21. }

客户端操作


  1. set /ztest 2
  2. set /ztest 3
  3. set /ztest 5

获取节点信息(Zookeeper::get) 结果


  1. php get.php
  2. #output
  3. ......int(3)
  4. int(3)
  5. string(6) "/ztest"
  6. string(1) "2"
  7. ..int(3)
  8. int(3)
  9. string(6) "/ztest"
  10. string(1) "3"
  11. ..int(3)
  12. int(3)
  13. string(6) "/ztest"
  14. string(1) "4"
  15. .int(3)
  16. int(3)
  17. string(6) "/ztest"
  18. string(1) "5"

创建子节点


  1. create /ztest/child1 c1
  2. # output: Created /ztest/child1
  3. create /ztest/child2 c2
  4. # output: Created /ztest/child2
  5. ls /ztest
  6. # output: [child2, child1]

php下获取子节点


  1. # getChild.php
  2. $zookeeper = new Zookeeper('192.168.1.45:2181');
  3. $path = '/ztest';
  4. $r = $zookeeper->getchildren($path);
  5. if (!empty($r)) {
  6. foreach ($r as $c)
  7. {
  8. var_dump($c);
  9. }
  10. }
  11. # php getChild.php
  12. string(6) "child2"
  13. string(6) "child1"

创建顺序节点


  1. [zk: localhost:2181(CONNECTED) 22] create /stest 1
  2. Created /stest
  3. [zk: localhost:2181(CONNECTED) 23] create -s /stest/seq 1
  4. Created /stest/seq0000000000
  5. [zk: localhost:2181(CONNECTED) 24] create -s /stest/seq 1
  6. Created /stest/seq0000000001
  7. [zk: localhost:2181(CONNECTED) 25] create -s /stest/seq 1
  8. Created /stest/seq0000000002
  9. [zk: localhost:2181(CONNECTED) 26] create -s /stest/seq 1
  10. Created /stest/seq0000000003
  11. [zk: localhost:2181(CONNECTED) 27] create -s /stest/seq 1
  12. Created /stest/seq0000000004
  13. [zk: localhost:2181(CONNECTED) 28] create -s /stest/seq 1
  14. Created /stest/seq0000000005
  15. [zk: localhost:2181(CONNECTED) 29] create -s /stest/seq 1
  16. Created /stest/seq0000000006
  17. [zk: localhost:2181(CONNECTED) 30] create -s /stest/seq 1
  18. Created /stest/seq0000000007
  19. [zk: localhost:2181(CONNECTED) 31] create -s /stest/seq 2
  20. Created /stest/seq0000000008
  21. [zk: localhost:2181(CONNECTED) 32] create -s /stest/seq 2
  22. Created /stest/seq0000000009
  23. [zk: localhost:2181(CONNECTED) 33] create -s /stest/seq 2
  24. Created /stest/seq0000000010
  25. [zk: localhost:2181(CONNECTED) 34] create -s /stest/seq 2
  26. Created /stest/seq0000000011
  27. [zk: localhost:2181(CONNECTED) 35] create -s /stest/seq 2
  28. Created /stest/seq0000000012
  29. [zk: localhost:2181(CONNECTED) 36] create -s /stest/seq 2
  30. Created /stest/seq0000000013
  31. [zk: localhost:2181(CONNECTED) 37] create -s /stest/seq 2
  32. Created /stest/seq0000000014

代码


  1. $zookeeper = new Zookeeper('192.168.1.45:2181');
  2. $aclArray = array(
  3. array(
  4. 'perms' => Zookeeper::PERM_ALL,
  5. 'scheme' => 'world',
  6. 'id' => 'anyone',
  7. )
  8. );
  9. $path = '/t3';
  10. //ZOO_EPHEMERAL = 1
  11. //ZOO_SEQUENCE = 2
  12. //这里这里的flag=NULL,flag=0 表示创建永久节点,=1创建临时节点,=2创建seq 顺序节点
  13. $realPath = $zookeeper->create($path, null, $aclArray, 1);
  14. var_dump($realPath);

worker

一个利用顺序临时节点的leader迁移实现


  1. # worker.php
  2. <?php
  3. /**
  4. * Created by PhpStorm.
  5. * User: qkl
  6. * Date: 2018/8/27
  7. * Time: 14:25
  8. */
  9. class Worker
  10. {
  11. const CONTAINER = '/worker_test';
  12. protected $acl = [
  13. [
  14. 'perms' => Zookeeper::PERM_ALL,
  15. 'scheme' => 'world',
  16. 'id' => 'anyone'
  17. ]
  18. ];
  19. private $isLeader = false;
  20. private $znode = '';
  21. private $prevNode = '';
  22. public function __construct($host = '', $watcher_cb = null, $recv_timeout = 10000)
  23. {
  24. $this->zk = new Zookeeper($host, $watcher_cb, $recv_timeout);
  25. }
  26. public function register()
  27. {
  28. if (!$this->zk->exists(self::CONTAINER)) {
  29. $this->zk->create(self::CONTAINER, null, $this->acl);
  30. }
  31. # 创建一个临时的顺序节点
  32. $this->znode = $this->zk->create(self::CONTAINER . '/w-',
  33. null,
  34. $this->acl,
  35. Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE);
  36. //获取顺序节点名,去除父路径
  37. $this->znode = str_replace(self::CONTAINER . '/', '', $this->znode);
  38. printf("我创建了节点: %s\n", self::CONTAINER . '/' . $this->znode);
  39. $this->prevNode = $this->getPrev();
  40. if (is_null($this->prevNode)) {
  41. $this->setLeader(true);
  42. } else {
  43. $this->zk->get(self::CONTAINER . "/" . $this->prevNode, [$this, 'watcher']);
  44. }
  45. }
  46. public function getPrev()
  47. {
  48. $workers = $this->zk->getChildren(self::CONTAINER);
  49. sort($workers);
  50. $size = count($workers);
  51. for ($i = 0; $i < $size; $i++) {
  52. if ($this->znode == $workers[$i] && $i > 0) {
  53. return $workers[$i - 1];
  54. }
  55. }
  56. return null;
  57. }
  58. public function watcher($type, $state, $key)
  59. {
  60. $prevNode = $this->prevNode;
  61. printf("watchNode-getPrevious:%s\n", self::CONTAINER . "/" . $prevNode);
  62. if (!is_null($prevNode)) {
  63. if ($type == 2) {
  64. printf($prevNode . " had deleted\n");
  65. }
  66. if ($type == 3) {
  67. printf("我重新监控节点:%s\n", self::CONTAINER . "/" . $prevNode);
  68. $this->zk->get(self::CONTAINER . "/" . $prevNode, [$this, 'watcher']);
  69. }
  70. }
  71. }
  72. public function isLeader()
  73. {
  74. return $this->isLeader;
  75. }
  76. public function setLeader($flag)
  77. {
  78. $this->isLeader = $flag;
  79. }
  80. public function run()
  81. {
  82. $this->register();
  83. while (true) {
  84. if ($this->isLeader()) {
  85. $this->leaderJob();
  86. } else {
  87. $this->watcherJob();
  88. }
  89. sleep(2);
  90. }
  91. }
  92. public function leaderJob()
  93. {
  94. echo "现在我是Leader\n";
  95. }
  96. public function watcherJob()
  97. {
  98. echo "我在监控:".(self::CONTAINER . "/" . $this->prevNode)."\n";
  99. }
  100. }
  101. $worker = new Worker('192.168.1.45:2181');
  102. $worker->run();

尝试


  1. # 终端1
  2. php worker.php
  3. # 终端2
  4. php worker.php
  5. # 终端3
  6. php worker.php
  7. # 此处运行不会被节点变化不会被监控到

再次尝试


  1. # zkCli
  2. create /worker_test/w-
  3. /worker_test/0000000020
  4. php worker.php
  5. # output
  6. 我创建了节点: /worker_test/w-0000000022
  7. 我在监控:/worker_test/w-0000000020
  8. 我在监控:/worker_test/w-0000000020
  9. watchNode-getPrevious:/worker_test/w-0000000020
  10. 我重新监控节点:/worker_test/w-0000000020
  11. 我在监控:/worker_test/w-0000000020
  12. 我在监控:/worker_test/w-0000000020
  13. 我在监控:/worker_test/w-0000000020
  14. 我在监控:/worker_test/w-0000000020
  15. 我在监控:/worker_test/w-0000000020
  16. watchNode-getPrevious:/worker_test/w-0000000020
  17. 我重新监控节点:/worker_test/w-0000000020
  18. 2018-08-28 02:11:46,684:2486(0x7f28ed0a1700):ZOO_WARN@zookeeper_interest@1570: Exceeded deadline by 15ms
  19. 我在监控:/worker_test/w-0000000020
  20. 我在监控:/worker_test/w-0000000020
  21. watchNode-getPrevious:/worker_test/w-0000000020
  22. w-0000000020 had deleted
  23. 我在监控:/worker_test/w-0000000020

这边发现一个类似bug问题


  1. 如果我们直接运行worker.php
  2. worker.php运行创建的临时顺序节点是不会被watcher到的
  3. 我们必须先首先创建好相关的节点再启动监控,不知道这里是不是php版本的zookeeperbug
  4. 有了解的小伙伴可以告之下

Watcher通知状态与事件类型一览

ZOO_CREATED_EVENT(value=1):节点创建事件,需要watch一个不存在的节点,当节点被创建时触发,此watch通过zoo_exists()设置
ZOO_DELETED_EVENT(value=2):节点删除事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHANGED_EVENT(value=3):节点数据改变事件,此watch通过zoo_exists()或zoo_get()设置
ZOO_CHILD_EVENT(value=4):子节点列表改变事件,此watch通过zoo_get_children()或zoo_get_children2()设置
ZOO_SESSION_EVENT(value=-1):会话事件,客户端与服务端断开或重连时触发
ZOO_NOTWATCHING_EVENT(value=-2):watch移除事件,服务端出于某些原因不再为客户端watch节点时触发

原文地址:https://segmentfault.com/a/1190000016173878

PHP和zookeeper结合实践的更多相关文章

  1. ZooKeeper场景实践:(6)集群监控和Master选举

    1. 集群机器监控 这通经常使用于那种对集群中机器状态,机器在线率有较高要求的场景,可以高速对集群中机器变化作出响应.这种场景中,往往有一个监控系统,实时检測集群机器是否存活. 利用ZooKeeper ...

  2. ZooKeeper场景实践:(2)集中式配置管理

    1. 基本介绍 在分布式的环境中,可能会有多个对等的程序读取相同的配置文件,程序能够部署在多台机器上,假设配置採用文件的话,则须要为部署该程序的机器也部署一个配置文件,一旦要改动配置的时候就会很麻烦, ...

  3. 13. ZooKeeper最佳实践

    以下列举了运行和管理ZooKeeper ensemble的一些最佳实践: ZooKeeper数据目录包含快照和事务日志文件.如果autopurge选项未启用,定期清理目录是一个好习惯.另外,管理员可能 ...

  4. zookeeper(3) zookeeper的实践及原理

    一.基于java API初探zookeeper的使用 (1)建立连接 public static void main(String[] args) { //NOT_CONNECTED-->CON ...

  5. zookeeper学习实践1-实现分布式锁

    引言 ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件.它是一个为分布式应用提供一致性服务的软件,提 ...

  6. Docker部署Zookeeper部署实践(1)

    Zookeeper可提供的服务主要有:配置服务.名字服务.分布式同步.组服务等 1. 抓取Zookeeper镜像 命令:docker pull zookeeper 2. 将Zookeeper镜像保存为 ...

  7. 《从Paxos到Zookeeper:分布式一致性原理与实践》【PDF】下载

    内容简介 Paxos到Zookeeper分布式一致性原理与实践从分布式一致性的理论出发,向读者简要介绍几种典型的分布式一致性协议,以及解决分布式一致性问题的思路,其中重点讲解了Paxos和ZAB协议. ...

  8. Zookeeper 运维实践手册

    Zookeeper是一个高可用的分布式数据管理与协调框架,该框架能很好地保证分布式环境中数据一致性.一般用来实现服务发现(类似DNS),配置管理,分布式锁,leader选举等. 一.生产环境中Zook ...

  9. 从Paxos到Zookeeper 分布式一致性原理与实践读书心得

    一 本书作者介绍 此书名为从Paxos到ZooKeeper分布式一致性原理与实践,作者倪超,阿里巴巴集团高级研发工程师,国家认证系统分析师,毕业于杭州电子科技大学计算机系.2010年加入阿里巴巴中间件 ...

随机推荐

  1. [NetworkFlow]网络流建模相关

    流 网络流问题本质上是线性规划问题的应用之中的一个,线性规划问题的标准形式是给出一组等式约束和不等式约束.要求最优化一个线性函数. 在流问题中,变量以流量的形式出如今问题中,我们给出一个流网络(以有向 ...

  2. [Java]LeetCode57 Insert Interval

    Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessa ...

  3. Java之POI读取Excel的Package should contain a content type part [M1.13]] with root cause异常问题解决

    Java之POI读取Excel的Package should contain a content type part [M1.13]] with root cause异常问题解决 引言: 在Java中 ...

  4. splunk的bucket组织目录——时间序列,按照时间来组织目录

    splunk的bucket组织目录:db_1481515116_1480695302_0db_1481537316_1481532688_1db_1481547598_1481539988_2db_1 ...

  5. 洛谷 P3515 [ POI 2011 ] Lightning Conductor —— 决策单调性DP

    题目:https://www.luogu.org/problemnew/show/P3515 决策单调性... 参考TJ:https://www.cnblogs.com/CQzhangyu/p/725 ...

  6. 线性预测与Levinson-Durbin算法实现

    在学习信号处理的时候,线性预测是一个比较难理解的知识点,为了加快很多朋友的理解,这里给出Levinson-Durbin算法的线性预测实现和一个测试Demo,Demo中很明确的把输入信号.预测信号.预测 ...

  7. JavaScript(基于react+dva)

    变量声明 const 和 let:分别表示常量和变量 模板字符串 const user = 'world'; console.log(`hello ${user}`); // hello world ...

  8. Java数据类型转换1

    1 如何将字串 String 转换成整数 int? A. 有两个方法: 1). int i = Integer.parseInt([String]); 或 i = Integer.parseInt([ ...

  9. 编码的来历和使用 utf-8 和GB2312比较

    经常我们打开外国网站的时候出现乱码,又或者打开很多非英语的外国网站的时候,显示的都是口口口口口的字符, wordpress程序是用的UTF-8,很多cms用的是GB2312. ● 为什么有这么多编码? ...

  10. js 字符串 处理方法

    charAt() 返回指定索引位置的字符 charCodeAt() 返回指定索引位置字符的 Unicode 值 concat() 连接两个或多个字符串,返回连接后的字符串 fromCharCode() ...