模塊的設計
基本架構
配置管理模塊是很多分佈式系統的基礎,它的主要功能是將用戶更新的配置信息實時的同步到各個節點的服務上,以便它們近似實時的加載這些配置,典型的架構如下圖所示
工作流程
- 服務啓動後,ConfigFetcher模塊與ZooKeeper服務通訊,讀取znode節點/serviceA/conf中保存的配置數據,並向該znode節點註冊一個watcher以監聽節點數據的變更。
- 用戶通過ConfigUpdater動態的變更znode節點/serviceA/conf中的配置數據。
- 各個服務受到節點配置數據變動通知,讀取新的配置數據,並重新註冊watcher以監聽下一次變更。
核心代碼實現
代碼實現
- 配置服務Zookeeper客戶端核心代碼。該類封裝了與ZooKeeper服務端交互的基本函數。
<?php
/**
* ConfigClient.class.php
* 配置模塊客戶端類
*/
class ConfigClient
{
private $pZk = null;
private $strConfPath = '';
public function __construct($host)
{
//實例化ZooKeeper客戶端類
$this->pZk = new Zookeeper($host);
//設置ZooKeeper日誌級別
$this->pZk->setDebugLevel(Zookeeper::LOG_LEVEL_ERROR);
}
/**
* 設置節點路徑
* @param String $strConfPath 節點路徑
*/
public function setConfPath($strConfPath)
{
$this->strConfPath = $strConfPath;
}
/**
* 判斷節點是否存在
* @return [type] [description]
*/
public function checkExist()
{
return $this->pZk->exists($this->strConfPath);
}
/**
* 設置配置項
* @param array $arrConfig 配置數據
*/
public function setConf($arrConfig)
{
if (false === $this->checkExist()) {
$arrAcl = [
[
'perms' => Zookeeper::PERM_ALL,
'scheme' => 'world',
'id' => 'anyone'
]
];
//當節點不存在是新建節點
$result = $this->pZk->create($this->strConfPath, null, $arrAcl);
if ($result === false) {
throw new Exception("節點創建失敗\n");
}
}
$strConf = json_encode($arrConfig);
//設置配置數據
$result = $this->pZk->set($this->strConfPath, $strConf);
if ($result === false) {
throw new Exception("配置設置失敗\n");
}
return true;
}
/**
* 獲取配置項
* @return array 配置數據
*/
public function getConf()
{
if (false === $this->checkExist()) {
throw new Exception("配置信息不存在\n");
}
//獲取節點配置信息並設置watcher監聽節點變更
$result = $this->pZk->get($this->strConfPath, [$this, 'watcher']);
return empty($result) ? [] : json_decode($result, true);
}
/**
* 監聽配置變更回調函數
* @param [type] $i [description]
* @param [type] $type [description]
* @param String $key 節點路徑
* @return [type] [description]
*/
public function watcher($i, $type, $key)
{
//讀取最新配置信息並重新設置watcher監聽
$result = $this->pZk->get($key, [$this, 'watcher']);
//處理配置變更邏輯
var_dump($result);
}
}
- ConfigFetcher模塊
<?php
//ConfigFetcher.php
require_once 'ConfigClient.class.php';
$pConfClient = new ConfigClient('127.0.0.1:2181');
$strConfPath = '/serviceA/conf';
$pConfClient->setConfPath($strConfPath);
$result = $pConfClient->getConf();
var_dump(json_encode($result));
while (true) {
sleep(2);
}
- ConfigUpdater模塊
<?php
//ConfigUpdater.php
require_once 'ConfigClient.class.php';
$pConfClient = new ConfigClient('127.0.0.1:2181');
$strConfPath = '/serviceA/conf';
$pConfClient->setConfPath($strConfPath);
//配置數據
$arrConf = [
'date' => date('Y-m-d'),
'time' => time()
];
$result = $pConfClient->setConf($arrConf);
if ($result === false) {
exit("配置設置失敗\n");
}
var_dump(json_encode($arrConf));
exit("配置設置成功\n");
配置測試
- 到項目所在目錄;
- 啓動各個服務對應的ConfigFetcher服務,執行
php ConfigFetcher.php
; - 用戶更新配置,執行
php ConfigUpdater.php
; - 實際測試效果如下圖示
—————END—————