dubbo-php-framework的服务注册zookeeper过程解析(三)

版权声明:转载请注明来源 https://blog.csdn.net/u013702678/article/details/82765337

我们从前面两篇服务注册zookeeper的过程可以看出,实际注册流程发生在zkService中,而zkService是通过RegistryFactory的getRegistry获取的,这篇文章我们分析这个getRegistry的过程和一系列和zk注册相关的流程,这里注册时封装层数很深,没理解为什么要这么封装,我们就按代码解析。

class RegistryServiceFactory
{
     //获取zk服务,其中registryUrl是zk对应的地址信息,这个也是在配置文件fsof.ini中配置的。
     public static function getRegistry($registryUrl)
     {
         if(empty($registryUrl)) 
         {
             return null;
         }
         else
         {   
             //获取zk服务信息
             return new RegistryService($registryUrl);
         }
     }
}
class RegistryService
{
    private $zookeeperClient = null;//zk客户端抽象类
	private $zookeeperAddr = null;//zk地址信息
    private $logger;

    public function __construct($registryUrl)
    {
        $this->logger = \Logger::getLogger(__CLASS__);
        $zkHostStr = '';
        foreach($registryUrl as $fsofUrl) 
        {
            $zkHostStr .= $fsofUrl->getHost().':'.$fsofUrl->getPort().',';//按IP:PORT,IP1:PORT1这种格式拼接地址信息
        }
        $this->zookeeperAddr = rtrim($zkHostStr,',');//去掉最后的,
        
        try
        {
			$this->zookeeperClient = new ZookeeperClient();//声明ZookeeperClient对象,这里不产生实际的网络连接
        }
        catch (\Exception $e) 
        {
            throw new \Exception("连接zookeeper失败".$e->getMessage());
        }
    }

	public function __destruct()
	{
		unset($this->zookeeperClient);
	}

    //连接到zk
	public function connectZk($ephemeral)
	{
		return $this->zookeeperClient->connectZk($this->zookeeperAddr, $ephemeral);
	}

    //在zk中注册服务地址信息,其中url为FSOFUrl对象
    public function register($url)
    {
        $ret = false;

        $this->logger->info('registryService::register|url:'.$url->getOriginUrl().'|path:'.$url->getZookeeperPath());
        try
        {
            //所谓在zk的注册,实际是在zk中创建相应路径的节点,其中路径信息从FsofUrl的对象url中获取。
            $ret = $this->zookeeperClient->create($url->getZookeeperPath());
        }
        catch (\Exception $e) 
        {
            $ret = false;
            throw new \Exception("注册service到zookeeper失败".$e->getMessage());
        }

        return $ret;
    }
    
    //取消注册
    public function unregister($url)
    {
        $path = $url->getZookeeperPath();//获取FsofUrl对象url的路径信息
        return  $this->zookeeperClient->delete($path);//从zk中删除相应的路径信息
    }

    public function subscribe($url, $listener)
    {
    }


    public function unsubscribe($url, $listener)
    {
    }


    public function lookup($url)
    {
    }
   
    
	public function registerCallFunc($func)
	{
		$this->zookeeperClient->registerCallFunc($func);
	}

    //设置zk的日志文件路径信息和日志级别信息
	public function setLogFile($file, $level = 2)
	{
		$this->zookeeperClient->setLogFile($file, $level);
	}
}
class ZookeeperClient
{
	/**
	 * @var Zookeeper
	 */
	private $zookeeper = null;
	private $address;
	private $func = null;
	private $ephemeral = false;
	private $zkFile = null;
    private $waiteForConnectStateTimes = 20;
    private $logger;

    public function __construct()
    {
        $this->logger = \Logger::getLogger(__CLASS__);
    }

	public function __destruct()
	{
		$this->closeLog();
		unset($this->zookeeper);
        $this->logger->info('zookeeperClient destruct');
	}

	public function connect_cb($type, $event, $string)
	{
		// Watcher gets consumed so we need to set a new one
        $this->logger->debug("connect state:{$event}");
		$params = array($type, $event, $string);
		if(isset($this->func))
		{
            $this->logger->warn("call connect state");
			call_user_func_array($this->func, $params);
		}
        $this->logger->debug("connect_cb end");
	}

    //连接zk
	public function connectZk($address, $ephemeral = false)
	{
		$ret = true;
		$this->address = $address;
		$this->ephemeral = $ephemeral;
		try
		{
			if ($ephemeral)
			{
                //创建zk,按zk的API文档介绍,在new的过程中,连接是异步的,真实连接成功时会回调用户定义的函数,在这里就是connect_cb函数,位于本类中。
				$this->zookeeper = new \Zookeeper($this->address, array($this,'connect_cb'));
			}
			else
			{ 
                //通过没有回调函数的构造函数创建Zookeeper时,连接不是马上就建立的,这里通过循环判断连接建立情况
				$this->zookeeper = new \Zookeeper($this->address);
				if($this->zookeeper)
				{
                    //在zk状态不是CONNECTED_STATE和重试次数没到限制时,多次尝试判断
					while(\Zookeeper::CONNECTED_STATE != $this->zookeeper->getState()
							&&($this->waiteForConnectStateTimes > 0)) 
					{
						//等待连接状态
						$this->waiteForConnectStateTimes--;
                        $this->logger->debug("wait for connect state");
						usleep(50000);
					}
				}
			}

			if(empty($this->zookeeper))
			{
				$ret = false;
			}
		}
		catch (\Exception $e)
		{
			$ret = false;
            $this->logger->error($e->getMessage().'|address:'.$this->address);
		}
		return $ret;
	}
    
    //注册连接成功时的回调函数,这个在上述构造函数中使用。
	public function registerCallFunc($func)
	{
		$this->func = $func;
	}

	/**
	 * 创建节点。
	 *
	 * @param path 节点的绝对路径,如/fsof/URL.Encode("com.fenqile.example.calculate.AddService")/providers/URL.Encoder(provider url)。
	 * @param ephemeral,是否是临时节点,所有树干节点都为固定节点,只有叶子节点可以设为临时节点,没有设置,默认为固定节点
	 */
	public function create($path)
	{
		$ret = $this->set($path);
        $this->logger->info('zookeeperClient create|path:'.$path.'|ret:'.$ret);
		return $ret;
	}

	/**
	 * 删除节点,临时节点不需要删除,zookeeper在与对应的 client的连接断开后自动删除
	 * @param path 节点的绝对路径,如/fsof/URL.Encode("com.fenqile.example.calculate.AddService")/providers/URL.Encoder(provider url)。
	 */
	public function delete($path, $version=-1)
	{
		if(isset($this->zookeeper))
		{
			if($this->zookeeper->exists($path))
			{
				$this->zookeeper->delete($path, $version);
			}
		}
		return true;
	}
	
	private function set($path, $value=null) 
	{
		if(isset($this->zookeeper))
		{
			if($this->zookeeper->exists($path))
			{
				$this->zookeeper->set($path, $value);
			}
			else
			{
				$this->makePath($path);
				$this->makeNode($path, $value, $this->ephemeral);
			}
		}
		return true;
	}

	/**
	 * 获取指定节点的所有childe节点
	 *
	 * @param path 节点的绝对路径,如/fsof/URL.Encode("com.fenqile.example.calculate.AddService")/providers。
	 */
	public function getChildren($path)
	{
		if((strlen($path) > 1) && preg_match('@/$@', $path))
		{
			// remove trailing /
			$path = substr($path, 0, -1);
		}
		return $this->zookeeper->getChildren($path);
	}

	/**
	 * 为指定节点设置一个 childListener,用于监听其child变动情况
	 *
	 * @param path 节点的绝对路径,如/fsof/URL.Encode("com.fenqile.example.calculate.AddService")/providers。
	 * @param ChildListener
	 */
	public function addChildListener($path, $childListener)
	{
	}

	/**
	 * 删除指定节点上的 childListener
	 *
	 * @param path 节点的绝对路径,如/fsof/URL.Encode("com.fenqile.example.calculate.AddService")/providers。
	 * @param ChildListener
	 */
	public function  removeChildListener($path, $childeListener)
	{
	}

	/**
	 * 设置一个client的state状态监听器,如在连接建立或重建时,主动向zookeeper server拉一次数据
	 *
	 * @param StateListener
	 */
	public function addStateListener($stateListener)
	{
	}

	/**
	 * 删除一个client的state状态监听器
	 *
	 * @param StateListener
	 */
	public function removeStateListener($stateListener)
	{
	}

	public function isConnected()
	{
		$ret = $this->zookeeper->getState();
		if(\Zookeeper::CONNECTED_STATE == $ret)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	public function close()
	{
	}

	public function getUrl()
	{
	}

	/**
	 * Equivalent of "mkdir -p" on ZooKeeper
	 *
	 * @param string $path The path to the node
	 * @param string $value The value to assign to each new node along the path
	 *
	 * @return bool
	 */
	private function makePath($path, $value = '') 
	{
		$parts = explode('/', $path);
		$parts = array_filter($parts);
		$subpath = '';
		while (count($parts) > 1) 
		{
			$subpath .= '/' . array_shift($parts);
			if (!$this->zookeeper->exists($subpath)) 
			{
				$this->makeNode($subpath, $value);
			}
		}
	}

	/**
	 * Create a node on ZooKeeper at the given path
	 *
	 * @param string $path   The path to the node
	 * @param string $value  The value to assign to the new node
	 * @param bool $endNode  The value to assign to the end node
	 * @param array  $params Optional parameters for the Zookeeper node.
	 *                       By default, a public node is created
	 *
	 * @return string the path to the newly created node or null on failure
	 */
	private function makeNode($path, $value, $ephemeral = false, array $params = array()) 
	{
        //$this->logger->debug("makeNode(".$path.",".$value.",".($ephemeral?1:0).",".json_encode($params).")");
		if(empty($params))
		{
			$params = array(
				array(
					'perms'  => \Zookeeper::PERM_ALL,
					'scheme' => 'world',
					'id'     => 'anyone',
				)
			);
		}
		
		if ($ephemeral)
		{
			return $this->zookeeper->create($path, $value, $params , \Zookeeper::EPHEMERAL);
		}
		else 
		{
			return $this->zookeeper->create($path, $value, $params);
		}
	}

	public function setLogFile($file, $logLevel = 2)
	{
		$this->zkFile = fopen($file,"a+");
		if($this->zkFile && $this->zookeeper)
		{
			$this->zookeeper->setDebugLevel($logLevel);
			$this->zookeeper->setLogStream($this->zkFile);
		}
	}

	private function closeLog()
	{
		if(!empty($this->zkFile))
		{
			fclose($this->zkFile);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/u013702678/article/details/82765337