1. 程式人生 > >dubbo-php-framework的服務註冊zookeeper過程解析(一)

dubbo-php-framework的服務註冊zookeeper過程解析(一)

我們在分析BaseServer的onManagerStart回撥函式時,看到有呼叫Provider註冊到zookeeper的過程,這篇我們詳細解析下這個過程。

//app啟動後向zookeeper註冊服務資訊
FSOFRegistry::instance()->setParams($this->processName, $this->config, $this->port,
            $this->serverProviders, $this->start_without_registry);
FSOFRegistry::instance()->registerZk();
//註冊單列類
class FSOFRegistry 
{
	//設定zookeeper的日誌檔案及日誌級別(1.error; 2.warn; 3.info; 4.debug)
	const ZOOKEEPER_LOG_NO = 0;
	const ZOOKEEPER_LOG_ERROR = 1;
	const ZOOKEEPER_LOG_WARN = 2;
	const ZOOKEEPER_LOG_INFO = 3;
	const ZOOKEEPER_LOG_DEBUG = 4;

	protected $appName;//應用名稱
	protected $port;//應用監聽埠資訊
	protected $config;//配置資訊
	protected $serverProviders;//服務介面資訊
	protected $localIp = '127.0.0.1';
	protected $ephemeral = false;

	//zookeeper相關
	protected $zkService = null;//zk service
	protected $fsofUrlList = array();//要註冊到zk的資訊的列表
    
	protected $start_without_registry;//p2p模式

	private static $_instance;//本例項資訊,這裡使用了單列模式

        private $logger;//日誌元件

        //單列模式建立例項
	public static function instance()
	{
		if (empty(FSOFRegistry::$_instance))
		{
			FSOFRegistry::$_instance = new FSOFRegistry();
		}
		return FSOFRegistry::$_instance;
	}
	
	public function __construct()
	{
            $this->logger = \Logger::getLogger(__CLASS__);//初始化日誌元件
	}

    //BaseServer側呼叫這個函式設定相關屬性資訊,這裡屬性資料已經在類的初始化處解釋過,這裡不重複解釋。
	public function setParams($appName, $appConfig, $port, $serverProviders, $registry = true)
	{
            $this->logger->info("serverProviders:".json_encode($serverProviders));
		$this->appName = $appName;
		$this->port = $port;
		$this->config = $appConfig;
		$this->serverProviders = $serverProviders;
		$this->start_without_registry = $registry;

		try
		{   
                         //獲取Provider服務所在的機器
			$this->localIp = FSOFSystemUtil::getServiceIP();
		}
		catch (\Exception $e)
		{
            $this->logger->error('The server network configuration errors',$e);
			//當獲取IP失敗時,禁止往zk註冊
			$this->start_without_registry = true;
		}
	}
//註冊到zookeeper
public function registerZk()
	{
		if(!$this->start_without_registry)//非p2p模式,服務啟動時,需要註冊流程
		{
			try
			{
                $this->logger->info("init zk start...");
				
				$this->ServiceSerialize();//生成service urls
				$this->createZookeeperService();//建立zk service
				$this->setZkLog();//設定日誌元件資訊

				if (!$this->ephemeral)//這個引數按意思是標記是否是短暫註冊,但全篇都是false。
				{
					//靜態註冊模式
					$this->registerServiceToZk();//呼叫zk的介面,註冊到zk
					$this->inventZkService();//登出zk服務
				}

				//連線成功後,通過注入watcherCallFunc函式進行註冊
                $this->logger->info("init zk end...");
			}
			catch (\Exception $e)
			{
                $this->logger->error($e->getMessage(),$e);
			}
		}
	}
//生成要註冊到zk的服務資訊
protected function ServiceSerialize()
	{
		try 
		{
			unset($this->fsofUrlList);//清理資訊
			if (!empty($this->serverProviders))//服務資訊不為空
			{
				if ($this->ephemeral)//短暫的
				{
					//註冊時間
					//$this->config["service_properties"]["timestamp"] = (int)(microtime(true) * 1000);
					$this->config["service_properties"]["dynamic"] = "true";
				} 
				else//長久的,按邏輯,流程會走這裡。 
				{
					$this->config["service_properties"]["dynamic"] = "false";
				}

				$services = $this->serverProviders;
				foreach ($services as $interface => $serviceInfo)
				{
					//合併全域性配置
					if (isset($this->config["service_properties"]))
					{
						//介面配置優先順序高於全域性配置,所以$serviceInfo放後面
						$serviceInfo = array_merge($this->config["service_properties"], $serviceInfo);
					}

					//不用上報的資訊去掉
					unset($serviceInfo['service']);
					unset($serviceInfo['p2p_mode']);

					if (empty($serviceInfo["version"]))
					{
						$serviceInfo['version'] = FSOFConstants::FSOF_SERVICE_VERSION_DEFAULT;
					}
					
					//與dubbo相容處理
					$serviceInfo['interface'] = $interface;//dubbo_admin需要使用
                    //序列化方式
                    $serviceInfo['serialization']= "fastjson";

					ksort($serviceInfo);//引數排序,與dubbo相容
					
                    //要註冊到zk的url資訊組成部分
					$urlPara = array(
						'scheme' => 'dubbo',
						'host' => $this->localIp,
						'port' => $this->port,
						'path' => '/' . $interface,
						//http_build_query會進行urlencode導致query引數被多編碼一次,使用urldecode抵消
						'query' => urldecode(http_build_query($serviceInfo)),
					);
                    $this->logger->debug("serviceInfo:" . json_encode($serviceInfo) . "|urlPara:" . json_encode($urlPara));
					try
					{
						$fsofUrl = new FSOFUrl($urlPara);//按規則拼接dubbo的url協議
					}
					catch (\Exception $e)
					{
                        $this->logger->error('init url failed|app:' . $this->appName . '|urlPara:' . json_encode($urlPara));
					}
                     
					$this->fsofUrlList[] = $fsofUrl;
				}
			}
		}
		catch(\Exception $e)
		{
			$errMsg = $e->getMessage();
            $this->logger->error('ServiceSerialize:'.$errMsg, $e);
		}
	}