邢台网站建设公司排名,企业解决方案榜单,长春建网站一般多少钱,网站做seo需要哪些准备介绍
一、zookeeper和redis实现分布式锁的对比 1、redis 分布式场景应用比较广泛#xff0c;redis分布式锁#xff0c;其实需要自己不断去尝试获取锁#xff0c;比较消耗性能#xff1b;zk分布式锁#xff0c;获取不到锁#xff0c;注册个监听器即可#xff0c;不需要不…介绍
一、zookeeper和redis实现分布式锁的对比 1、redis 分布式场景应用比较广泛redis分布式锁其实需要自己不断去尝试获取锁比较消耗性能zk分布式锁获取不到锁注册个监听器即可不需要不断主动尝试获取锁性能开销较小
2、如果是redis获取锁的那个客户端bug了或者挂了那么只能等待超时时间之后才能释放锁而zk的话因为创建的是临时znode只要客户端挂了znode就没了此时就自动释放锁。
二、zookeeper分布式锁原理 这个主要得益于ZooKeeper为我们保证了数据的强一致性。锁服务可以分为两类一个是保持独占另一个是控制时序。
1、保持独占就是所有试图来获取这个锁的客户端最终只有一个可以成功获得这把锁。通常的做法是把zk上的一个znode看作是一把锁通过create znode的方式来实现。所有客户端都去创建 /mylock节点最终成功创建的那个客户端也即拥有了这把锁。
2、控制时序就是所有试图来获取这个锁的客户端最终都会被安排执行只是有个全局时序。做法和上面基本类似只是这里 /mylock已经预先存在客户端在它下面创建临时顺序节点。Zk的父节点/mylock维持一份sequence,保证子节点创建的时序性从而也形成了每个客户端的全局时序。
三、zookeeper实现分布式锁的方式 1方式一创建一个临时节点 在需要获取排他锁时所有的客户端都会试图通过调用 create -e 接口在/mylock节点下创建临时子节点/mylock/lock。 ZooKeeper会保证在所有的客户端中最络只有一个客户端能够创建成功那么就可以认为该客户端获取了锁。 同时所有没有获取到锁的客户端就需要对 /mylock/lock 节点上注册一个Watcher监听以便实时监听到lock节点的变更情况。如果节点被使用完删除了zookeeper要向所有监听者发送通知这会阻塞其他操作并且会导致所有客户端来争抢锁这种情况称为“羊群效应”试想一下如果监听者众多的话会拖累性能。
2方式二创建临时顺序节点
create -s -e /mylock/lock-data 1、每个试图加锁的客户端都会创建一个临时顺序节点 /mylock/lock-xxxxx并且zk可以保证序号连续且唯一
2、然后获取 /mylock/ 下的所有子节点并按从小到大排序list
3、判断最小节点是不是自己如果是证明你就获取锁了可以去处理业务逻辑了
4、如果不是获取到list中你的上一个节点名称(不一定是 -1 的那一个因为此时它对应的客户端有可能主动放弃了)对其实施监听操作 get /mylock/lock-xxxxx watch 如果get监听失败了说明节点已经别清除了重复 2,3 直到监听成功或者获取锁如果监听成功就在这里阻塞等待通知
5、如果通知过来了重复 2,3,4 的步骤直到获取锁因为上一个节点被释放的原因并不一定是它得到锁-使用完-释放有可能是客户端断开连接了
6、锁用完后记得主动清除不然要等到心跳检测的时候才会清除。
优点具备高可用、可重入、阻塞锁特性可解决失效死锁问题。
缺点因为需要频繁的创建和删除节点性能上不如Redis方式。
四、安装PHP的zookeeper扩展 虽然ZooKeeper是一个Java应用程序但C也可以使用。所以安装PHP的扩展则首先安装zookeeper的C扩展支持
1、安装Zookeeper C扩展支持 示例中使用的zookeeper3.4.12版本
cd /usr/local/zk3.4/src/c #编译C扩展由于zookeeper解压即可用这里下载源码主要是了编译C扩展为后面安装PHP的扩展用 ./configure --prefix/usr/local/zk3.4/ make make install 2、安装php的zookeeper扩展 zookeeper的PHP扩展可以在pecl上下载也可以在github上下载但有人说pecl上有bug。
git clone https://github.com/php-zookeeper/php-zookeeper.git cd php-zookeeper /usr/local/php7.4/bin/phpize ./configure --with-libzookeeper-dir/usr/local/zk3.4/ --with-php-config/usr/local/php7.4/bin/php-config make make install vim php.ini extensionzookeeper /etc/php-fpm restart 五、PHPzookeeper实现分布式锁示例 ?php /* * zookeeper 类属性常量参考 * https://www.php.net/manual/zh/class.zookeeper.php#zookeeper.class.constants.perms */ class zkCli { protected static $zk; protected static $myNode; protected static $isNotifyed; protected static $root; public static function getZkInstance($conf, $root){ try{ if(isset(self::$zk)){ return self::$zk; } $zk new \Zookeeper($conf[host] . : . $conf[port]); if(!$zk){ throw new \Exception(connect zookeeper error); } self::$zk $zk; self::$root $root; return $zk; } catch (\ZookeeperException $e){ die($e-getMessage()); } catch (\Exception $e){ die($e-getMessage()); } } // 获取锁 public static function tryGetDistributedLock($lockKey, $value){ try{ // 创建根节点 self::createRootPath($value); // 创建临时顺序节点 self::createSubPath(self::$root . $lockKey, $value); // 获取锁 return self::getLock(); } catch (\ZookeeperException $e){ return false; } catch (\Exception $e){ return false; } } // 释放锁 public static function releaseDistributedLock(){ if(self::$zk-delete(self::$myNode)){ return true; }else{ return false; } } public static function createRootPath($value){ $aclArray [ [ perms Zookeeper::PERM_ALL, scheme world, id anyone, ] ]; // 判断根节点是否存在 if(false self::$zk-exists(self::$root)){ // 创建根节点 $result self::$zk-create(self::$root, $value, $aclArray); if(false $result){ throw new \Exception(create .self::$root. fail); } } return true; } public static function createSubPath($path, $value){ // 全部权限 $aclArray [ [ perms Zookeeper::PERM_ALL, scheme world, id anyone, ] ]; /** * flags : * 0 和 null 永久节点 * Zookeeper::EPHEMERAL临时 * Zookeeper::SEQUENCE顺序 * Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE 临时顺序 */ self::$myNode self::$zk-create($path, $value, $aclArray, Zookeeper::EPHEMERAL | Zookeeper::SEQUENCE); if(false self::$myNode){ throw new \Exception(create -s -e .$path. fail); } echo my node is . self::$myNode.-----------.PHP_EOL; return true; } public function getLock(){ // 获取子节点列表从小到大显然不可能为空至少有一个节点 $res self::checkMyNodeOrBefore(); if($res true){ return true; }else{ self::$isNotifyed false;// 初始化状态值 // 考虑监听失败的情况当我正要监听before之前它被清除了监听失败返回 false $result self::$zk-get($res, [zkCli::class, watcher]); while(!$result){ $res1 self::checkMyNodeOrBefore(); if($res1 true){ return true; }else{ $result self::$zk-get($res1, [zkCli::class, watcher]); } } // 阻塞等待watcher被执行watcher执行完回到这里 while(!self::$isNotifyed){ echo .; usleep(500000); // 500ms } return true; } } /** * 通知回调处理 * param $type 变化类型 Zookeeper::CREATED_EVENT, Zookeeper::DELETED_EVENT, Zookeeper::CHANGED_EVENT * param $state * param $key 监听的path */ public static function watcher($type, $state, $key){ echo PHP_EOL.$key. notifyed .....PHP_EOL; self::$isNotifyed true; self::getLock(); } public static function checkMyNodeOrBefore(){ $list self::$zk-getChildren(self::$root); sort($list); $root self::$root; array_walk($list, function($val) use ($root){ $val $root . / . $val; }); if($list[0] self::$myNode){ echo get locak node .self::$myNode......PHP_EOL; return true; }else{ // 找到上一个节点 $index array_search(self::$myNode, $list); $before $list[$index - 1]; echo before node .$before...........PHP_EOL; return $before; } } } function zkLock($resourceId){ $conf [host127.0.0.1, port2181]; $root /lockKey_ . $resourceId; $lockKey /lock_; $value a; $client zkCli::getZkInstance($conf, $root); $re zkCli::tryGetDistributedLock($lockKey, $value); if($re){ echo get lock success.PHP_EOL; }else{ echo get lock fail.PHP_EOL; return ; } try { doSomething(); } catch(\Exception $e) { echo $e-getMessage() . PHP_EOL; } finally { $re zkCli::releaseDistributedLock(); if($re){ echo release lock success.PHP_EOL; }else{ echo release lock fail.PHP_EOL; } return ; } } function doSomething(){ $n rand(1, 20); switch($n){ case 1: sleep(15);// 模拟超时 break; case 2: throw new \Exception(system throw message...);// 模拟程序中止 break; case 3: die(system crashed...);// 模拟程序崩溃 break; default: sleep(13);// 正常处理过程 } } // 执行 zkLock(0);