分佈式配置之qconf

    QConf 是一個分佈式配置管理工具。 用來替代傳統的配置文件,使得配置和業務代碼分離,同時配置可以實時同步到客戶端保證配置及時生效。php

使用場景

  • 單條數據量小html

  • 更新頻繁(較代碼而言)java

  • 配置總數可能巨大,但單臺機器關心配置數有限node

  • 讀多寫少python

特色

  • 一處修改,全部機器實時同步更新
  • 高效讀取配置
  • 安裝部署方便,使用簡單
  • 服務器宕機、網絡中斷、集羣遷移等異常狀況對用戶透明
  • 支持c/c++、shell、php、python、lua、java、go、node 等語言

編譯安裝

QConf採用CMake進行構建(CMake 版本 2.6及以上)c++

可使用如下命令完成QConf的編譯安裝:git

mkdir build && cd build
cmake ..
make
make install複製代碼

使用

  • 搭建Zookeeper集羣github

  • 在QConf 配置文件中配置Zookeeper集羣地址shell

vi QCONF_INSTALL_PREFIX/conf/idc.conf複製代碼
#all the zookeeper host configuration.
  #[zookeeper]
  zookeeper.test=127.0.0.1:2181,127.0.0.1:2182,127.0.0.1:2183 #test機房zookeeper配置複製代碼
  • 在QConf配置文件中指定本地機房
echo test > QCONF_INSTALL_PREFIX/conf/localidc #指定本地機房爲test複製代碼
  • 啓動QConf
cd QCONF_INSTALL_PREFIX/bin && sh agent-cmd.sh start複製代碼

使用樣例

  • shell
qconf get_conf /demo/node1   # get the value of '/demo/node1'複製代碼

文檔

總體認識

      Qconf採用Zookeeper爲分佈式配置數據集羣,利用qconf_agent與zookeeper集羣交互獲取數據,業務代碼經過與qconf進行交互獲取配置信息,Qconf服務端與zookeeper集羣交互進行配置集羣數據。整體來看仍是很清晰的,其核心就是利用zookeeper分佈式系統及其watcher功能。緩存

架構

      進入主題,開始介紹QConf的架構實現,下圖展現的是QConf的基本結構,從角色上劃分主要包括 QConf客戶端QConf服務端 QConf管理端


QConf服務端

    QConf使用ZooKeeper集羣做爲服務端提供服務。能夠將單條配置內容直接存儲在ZooKeeper的一個ZNode上,並利用ZooKeeper的Watch監聽功能實現配置變化時對客戶端的及時通知。 按照ZooKeeper的設計目標,其只提供最基礎的功能,包括順序一致,原子性,單一系統鏡像,可靠性和及時性。

QConf客戶端

由於ZooKeeper在接口方面只提供了很是基本的操做,而且其客戶端接口原始,因此咱們須要在QConf的客戶端部分解決以下問題:

  • 下降與ZooKeeper的連接數 原生的ZooKeeper客戶端中,全部須要獲取配置的進程都須要與ZooKeeper保持長鏈接,在生產環境中每一個客戶端機器可能都會有上百個進程須要訪問數據,這對ZooKeeper的壓力很是大並且也是沒必要要的。

  • 本地緩存 固然咱們不但願客戶端進程每次須要數據都走網絡獲取,因此須要維護一份客戶端緩存,僅在配置變化時更新。

  • 容錯 當進程死掉,網絡終端,機器重啓等異常狀況發生時,咱們但願能儘量的提供可靠的配置獲取服務。

  • 多語言版本接口 目前提供的語言版本包括:c,php,java,python,go,lua,shell。

  • 配置更新及時 能夠秒級同步到全部客戶端機器。

  • 高效的配置讀取 內存級的訪問速度。

下面來看下QConf客戶端的架構:

能夠看到QConf客戶端主要有:Agent、各類語言接口、鏈接他們的消息隊列和共享內存。

在QConf中,配置以Key-Value的形式存在,業務進程給出key得到對應Value,這與傳統的配置文件方式是一致的。

下面經過兩個主要場景的數據流動來講明他們各自的功能和角色:

場景1.業務進程請求數據:

  1. 業務進程調用某一種語言的QConf接口,從共享內存中查找須要的配置信息。

  2. 若是存在,直接獲取,不然會向消息隊列中加入該配置key。

  3. Agent從消息隊列中感知須要獲取的配置key。

  4. Agent向ZooKeeper查詢數據並註冊監聽。

  5. Agent將得到的配置Value序列化後放入共享內存。

  6. 業務進程從共享內存中得到最新值。

場景2.配置信息更新:

圖6 數據流動-配置更新

  1. ZooKeeper通知Agent某配置項發生變化。

  2. Agent從ZooKeeper查詢新值並更新Watcher。

  3. Agent用新值更新共享內存中的該配置項。

經過上面的說明,能夠看出QConf的總體結構和流程很是簡單。 QConf中各個組件或線程之間僅經過有限的中間數據結構通訊,耦合性很是小,各自只負責本身的本職工做和一畝三分地,而不感知總體結構。

下面經過幾個點來詳細介紹:

無鎖

根據上文提到的配置信息的特徵,咱們認爲在QConf客戶端進行的是多進程並行讀取的過程,對配置數據來講讀操做遠多於寫操做。爲了儘量的提升讀效率,整個QConf客戶端在操做共享內存時採用的是無鎖的操做,同時爲了保證數據的正確,採起了以下兩個措施:

單點寫

將寫操做集中到單一線程,其餘線程經過中間數據結構與之通訊,寫操做排隊,用這種方法犧牲掉一些寫效率。 在QConf客戶端,須要對共享內存進行寫操做的場景有:

  • 用戶進程經過消息隊列發送的需獲取Key;

  • ZooKeeper 配置修改刪除等觸發Watcher通知,需更新;

  • 爲了消除Watcher丟失形成的不一致,須要定時對共享內存中的全部配置從新註冊Watcher,此時可能會須要更新;

  • 發生Agent重啓、網絡中斷、ZooKeeper會話過時等異常狀況以後,需從新拉數據,此時可能須要更新。

讀驗證

無鎖的讀寫方式,會存在讀到未寫入徹底數據的危險,但考慮到在絕對的讀多寫少環境中這種狀況發生的機率較低,因此咱們容許其發生,經過讀操做時的驗證來發現。共享內存數據在序列化時會帶其md5值,業務進程從共享內存中讀取時,利用預存的md5值驗證是否正確讀取。

異常處理

QConf中採起了一些處理來應對不可避免的異常狀況:

  • 採用父子進程Keepalive的方式,應對Agent進程異常退出的狀況;

  • 維護一份落盤數據,應對斷網狀況下共享內存又被清空的情況;

  • 網絡中斷恢復後,對共享內存中全部數據進行檢查,並從新註冊Watcher;

  • 定時掃描共享內存;

數據序列化

QConf 客戶端中有多處須要將數據序列化通訊或存儲,包括共享內存,消息隊列,落盤數據中的內容。 咱們採起了以下協議:

圖7 數據序列化協議

Agent任務

經過上面的描述,你們應該大體知道了Agent所作的一些事情,下面從Agent內線程分工的角度整理一下,以下圖:

圖8 Agent內部結構

  • Send線程:ZooKeeper線程,處理網絡數據包,進行協議包的解析與封裝,並將Zookeeper的事件加入WaitingEvent隊列等待處理。

  • Event 線程:ZooKeeper線程,依次獲取WaitingEvent隊列中的事件,並進行相應處理,這裏咱們關注節點刪除、節點值修改、子節點變化、會話過時等事件。對特定的事件會進行相應的操做,以節點值修改成例,Agent會按上邊提到的方式序列化該節點Key,並將其加入到WaitingWriting隊列,等待Main線程處理。

  • Msq線程:以前講數據流動場景的時候有提到,用戶進程從共享內存中找不到對應配置後,會向消息隊列中加入該配置,Msq線程即是負責從消息隊列中獲取業務進程的取配置需求,並一樣經過WaitingWriting隊列發送給Main進程。

  • Scan線程:掃描共享內存中的全部配置,發現與Zookeeper不一致的狀況時,將key值加入WaitingWriting隊列。Scan線程會在ZooKeeper重連或輪詢期到達時進行上述操做。

  • Main線程:共享內存的惟一寫入線程,從Zookeeper得到數據寫入共享內存,維護共享內存中的內容。

  • Trigger線程:該線程負責一些周邊邏輯的調用。

www.tuicool.com/articles/BJ…

相關文章
相關標籤/搜索