Consul是一种提供具有服务发现,配置和分段功能的全功能控制平面的服务网格解决方案,其主要功能有:
服务发现:Consul的客户端可以注册服务,例如api或mysql,其他客户端可以使用Consul来发现给定服务的提供者。使用DNS或HTTP,应用程序可以轻松找到它们所依赖的服务。
健康监测:Consul客户端可以提供与给定服务相关的任意数量的健康检查,可以使用此信息来监控集群运行状况,服务发现组件使用该信息将流量路由远离不健康的主机。
键值存储:应用程序可以将Consul的分层键/值存储用于任何目的,包括动态配置,功能标记,协调,领导者选举等。简单的HTTP API使其易于使用。
Secure Service Communication: Consul可以为服务生成和分发TLS证书,以建立相互的TLS连接。意图可用于定义允许哪些服务进行通信。可以使用可以实时更改的意图轻松管理服务分段,而不是使用复杂的网络拓扑和静态防火墙规则。
多数据中心:Consul支持多个数据中心。这意味着Consul的用户不必担心构建额外的抽象层以扩展到多个区域。
具体关于Consul的介绍可以查看官网:https://www.consul.io/docs/index.html 。这里介绍在我们的项目中使用到的服务注册与发现功能。
首先下载对应平台的consul进行安装,笔者使用windows 64位,具体下载链接:https://www.consul.io/downloads.html 。windows下载下来就是一个consul.exe文件,可以运行下面的命令来启动consul服务。
consul.exe agent --dev
浏览器访问 http://localhost:8500/ui/dc1/services 可以看到Consul的界面
安装完Consul之后,如何在User.Identity中找到User.Api呢,接着往下看。
要让User.Identity找到,需要将User.Api注册到Consul中,首先在User.Api项目中添加Consul的Nuget包。
install-package Consul
在appsettings.json中添加配置
"ServiceDiscovery": {"ServiceName": "userapi","Consul": {"HttpEndpoint": "http://127.0.0.1:8500","DnsEndpoint": {"Address": "127.0.0.1","Port": 8600}
}
}
为了读取到该配置,需要创建一个ServiceDiscoveryOptions、ConsulOptions、DnsEndpoint来建立映射。
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Net;usingSystem.Threading.Tasks;namespaceUser.API.Dtos
{public classDnsEndpoint
{public string Address { get; set; }public int Port { get; set; }publicIPEndPoint ToIPEndPoint()
{return newIPEndPoint(IPAddress.Parse(Address), Port);
}
}
}
namespaceUser.API.Dtos
{public classConsulOptions
{public string HttpEndpoint { get; set; }public DnsEndpoint DnsEndpoint { get; set; }
}
}
namespaceUser.API.Dtos
{public classServiceDiscoveryOptions
{public string ServiceName { get; set; }public ConsulOptions Consul { get; set; }
}
}
接着在Startup.cs中添加注入
services.AddOptions();
services.Configure(Configuration.GetSection("ServiceDiscovery"));
services.AddSingleton(p => new ConsulClient(cfg =>{var serviceConfiguration = p.GetRequiredService>().Value;if (!string.IsNullOrEmpty(serviceConfiguration.Consul.HttpEndpoint))
{//if not configured, the client will use the default value "127.0.0.1:8500"
cfg.Address = newUri(serviceConfiguration.Consul.HttpEndpoint);
}
}));
最后就是在User.Api启动时将其注册到Consul中,停止时删除注册了,代码如下
public voidConfigure(IApplicationBuilder app
,IHostingEnvironment env
,IApplicationLifetime applicationLifetime
,ILoggerFactory loggerFactory
,IOptionsserviceOptions
,IConsulClient consul)
{if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}else{//The default HSTS value is 30 days. You may want to change this for production scenarios, seehttps://aka.ms/aspnetcore-hsts.
app.UseHsts();
}//启动时向consul注册服务
applicationLifetime.ApplicationStarted.Register(()=>{
RegisterService(app, serviceOptions, consul, applicationLifetime);
});app.UseMvc();
}///
///注册服务///
///
///
///
///
private voidRegisterService(IApplicationBuilder app,
IOptionsserviceOptions,
IConsulClient consul,
IApplicationLifetime applicationLifetime)
{var features = app.Properties["server.Features"] asFeatureCollection;var addresses = features.Get()
.Addresses
.Select(p=> newUri(p));foreach (var address inaddresses)
{var serviceId = $"{serviceOptions.Value.ServiceName}_{address.Host}:{address.Port}";var httpCheck = newAgentServiceCheck()
{
DeregisterCriticalServiceAfter= TimeSpan.FromMinutes(1),
Interval= TimeSpan.FromSeconds(30),
HTTP= new Uri(address, "HealthCheck").OriginalString
};var registration = newAgentServiceRegistration()
{
Checks= new[] { httpCheck },
Address=address.Host,
ID=serviceId,
Name=serviceOptions.Value.ServiceName,
Port=address.Port
};
consul.Agent.ServiceRegister(registration).GetAwaiter().GetResult();//停止时向consul清除该服务
applicationLifetime.ApplicationStopping.Register(() =>{
DeRegisterService(consul, serviceId);
});
}
}///
///清除服务///
///
///
private void DeRegisterService(IConsulClient consul,stringserviceId)
{
consul.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();
}
为了consul可以监控user.api的运行情况,在User.Api中创建一个controller
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Threading.Tasks;usingMicrosoft.AspNetCore.Mvc;namespaceUser.API.Controllers
{
[Route("[Controller]")]public classHealthCheckController : Controller
{
[HttpGet("")]
[HttpHead("")]public voidGet()
{
}
}
}
到这里,User.Api注册成功了,接下来就是要在User.Identity中调用User.Api了,我们将用到Polly做熔断重试,下篇再讲。