Consul包含多個組件,但是作為一個整體,為你的基礎設施提供服務發現和服務配置的工具。
它提供以下關鍵特性:
服務發現: Consul的客戶端可用提供一個服務,比如 api 或者mysql ,另外一些客戶端可用使用Consul去發現一個指定服務的提供者。通過DNS或者HTTP應用程序可用很容易的找到他所依賴的服務。
健康檢查: Consul客戶端可用提供任意數量的健康檢查,指定一個服務(比如:webserver是否返回了200 OK 狀態碼)或者使用本地節點(比如:內存使用是否大于90%)。 這個信息可由operator用來監視集群的健康.被服務發現組件用來避免將流量發送到不健康的主機。
Key/Value存儲: 應用程序可用根據自己的需要使用Consul的層級的Key/Value存儲。比如動態配置,功能標記,協調,領袖選舉等等,簡單的HTTP API讓他更易于使用.
多數據中心: Consul支持開箱即用的多數據中心,這意味著用戶不需要擔心需要建立額外的抽象層讓業務擴展到多個區域.
Consul面向DevOps和應用開發者友好.是他適合現代的彈性的基礎設施。
安裝
應用consul到微服務集群中,首先要解決的是運維的問題。使用ansible能快速部署與管理consul。
在ansible的配置文件中,指定consul集群的所有機器名,server機器名與client機器名
[dev_all:children]
dev
lab
demo
[dev_server:children]
dev
lab
demo
[dev_client:children]
使用ansible部署consul的腳本
#定義配置目錄
installPath="/usr/local/bin/"
configPath="/etc/consul.d"
dataPath="/tmp/consul"
runLogPath="/tmp/consulRun.log"
ansibleConfPath="/data/x/tools/pub/conf"
sudoCmd="-b --become-user=root --become-method=sudo --ask-become-pass -k"
#安裝consul
cmd="src=$curDir/consul dest=$installPath owner=root group=root mode=0755"
ansible -i $ansibleConfPath/consul.hosts $hostList -m copy -a "$cmd" $sudoCmd
cmd="src=$curDir/consul-template dest=$installPath owner=root group=root mode=0755"
ansible -i $ansibleConfPath/consul.hosts $hostList -m copy -a "$cmd" $sudoCmd
#創建配置目錄
cmd="mkdir -m 755 $configPath;mkdir -m 777 $dataPath"
ansible -i $ansibleConfPath/consul.hosts $hostList -m shell -a "$cmd" $sudoCmd
建立集群
圖中的Server是服務端,Client是客戶端。客戶端不保存數據,將接收到的請求轉發給響應的Server端。Server之間通過局域網或廣域網通信實現數據一致性。每個Server或Client都是一個consul agent。Consul集群間使用了gossip協議通信和raft一致性算法。
Agent 是一直運行在Consul集群中每個成員上的守護進程。agent可以運行在client或者server模式。所有的agent都能運行DNS或者HTTP接口,并負責運行時檢查和保持服務同步。
Client 是一個轉發所有RPC到server的代理。client是相對無狀態的。client唯一執行的后臺活動是加入LAN gossip池。這有一個最低的資源開銷并且僅消耗少量的網絡帶寬。
Server 是一個有一組擴展功能的代理,這些功能包括參與raft選舉,維護集群狀態,響應RPC查詢,與其他數據中心交互和轉發查詢給leader或者遠程數據中心。
DataCenter 是一個私有的,低延遲和高帶寬的一個網絡環境。
綜合可用性和性能考慮,一個數據中心(dc)建議有3-5臺server。如果server越多,達成共識越慢。但不限制client的數量,client可以擴展到數千或者數萬臺。下面是使用ansible啟動consul集群的過程
#啟動server
cmd="consul leave;nohup consul agent -server -data-dir $dataPath -ui -config-dir=$configPath -client 0.0.0.0 >$runLogPath 2>&1 &"
ansible -i $ansibleConfPath/consul.hosts $serverHostList -m shell -a "$cmd" $sudoCmd
#啟動client
cmd="consul leave;nohup consul agent -data-dir $dataPath -config-dir=$configPath -client 0.0.0.0 >$runLogPath 2>&1 &"
ansible -i $ansibleConfPath/consul.hosts $clientHostList -m shell -a "$cmd" $sudoCmd
#構建集群
cmd="consul join 10.24.188.52"
ansible -i $ansibleConfPath/consul.hosts $allHostList -m shell -a "$cmd" $sudoCmd
服務的注冊與發現
平臺當前的微服務的架構,服務注冊與發現是通過如下幾個步驟實現的
- 每個服務項目在nginx中配置獨立的域名,例如 api.xxx.xxx.cn
- 阿里云上新建一個私網slb,設置健康檢查域名,并掛載該服務對應的后端服務器。
- 將該服務的域名api.xxx.xxx.com解析到slb的內網地址上。這樣網關就可以通過內網域名訪問到對應的服務。
如果使用consul實現服務發現,步驟如下
- 每個服務項目需要添加一個服務描述模板文件,如下圖
{
"service":{
"id" : "MARKET",
"name" : "MARKET",
"address" : "api.market.{{key "domain/cn"}}",
"port" : 8086,
"tags" : ["{{key "env/name"}}"],
"checks": [
{
"http": "http://api.market.{{key "domain/cn"}}:8086/monitor",
"interval": "5s"
}
]
}
}
- 在項目發布后的重啟腳本中,使用consul-template工具將服務描述模板文件生成服務描述文件。模板文件中dmoain/cn"與env/name保存在consul提供的kv存儲中。
Consul Template能監控Consul實例的變化,并將模板中變化的數據通過后臺程序渲染到文件。模板文件更新完成后可以運行任何命令
- 將服務描述文件軟鏈到consul的config目錄中后,執行consul reload 。
腳本如下,這里consul template使用-once指令,只渲染一次。
serviceName=$PRJNAME"_service.json"
consul-template -consul-addr=127.0.0.1:8500 -template "options/service.json:used/service.json:ln -fs $CONFDIR/used/service.json /etc/consul.d/$serviceName" -once
consul reload
通過以上幾個步驟就完成了服務注冊。服務發現則是在sdk中,調用consul的http接口查詢服務實現
// 通過consul的8500端口查詢服務信息
static function getConsulCaller()
{
$conf = new XHttpConf();
$conf->conf("127.0.0.1",$logger);
$conf->port = 8500;
$conf->timeout = 5;
$conf->caller = "sdk";
return new XHttpCaller($conf);
}
// 隨機返回一個可用的Address地址
static function queryService()
{
$serviceName = static::confXPath();
$curl = static::getConsulCaller();
$resp = $curl->get("/v1/catalog/service".$serviceName."?passing");
$ret = \XRestResult::ok($resp);
$roundBin = rand(0,$nodeCount);
return $ret[$roundBin];
}
//查詢服務信息
$data = static::queryService();
//通過查詢到的信息生成httpCaller
$conf = self::conf($data['ServiceAddress'],$logger,$proxy,$data['ServicePort'],$data['Address']);4
示意圖如下
從日志中可以看到最終到服務的請求過程
consul控制臺界面如下,可以查看服務的運行情況
總結
consul的引入能夠幫我們解決系統開發中的一些痛點問題,包括以下幾點
- consul使服務注冊與發現變得簡單,不用再去配置slb。
- 使用consul的kv存儲與consul-template工具管理項目配置信息,配置信息變更不用再發版。
還有些問題需要探討
- 服務發現時在sdk中實現的,是否需要單獨一臺機器做請求轉發
- 每個服務的內網域名是否還需要進行解析
以上只是簡單的使用了consul,想在生產環境中使用起來還有很長的一段路要走。