Zookper is a distributed, open source, collaborative service applied to distributed applications. It provides simple operations that allow distributed applications to implement services such as synchronization, configuration maintenance, and clustering or naming based on these interfaces. Zookper is easy to program and uses a data model with a similar structure to the file tree.
Although ZooKeeper is a Java application, C can also be used. Here is a PHP extension, you can download it from PECL, or directly get PHP-ZooKeeper from GitHub.
To use this extension you first need to install ZooKeeper. Can be downloaded from the official website.
$ tar zxfv zookeeper-3.4. $ cd zookeeper-3.4.5/src/c $ ./configure --prefix=/usr/ $ make $ sudo make install
This will install ZooKeeper's library and header files. Now ready to compile the PHP extension.
$ git clone /andreiz/ $ cd php-zookeeper $ phpize $ ./configure $ make $ sudo make install
Add "" to your PHP configuration.
$ vim /etc/php5/cli//
Because I don't need to run it in a web service environment, I only edited the CLI configuration here. Copy the following line into the ini file.
extension=
Use the following command to determine whether the extension is working.
$ php -m | grep zookeeper zookeeper
Now it's time to run ZooKeeper. The only thing that has not been done yet is configuration. Create a directory for storing all service data.
$ mkdir /home/you-account/zoo $ cd $ cd zookeeper-3.4.5/ $ cp conf/zoo_sample.cfg conf/ $ vim conf/
Find the property named "dataDir" and point it to the "/home/you-account/zoo" directory.
$ bin/ start $ bin/ -server 127.0.0.1:2181 [zk: 127.0.0.1:2181(CONNECTED) 14] create /test 1 Created /test [zk: 127.0.0.1:2181(CONNECTED) 19] ls / [test, zookeeper]
At this point, you have successfully connected to ZooKeeper and created a znode called "/test" (we'll use it later). ZooKeeper saves data in a tree structure. This is very similar to a file system, but "folder" (translator's note: here refers to a node that is not the lowest level) is very similar to a file. znode is an entity saved by ZooKeeper. The statement of Node is easy to be confused, so to avoid confusion znode is used here.
Since we will use it later, here we keep the client connected. Open a new window and create a file.
<?php class ZookeeperDemo extends Zookeeper { public function watcher( $i, $type, $key ) { echo "Insider Watcher\n"; // Watcher gets consumed so we need to set a new one $this->get( '/test', array($this, 'watcher' ) ); } } $zoo = new ZookeeperDemo('127.0.0.1:2181'); $zoo->get( '/test', array($zoo, 'watcher' ) ); while( true ) { echo '.'; sleep(2); }
Now run the script.
$ php
Here, a point should be generated every 2 seconds. Now switch to the ZooKeeper client and update the "/test" value.
[zk: 127.0.0.1:2181(CONNECTED) 20] set /test foo
This will silently trigger the "Insider Watcher" message in the PHP script. How could this happen?
ZooKeeper provides monitors that can be bound to znode. If the monitor finds that the znode has changed, the service will immediately notify all relevant clients. This is how PHP scripts know changes. The second parameter of the Zookeeper::get method is the callback function. When an event is triggered, the monitor will be consumed, so we need to set the monitor again in the callback function.
Now you are ready to create a distributed application. The challenge is to let these independent programs decide which (the leader) coordinates their work and which (the worker) needs to be executed. This processing process is called leader election, and you can see the relevant implementation methods in ZooKeeper Recipes and Solutions.
Simply put, each processor (or server) is staring at the adjacent processor (or server). If a monitored process (i.e., the Leader) exits or crashes, the monitoring program will look for its adjacent (the oldest) process as the Leader.
In real applications, the leader will assign tasks to the worker, monitor processes and save results. I skipped these parts here for simplicity.
Create a new PHP file named.
<?php class Worker extends Zookeeper { const CONTAINER = '/cluster'; protected $acl = array( array( 'perms' => Zookeeper::PERM_ALL, 'scheme' => 'world', 'id' => 'anyone' ) ); private $isLeader = false; private $znode; public function __construct( $host = '', $watcher_cb = null, $recv_timeout = 10000 ) { parent::__construct( $host, $watcher_cb, $recv_timeout ); } public function register() { if( ! $this->exists( self::CONTAINER ) ) { $this->create( self::CONTAINER, null, $this->acl ); } $this->znode = $this->create( self::CONTAINER . '/w-', null, $this->acl, Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE ); $this->znode = str_replace( self::CONTAINER .'/', '', $this->znode ); printf( "I'm registred as: %s\n", $this->znode ); $watching = $this->watchPrevious(); if( $watching == $this->znode ) { printf( "Nobody here, I'm the leader\n" ); $this->setLeader( true ); } else { printf( "I'm watching %s\n", $watching ); } } public function watchPrevious() { $workers = $this->getChildren( self::CONTAINER ); sort( $workers ); $size = sizeof( $workers ); for( $i = 0 ; $i < $size ; $i++ ) { if( $this->znode == $workers[ $i ] ) { if( $i > 0 ) { $this->get( self::CONTAINER . '/' . $workers[ $i - 1 ], array( $this, 'watchNode' ) ); return $workers[ $i - 1 ]; } return $workers[ $i ]; } } throw new Exception( sprintf( "Something went very wrong! I can't find myself: %s/%s", self::CONTAINER, $this->znode ) ); } public function watchNode( $i, $type, $name ) { $watching = $this->watchPrevious(); if( $watching == $this->znode ) { printf( "I'm the new leader!\n" ); $this->setLeader( true ); } else { printf( "Now I'm watching %s\n", $watching ); } } public function isLeader() { return $this->isLeader; } public function setLeader($flag) { $this->isLeader = $flag; } public function run() { $this->register(); while( true ) { if( $this->isLeader() ) { $this->doLeaderJob(); } else { $this->doWorkerJob(); } sleep( 2 ); } } public function doLeaderJob() { echo "Leading\n"; } public function doWorkerJob() { echo "Working\n"; } } $worker = new Worker( '127.0.0.1:2181' ); $worker->run();
Open at least 3 terminals and run the following script in each terminal:
# term1 $ php I'm registred as: w-0000000001 Nobody here, I'm the leader Leading # term2 $ php I'm registred as: w-0000000002 I'm watching w-0000000001 Working # term3 $ php I'm registred as: w-0000000003 I'm watching w-0000000002 Working
Now simulate the situation of the leader crash. Use Ctrl+c or other methods to exit the first script. There will be no changes at the beginning, and the worker can continue to work. Later, ZooKeeper will find the timeout and elect a new leader.
Although these scripts are easy to understand, it is still necessary to comment on the used Zookeeper flag.
$this->znode = $this->create( self::CONTAINER . '/w-', null, $this->acl, Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE );
Each znode is EPHEMERAL and SEQUENCE.
EPHEMRAL means to remove the znode when the client loses the connection. This is why PHP scripts know the timeout. SEQUENCE means adding sequential identifiers after each znode name. We tag workers with these unique identities.
There are still some issues to pay attention to in the PHP section. This extension is currently still beta version, and segmentation fault is likely to occur if used improperly. For example, ordinary functions cannot be passed as callback functions, and the passed in must be a method. I hope more colleagues in the PHP community can see the goodness of Apache ZooKeeper, and the extension will also receive more support.
ZooKeeper is a powerful software with a simple and simple API. Since the documentation and examples are done well, it is easy for anyone to write distributed software.
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for your study or work. Thank you for your support. If you want to know more about it, please see the relevant links below