Consul介紹:html
Consul 是由 HashiCorp 公司推出的開源軟件,用於實現分佈式系統的服務發現與配置。與其餘分佈式服務註冊與發現的方案,Consul 的方案更「一站式」,內置了服務註冊與發現框 架、分佈一致性協議實現、健康檢查、Key/Value 存儲、多數據中心方案,再也不須要依賴其餘工具(好比 ZooKeeper 等),使用起來也較爲簡單。node
Consul的如何實現的?git
Consul 用 Golang 實現,所以具備自然可移植性(支持 Linux、windows 和 Mac OS X ),它的安裝包僅包含一個可執行文件,方便部署,與 Docker 等輕量級容器可無縫配合。github
微服務概念:編程
微服務是一種架構風格,一個大型複雜軟件應用由一個或多個微服務組成。系統中的各個微服務可被獨立部署,各個微服務之間是鬆耦合的。每一個微服務僅關注於完成一件任務並很好地完成該任務。在全部狀況下,每一個任務表明着一個小的業務能力。json
儘管「微服務」這種架構風格沒有精確的定義,但其具備一些共同的特性,如圍繞業務能力組織服務、自動化部署、智能端點、對語言及數據的「去集中化」控制等等。簡而言之,微服務架構風格是一種將單個應用程序開發爲一套小型服務的方法,每一個小型服務都在本身的流程中運行,並與輕量級機制(一般是HTTP資源API)進行通訊。這些服務圍繞業務功能構建,可經過全自動部署機制獨立部署。這些服務至少集中管理,能夠用不一樣的編程語言編寫,並使用不一樣的數據存儲技術。bootstrap
Consul的安裝與配置windows
咱們須要去下載Consul ,下載很簡單,直接去:https://www.consul.io/downloads.html 選擇對應的平臺便可,若是你的是Mac OS x 那麼直接雙擊那個可執行文件便可,個人平臺是windows10 ,那麼相對於MacOsX是比較困難的,即配置環境變量,將文件的位置放到你的path中就能夠了,其目的就是爲了在Cmd終端中可以鍵入執行Consul命令,若是你的環境變量已經配置成功,請在Cmd中敲擊consul,若是結果以下,那麼恭喜您,你成功進入Consul大門。api
名詞解釋安全
Client : Consul 的 Client模式,就是客戶端模式。是 Consul 節點的一種模式,這種模式下,全部註冊到當前節點的服務會被轉發到 Server,自己是不持久化這些信息。
Server :Consul 的 Server 模式,代表這個 Consul 是個 Server ,這種模式下,功能和 Client 都同樣,惟一不一樣的是,它會把全部的信息持久化的本地,這樣遇到故障,信息是能夠被保留的。
Server-Leader: Server 是它們的老大,它和其它 Server 不同的一點是,它須要負責同步註冊的信息給其它的 Server ,同時也要負責各個節點的健康監測。
raft: Server 節點之間的數據一致性保證協議使用的是 raft,而 zookeeper 用的 paxos,etcd採用的也是raft
服務發現協議:Consul 採用 http 和 DNS 協議,etcd 只支持 http 。
服務註冊:Consul 支持兩種方式實現服務註冊,一種是經過 Consul 的服務註冊 Http API,由服務本身調用 API 實現註冊,另外一種方式是經過 json 格式的配置文件實現註冊,將須要註冊的服務以 json 格式的配置文件給出。Consul 官方建議使用第二種方式。
啓動Consul
若是是在單機狀況下使用開發模式啓動,在終端中輸入:
1
|
~ » consul agent -dev
|
開啓Consul 集羣
首先建立Server-Leader,即老大,那麼在終端上輸入如下命令:
1
2
3
4
5
|
//Server
consul agent -server -ui -bootstrap-expect=2 -data-dir=/tmp/consul -node=con
sul-server-1 -client=0.0.0.0 -bind=10.211.55.2 -datacenter=dc1
//Client
consul agent -client -bind 0.0.0.0 本機ip -data-dir=\tmp\consul -node 節點名 -
join
隨意一個服務器的地址
|
其中:
consul agent -server 表示以服務器模式啓動代理。
-bootstrap-expect=2 表示節點個數爲2個。
-node=consul-server-1 表示節點名稱
-client=0.0.0.0 表示客戶端 IP
-bind=10.211.55.2 表示服務端 IP
-datacenter=dc1 數據中心名稱
須要注意的是,若是你啓動的Server模式的話,你必定要注意node名不要相同,不然將會替換你的項。
那麼Server-Leader已經建立了,須要別的服務器去進行鏈接了,若是是Server模式,輸入如下命令,只不過是拼接了-join id.
1
2
3
|
consul agent -server -ui -bootstrap-expect=2 -data-dir=/tmp/consul -node=con
sul-server-2 -client=0.0.0.0 -bind=10.211.55.4 -datacenter=dc1 -
join
10.211.
55.2
|
- -data-dir=/tmp/consul 表示臨時數據存儲路徑
- -join 10.211.55.2 表示加入 10.211.55.2 所在的集羣
這個時候若是出現Consul agent Running!!還有一大堆東西。那麼說明你已經集羣成功了,你能夠去本身的經過Consul提供的UI去看節點情況,地址爲 你本身的id+8500端口,即192.168.10.6:8500或者你的子節點都可,可是若是說你的節點個數是4個,你還有幾個節點沒有放上去,那麼UI是出不來了(有可能會報500錯)。
那麼除了UI查看節點之外,還能夠經過終端輸入指令來查看咱們的節點狀態。
1
|
consul members
|
若是咱們但願獲得更爲詳細的信息,可使用指令來查看
1
|
consul
operator
raft list-peers
|
若是說你沒有服務器集羣,那麼輸入以上命令就會出現如下結果:
建立.NET Core API 並註冊服務
若是你的 Consul Cluster 已經搭建完成,那麼能夠接下來建立一個.NET Core API 來實現服務的註冊。
咱們建立一個空的解決方案,添加解決方案文件夾 「服務註冊」,建立Api項目。
修改啓動配置文件
在launchSettings.json中修改啓動ip和端口。
1
2
3
4
5
6
7
8
9
10
11
|
{
"profiles"
: {
"BasicPlatformService"
: {
"commandName"
:
"Project"
,
"applicationUrl"
:
"http://192.168.43.174:8080"
,
"environmentVariables"
: {
"ASPNETCORE_ENVIRONMENT"
:
"Development"
}
}
}
}
|
添加健康檢查控制器
在項目中添加一個名爲 HealthController 的 API 控制器,用於在將服務註冊到 Consul 後的健康檢查。
1
2
3
4
5
6
7
8
9
10
11
|
[Route(
"api/[controller]"
)]
[ApiController]
public
class
HealthController : ControllerBase
{
/// <summary>
/// 服務健康檢測 ⽅方法
/// </summary>
/// <returns></returns>
[HttpGet]
public
IActionResult Get() => Ok(
" health check ok"
);
}
|
在項目中添加Consul,或者鍵入命令,這固然,由你選擇。
1
|
install-package Consul
|
註冊Consul中間件,修改Startup.cs文件,這裏使用的是 Consul 的服務註冊 Http API。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
public
void
Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime life)
{
if
(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseMvc();
using
(ConsulClient client =
new
ConsulClient(x => x.Address =
new
Uri(
"http://192.168.43.174:8500"
)))
{
var
httpCheck =
new
AgentServiceCheck()
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),
Interval = TimeSpan.FromSeconds(10),
HTTP = $
"http://192.168.43.174:8080/api/health"
,
Timeout = TimeSpan.FromSeconds(5)
};
var
registration =
new
AgentServiceRegistration()
{
Checks =
new
[] { httpCheck },
ID =
"MicroService.Service"
,
Name =
"MicroService.Service"
,
Address =
"192.168.43.174"
,
Port = 8080,
Tags =
new
[] {
"urlprefix-/MicroService.Chanpter01.Service"
}
};
// 服務啓動時註冊,內部實現是使⽤用 Consul API 進⾏行行註冊(HttpClient發起)
client.Agent.ServiceRegister(registration).Wait();
// 當服務停⽌止時,取消註冊
life.ApplicationStopping.Register(() =>
{
// 服務停⽌止時取消註冊
client.Agent.ServiceDeregister(registration.ID).Wait();
});
}
}
|
完成後,啓動項目,此時已成功註冊。
2018-12-18 更新 使用Json文件配置
爲了避免讓每一個服務器都打以上的代碼,那麼咱們可使用json配置(放到你的config中)。建立一個ProjectServer.json
{ "services": [ { "ID": "t169_000000001_student_service", "name": "T169.ZhangZiHao.Service", "tags": [ "urlprefix-/T169.Studeent.Service" ], "address": "192.168.43.174", "port": 8080, "checks": [ { "name": "Student Service check", "http": "http://192.168.43.174:8080/api/health", "interval": "10s", "timeout": "5s" } ] }, { "ID": "t169_000000002_mail_service", "name": "T169.Mail.Service", "tags": [ "urlprefix-/T169.Mail.Service" ], "address": "192.168.43.174", "port": 8081, "checks": [ { "name": "Mail Service check", "http": "http://192.168.43.174:8081/api/health", "interval": "10s", "timeout": "5s" } ] } ] }
其中每一個節點我就不一一闡述了,和硬編碼中的都同樣,就須要改改http address。
而後開始部署集羣的時候要注意了,和上面不同的是 須要你去指定tmp了,就是你的那個config的地方 。
consul agent -server -ui -bootstrap-expect=2 -data-dir=/tmp/consul -config-d ir=/tmp/consul/config -node=consul-server-2 -client=0.0.0.0 -bind=10.211.55. 4 -datacenter=dc1
若是要加入集羣則是:
consul agent -server -ui -bootstrap-expect=2 -data-dir=/tmp/consul -config-d ir=/tmp/consul/config -node=consul-server-2 -client=0.0.0.0 -bind=10.211.55. 4 -datacenter=dc1 -join 10.211.55.2
2018-12-19 更新 使用MailKit
爲了更好的接收健康狀態,那麼咱們使用MailKit,使用這個以前,先nuget這個emailkit。
定義EmailHelper.cs:

public class EmailSettings { public string SmtpServer { get; set; } public int SmtpPort { get; set; } public string AuthAccount { get; set; } public string AuthPassword { get; set; } public string ToWho { get; set; } public string ToAccount { get; set; } public string FromWho { get; set; } public string FromAccount { get; set; } public string Subject { get; set; } } public class EmailHelper { public static void SendHealthEmail(EmailSettings settings, string content) { try { dynamic list = JsonConvert.DeserializeObject(content); if (list != null && list.Count > 0) { var emailBody = new StringBuilder("健康檢查故障:\r\n"); foreach (var noticy in list) { emailBody.AppendLine($"--------------------------------------"); emailBody.AppendLine($"Node:{noticy.Node}"); emailBody.AppendLine($"Service ID:{noticy.ServiceID}"); emailBody.AppendLine($"Service Name:{noticy.ServiceName}"); emailBody.AppendLine($"Check ID:{noticy.CheckID}"); emailBody.AppendLine($"Check Name:{noticy.Name}"); emailBody.AppendLine($"Check Status:{noticy.Status}"); emailBody.AppendLine($"Check Output:{noticy.Output}"); emailBody.AppendLine($"--------------------------------------"); } var message = new MimeMessage(); // 從誰發出 message.From.Add(new MailboxAddress(settings.FromWho, settings.FromAccount)); // 發送給誰 message.To.Add(new MailboxAddress(settings.ToWho, settings.ToAccount)); // 設置郵件標題 message.Subject = settings.Subject; // 設置郵件內容 message.Body = new TextPart("plain") { Text = emailBody.ToString() }; using (var client = new SmtpClient()) { client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect(settings.SmtpServer, settings.SmtpPort, false); client.AuthenticationMechanisms.Remove("XOAUTH2");// 去除安全令牌 // 驗證帳號+密碼 client.Authenticate(settings.AuthAccount, settings.AuthPassword); // 發郵件 client.Send(message); client.Disconnect(true); } } } catch (Exception ex) { Console.WriteLine(ex.Message); } } }
建立一個MailController:
[Produces("application/json")] [Route("api/Mail")] public class MailController : Controller { public IConfiguration Configuration { get; } public MailController(IConfiguration configuration) { Configuration = configuration; } /// <summary> /// /// </summary> /// <returns></returns> [HttpPost("/notice")] public IActionResult Notice() { var bytes = new byte[10240]; var i = Request.Body.ReadAsync(bytes, 0, bytes.Length); var content = System.Text.Encoding.UTF8.GetString(bytes).Trim('\0'); EmailSettings settings = new EmailSettings() { SmtpServer = "smtp.126.com", // 發送郵件的服務器地址 SmtpPort = 25, // 服務器端口號 AuthAccount = "", // 用戶名 AuthPassword = "", // 密碼 ToWho = "接收方名字", // 接收方的名字 ToAccount = "", // 接收方郵箱 FromWho = "你本身的名字", // 發郵件的人姓名 FromAccount ="", // 發郵件的郵件地址 Subject = "health check notice" // 郵件標題 }; EmailHelper.SendHealthEmail(settings, content); return Ok(); } }
而後再建立emailserver.json 那麼就ok了 ,從新啓動集羣。
{ "watches": [ { "type": "checks", "handler_type": "http", "state": "critical", "http_handler_config": { "path": "http://10.211.55.4:8081/notice", "method": "POST", "timeout": "10s", "header": { "Authorization": [ "token" ] } } } ] }
————————————————————————————————————————————————————————————————————————————————————
.NET Core 接入 Consul

-
建立 .NET Core WebAPI 服務 ServiceA(2個實例) 和 ServiceB
-
NuGet 安裝 Consul
-
註冊到 Consul 的核心代碼以下(源碼下載):
public static class ConsulBuilderExtensions { public static IApplicationBuilder RegisterConsul(this IApplicationBuilder app, IApplicationLifetime lifetime, ConsulOption consulOption) { var consulClient = new ConsulClient(x => { // consul 服務地址 x.Address = new Uri(consulOption.Address); }); var registration = new AgentServiceRegistration() { ID = Guid.NewGuid().ToString(), Name = consulOption.ServiceName,// 服務名 Address = consulOption.ServiceIP, // 服務綁定IP Port = consulOption.ServicePort, // 服務綁定端口 Check = new AgentServiceCheck() { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服務啓動多久後註冊 Interval = TimeSpan.FromSeconds(10),//健康檢查時間間隔 HTTP = consulOption.ServiceHealthCheck,//健康檢查地址 Timeout = TimeSpan.FromSeconds(5) } }; // 服務註冊 consulClient.Agent.ServiceRegister(registration).Wait(); // 應用程序終止時,服務取消註冊 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(registration.ID).Wait(); }); return app; } }
-
添加配置以下:
"ServiceName": "ServiceA", "ServiceIP": "192.168.124.8", "ServicePort": 8000, "ServiceHealthCheck": "http://192.168.124.8:8000/healthCheck", "ConsulAddress": "http://192.168.124.8:8500"
-
註冊成功結果以下:
service register -
ServiceB 調用 ServiceA 接口
ServiceB 經過 ConsulClient 進行服務發現,獲取到 ServiceA 的地址,而後隨機任意一臺進行請求,核心代碼以下:
var url = _configuration["ConsulAddress"].ToString(); using (var consulClient = new ConsulClient(a => a.Address = new Uri(url))) { var services = consulClient.Catalog.Service("ServiceA").Result.Response; if (services != null && services.Any()) { // 模擬隨機一臺進行請求,這裏只是測試,能夠選擇合適的負載均衡工具或框架 Random r = new Random(); int index = r.Next(services.Count()); var service = services.ElementAt(index); using (HttpClient client = new HttpClient()) { var response = await client.GetAsync($"http://{service.ServiceAddress}:{service.ServicePort}/values/test"); var result = await response.Content.ReadAsStringAsync(); return result; } } }
-
屢次調用 ServiceB 接口結果以下:


做者:BeckJin
連接: https://www.jianshu.com/p/4aaaee6e9ce1 來源:簡書 著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。