隨著大數據時代的到來,分布式是解決大數據問題的一個主要手段,隨著越來越多的分布式的服務,如何在分布式的系統中對這些服務做協調變成了一個很棘手的問題。今天我們就來看看如何使用C# ,利用開源對分布式服務做協調。
在對分布式的應用做協調的時候,主要會碰到以下的應用場景:
- 業務發現(service discovery)
找到分布式系統中存在那些可用的服務和節點
- 名字服務 (name service)
通過給定的名字知道到對應的資源
- 配置管理 (configuration management)
如何在分布式的節點中共享配置文件,保證一致性。
- 故障發現和故障轉移 (failure detection and failover)
當某一個節點出故障的時候,如何檢測到并通知其它節點, 或者把想用的服務轉移到其它的可用節點
- 領導選舉(leader election)
如何在眾多的節點中選舉一個領導者,來協調所有的節點
- 分布式的鎖 (distributed exclusive lock)
如何通過鎖在分布式的服務中進行同步
- 消息和通知服務 (message queue and notification)
如何在分布式的服務中傳遞消息,以通知的形式對事件作出主動的響應
Consul
Consul是用Go開發的分布式服務協調管理的工具,它提供了服務發現,健康檢查,Key/Value存儲等功能,并且支持跨數據中心的功能。consul提供的一些關鍵特性:
-
service discovery:consul通過DNS或者HTTP接口使服務注冊和服務發現變的很容易,一些外部服務,例如saas提供的也可以一樣注冊。
-
health checking:健康檢測使consul可以快速的告警在集群中的操作。和服務發現的集成,可以防止服務轉發到故障的服務上面。
-
key/value storage:一個用來存儲動態配置的系統。提供簡單的HTTP接口,可以在任何地方操作。
-
multi-datacenter:無需復雜的配置,即可支持任意數量的區域。
Consul基于HTTP的API可以方便的和各種語言進行綁定,C# 語言綁定https://github.com/PlayFab/consuldotnet
Consul在Cluster上的每一個節點都運行一個Agent,這個Agent可以使用Server或者Client模式。Client負責到Server的高效通信,相對為無狀態的。 Server負責包括選舉領導節點,維護cluster的狀態,對所有的查詢做出響應,跨數據中心的通信等等。
consul官網已經有編譯好的二進制包,支持各種平臺:win、linux等等,下載符合你平臺的軟件包:在這里,下載包:0.5.2_windows_386.zip。解壓完畢后只有一個consul文件。
D:\GitHub\consuldotnet\Consul.Test>consul
usage: consul [--version] [--help] <command> [<args>]
Available commands are:
agent Runs a Consul agent
configtest Validate config file
event Fire a new event
exec Executes a command on Consul nodes
force-leave Forces a member of the cluster to enter the "left" state
info Provides debugging information for operators
join Tell Consul agent to join cluster
keygen Generates a new encryption key
keyring Manages gossip layer encryption keys
leave Gracefully leaves the Consul cluster and shuts down
lock Execute a command holding a lock
maint Controls node or service maintenance mode
members Lists the members of a Consul cluster
monitor Stream logs from a Consul agent
reload Triggers the agent to reload configuration files
version Prints the Consul version
watch Watch for changes in Consul
consul安裝完畢后,agent就可以啟動了,agent可以運行在server或者client模式,每個數據中心至少有一個agent運行在server模式,一般建議是3或者5個server。部署單個server是非常不好的,因為在失敗場景中出現數據丟失是不可避免的。本文涵蓋的是創建一個新的數據中心,所有其他的agents都運行在client模式,這是一個非常輕量級的服務注冊進程,它會運行健康監測,并將查詢結果轉發到服務。agent必須運行在集群中的每一個節點上。
consul.exe agent -config-file test_config.json
我們先運行一個agent在server模式:
D:\GitHub\consuldotnet\Consul.Test> consul.exe agent -config-file test_config.json
==> WARNING: Bootstrap mode enabled! Do not enable unless necessary
==> WARNING: Windows is not recommended as a Consul server. Do not use in production.
==> WARNING: It is highly recommended to set GOMAXPROCS higher than 1
==> Starting Consul agent...
==> Starting Consul agent RPC...
==> Consul agent running!
Node name: 'GEFFZHANG-NB'
Datacenter: 'dc1'
Server: true (bootstrap: true)
Client Addr: 127.0.0.1 (HTTP: 8500, HTTPS: -1, DNS: 8600, RPC: 8400)
Cluster Addr: 192.168.1.4 (LAN: 8301, WAN: 8302)
Gossip encrypt: false, RPC-TLS: false, TLS-Incoming: false
Atlas: <disabled>
==> Log data will now stream in as it occurs:
2015/08/09 09:14:48 [INFO] serf: EventMemberJoin: GEFFZHANG-NB 192.168.1.4
2015/08/09 09:14:48 [INFO] serf: EventMemberJoin: GEFFZHANG-NB.dc1 192.168.1.4
2015/08/09 09:14:48 [INFO] raft: Node at 192.168.1.4:8300 [Follower] entering Follower state
2015/08/09 09:14:48 [INFO] consul: adding server GEFFZHANG-NB (Addr: 192.168.1.4:8300) (DC: dc1)
2015/08/09 09:14:48 [INFO] consul: adding server GEFFZHANG-NB.dc1 (Addr: 192.168.1.4:8300) (DC: dc1)
2015/08/09 09:14:48 [ERR] agent: failed to sync remote state: No cluster leader
2015/08/09 09:14:50 [WARN] raft: Heartbeat timeout reached, starting election
2015/08/09 09:14:50 [INFO] raft: Node at 192.168.1.4:8300 [Candidate] entering Candidate state
2015/08/09 09:14:50 [DEBUG] raft: Votes needed: 1
2015/08/09 09:14:50 [DEBUG] raft: Vote granted. Tally: 1
2015/08/09 09:14:50 [INFO] raft: Election won. Tally: 1
2015/08/09 09:14:50 [INFO] raft: Node at 192.168.1.4:8300 [Leader] entering Leader state
2015/08/09 09:14:50 [INFO] consul: cluster leadership acquired
2015/08/09 09:14:50 [INFO] consul: New leader elected: GEFFZHANG-NB
2015/08/09 09:14:50 [INFO] raft: Disabling EnableSingleNode (bootstrap)
2015/08/09 09:14:50 [DEBUG] raft: Node 192.168.1.4:8300 updated peer set (2): [192.168.1.4:8300]
2015/08/09 09:14:50 [DEBUG] consul: reset tombstone GC to index 2
2015/08/09 09:14:50 [INFO] consul: member 'GEFFZHANG-NB' joined, marking health alive
2015/08/09 09:14:51 [INFO] agent: Synced service 'consul'
2015/08/09 09:16:03 [DEBUG] agent: Service 'consul' in sync
2015/08/09 09:17:30 [DEBUG] agent: Service 'consul' in sync
2015/08/09 09:18:38 [DEBUG] agent: Service 'consul' in sync
2015/08/09 09:19:47 [DEBUG] http: Request /v1/status/peers (0)
2015/08/09 09:19:52 [DEBUG] agent: Service 'consul' in sync
正如你看到的一樣,consul agent已經啟動了,并且打印了一些日志到終端上,從日志中可以看到我們的agent已經運行在server模式了,并且已經是整個集群的領導節點。而且,本地成員已經被標記為集群中的健康成員了。這時候你在另一個終端中運行consul members就可以看到整個集群中的成員了。這時候你只能看到你自己,因為我們的集群中還沒加入其他成員。
輸出已經顯示了你自己的節點信息,有地址信息、健康狀況、在集群中的角色、以及一些版本信息,如果要查看一些metadata,則可以加入-detailed標記
consul members命令輸出的信息是基于gossip協議產生的,并且最終一致的。
KV基本操作
Consul提供了一個簡單的K/V存儲系統,這可以用來動態獲取配置、進行服務協調、主節點選舉,其他開發人員能想到的build過程等等。
var client = new Client();
var kv = client.KV;
var key = GenerateTestKeyName();
var value = Encoding.UTF8.GetBytes("test");
var getRequest = kv.Get(key);
Assert.IsNull(getRequest.Response);
var pair = new KVPair(key)
{
Flags = 42,
Value = value
};
var putRequest = kv.Put(pair);
Assert.IsTrue(putRequest.Response);
getRequest = kv.Get(key);
var res = getRequest.Response;
Assert.IsNotNull(res);
Assert.IsTrue(StructuralComparisons.StructuralEqualityComparer.Equals(value, res.Value));
Assert.AreEqual(pair.Flags, res.Flags);
Assert.IsTrue(getRequest.LastIndex > 0);
var del = kv.Delete(key);
Assert.IsTrue(del.Response);
getRequest = kv.Get(key);
Assert.IsNull(getRequest.Response);
服務發現(Service Discovery)和健康檢查(Health Check)
Consul的另一個主要的功能是用于對分布式的服務做管理,用戶可以注冊一個服務,同時還提供對服務做健康檢測的功能。
服務定義:一個服務可以通過提供服務定義配置文件或者通過調用HTTP API來動態的增加、刪除、修改服務。
服務查詢:一旦agent啟動后,并且服務已經同步,我們就可以使用DNS或者HTTP API來進行查詢了。
服務升級:服務定義的升級可以通過先修改服務定義配置文件,然后給agent發送一個SIGHUP信號即可,這樣允許你在升級服務時,而不會產生agent宕機時間或者服務不可達。或者通過HTTP API接口來動態的增加、刪除、修改服務。
Consul支持三種Check的模式:
- 調用一個外部腳本(Script),在該模式下,consul定時會調用一個外部腳本,通過腳本的返回內容獲得對應服務的健康狀態。
- 調用HTTP,在該模式下,consul定時會調用一個HTTP請求,返回2XX,則為健康;429 (Too many request)是警告。其它均為不健康
- 主動上報,在該模式下,服務需要主動調用一個consul提供的HTTP PUT請求,上報健康狀態。
C# API提供對應的接口
- Client.Agent.Service
- Client.Agent.Check
Consul的Health Check,通過調用腳本,HTTP或者主動上報的方式檢查服務的狀態,更為靈活,可以獲得等多的信息,但是也需要做更多的工作。
故障檢測(Failure Detection)
Consul提供Session的概念,利用Session可以檢查服務是否存活。對每一個服務我們都可以創建一個session對象,注意這里我們設置了ttl,consul會以ttl的數值為間隔時間,持續的對session的存活做檢查。對應的在服務中,我們需要持續的renew session,保證session是合法的。
var client = new Client();
var sessionRequest = client.Session.Create(new SessionEntry() { TTL = TimeSpan.FromSeconds(10) });
var id = sessionRequest.Response;
Assert.IsTrue(sessionRequest.RequestTime.TotalMilliseconds > 0);
Assert.IsFalse(string.IsNullOrEmpty(sessionRequest.Response));
var tokenSource = new CancellationTokenSource();
var ct = tokenSource.Token;
client.Session.RenewPeriodic(TimeSpan.FromSeconds(1), id, WriteOptions.Empty, ct);
tokenSource.CancelAfter(3000);
Task.Delay(3000, ct).Wait(ct);
var infoRequest = client.Session.Info(id);
Assert.IsTrue(infoRequest.LastIndex > 0);
Assert.IsNotNull(infoRequest.KnownLeader);
Assert.AreEqual(id, infoRequest.Response.ID);
Assert.IsTrue(client.Session.Destroy(id).Response);
這里注意,因為是基于ttl(最小10秒)的檢測,從業務中斷到被檢測到,至少有10秒的時延,對應需要實時響應的情景,并不適用。
領導選舉和分布式的鎖
這篇文檔介紹了如何利用Consul的KV存儲來實現Leader Election,利用Consul的KV功能,可以很方便的實現領導選舉和鎖的功能。
WEB UI
consul同樣也支持web界面,這個UI可以用來查看所有的服務和節點,所有的健康檢測和它們當前的狀態,讀取設置K/V系統的值。UI默認自動支持多datacenter。這些UI是靜態html你不需要單獨運行一個web服務器,consul agent本身可以配置一個web服務。
下載UI組件:WEB UI
下載完成后是一個0.5.2_web_ui.zip壓縮文件,解壓后是一個dist目錄。然后添加-ui-dir參數和-client參數重新啟動agent。
D:\GitHub\consuldotnet\Consul.Test> consul.exe agent -config-file test_config.json -ui-dir=D:\GitHub\consuldotnet\Consul.Test\0.5.2_web_ui\dist
在瀏覽器中輸入http://127.0.0.1:8500,即可訪問UI了
有services、nodes、K/V、acl、datacenter的管理,很完善的一個系統了。
總結
Consul作為使用Go語言開發的分布式協調,對業務發現的管理提供很好的支持,他的HTTP API也能很好的和不同的語言綁定,并支持跨數據中心的應用。缺點是相對較新,適合喜歡嘗試新事物的用戶。
https://github.com/anurse/Consulate
https://github.com/geffzhang/Consul-IO-WindowsDemo
https://github.com/catwithboots/Hortlak
https://github.com/catwithboots/Orek
https://github.com/geffzhang/Pk.OrleansUtils
http://blog.csdn.net/u010246789/article/category/6286612
文章列表