Consul([ˈkɒnsl],康搜)是注册中心,服务提供者、服务消费者等都要注册到Consul中,这样就可以实现服务提供者、服务消费者的隔离。
除了Consul之外,还有Eureka、Zookeeper等类似软件。
用DNS举例来理解Consul。consul是存储服务名称与IP和端口对应关系的服务器。
假设:我有3台用于发帖的服务器,他们的IP和端口分别是
127.0.0.1:8887
127.0.0.1:8888
127.0.0.1:8889
那么这三台服务器就在Consul中注册,那么Consul就知道了这三台服务器的IP可端口了。当我们要发帖,想调用发帖服务的时候,就像Consul要,Consul会告诉我们,哪些服务器提供了发帖服务,然后我们自己选择一个发帖服务器就可以了。(是不是特别简单,这样就不需要我们记住有那些发帖服务器的IP地址和端口了)
Consul还提供一个健康检查的功能
假如有三台发帖的服务器都在Consul进行注册了发帖服务,假如有一台服务器挂了怎么办? 所有Consul就提供了一个服务器的健康检查功能,他会每隔一段时间向这三台服务器发送心跳包,比如每隔10秒钟就向这三台服务器请求一次,通过这样来检查这三台服务器是否还活着
https://www.consul.io/downloads.html
因为我的电脑是windows64位的,因为仅仅是测试,所有就下了一个windows版本的Consul
下载下来后,在运行中输入cmd 命令,然后在cmd中输入命令,执行cd命令切换到consul文件所在的盘符及文件夹
然后执行 consul.exe agent -dev
【这是开发环境测试,所有运行一台服务器就够了,因为开发环境无所谓稳定不稳定,但是如果是生产环境就要建集群,要至少一台Server,多台Agent】如果觉得搭建环境麻烦的话就去阿里云去买Consul服务吧,阿里云都给你配置好了,直接用就行
开发环境中consul重启后数据就会丢失。
consul的监控页面http://127.0.0.1:8500/
consult主要做三件事:提供服务到ip地址的注册;提供服务到ip地址列表的查询;对提供服务方的健康检查(HealthCheck);
在nuget管理器中执行:Install-Package Consul
1>创建一个Asp.Net Core Web应用程序(这个应用程序主要提供发送信息的服务,所有我取名叫MsgServer)
在程序中添加一个API控制器(这个控制器主要用于做服务器的健康检查,所有我取名叫HealthController)
using Microsoft.AspNetCore.Mvc;
namespace MsgServer.Controllers
{
[Produces("application/json")]
[Route("api/Health")]
public class HealthController : Controller
{
//这个控制器主要用于对这个服务的健康检查,如果返回OK表示服务正常,没有挂掉
[HttpGet]
public IActionResult Get()
{
Console.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "health check");
return Content("ok");
}
}
}
Program.cs文件
namespace MsgServer
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args)
{
//程序通过selfhost方式启动,可以设置这个args参数值。比如:dotnet test.dll --ip 127.0.0.1 --port 8080
//args就会接收到ip,port这些值。如果直接以IIS Express方式启动,这里好像是接收不到args参数的
var config = new ConfigurationBuilder().AddCommandLine(args).Build();
string ip = config["ip"];
string port = config["port"];
return WebHost.CreateDefaultBuilder(args)
.UseStartup()
//.UseUrls("http://127.0.0.1:8080") //如果要在之类指定了URL地址,那么它的优先权最高
.UseUrls($"http://{ip}:{port}")
.Build();
}
}
}
Startup.cs文件
using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
namespace MsgServer
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
string ip = Configuration["ip"];
string port = Configuration["port"];
string serviceName = "MsgService";//服务名称
string serviceId = serviceName + Guid.NewGuid();//服务编号
using (var consulClient = new ConsulClient(consulConfig))
{
AgentServiceRegistration ars = new AgentServiceRegistration();
ars.Address = ip; //服务器的IP地址(必须能被调用者访问的IP地址,所有正式环境就不能用127.0.0.1)
ars.Port = Convert.ToInt32(port); //服务器的端口号,必须能被调用者访问的的端口
ars.Name = serviceName;//服务器名称(同一个服务,服务名称都是一致的)
ars.ID = serviceId; //服务器的编号(如果有5个发帖服务器,那么它们的服务器编号都是唯一的)
ars.Check = new AgentServiceCheck() //健康检查
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), //发现服务器挂了后,多久时间注销掉这个服务器
HTTP = $"http://{ip}:{port}/api/Health",//健康检查调用的控制器地址
Interval = TimeSpan.FromSeconds(10),//多久多一次健康检查(心跳检查)
Timeout = TimeSpan.FromSeconds(5)
};
consulClient.Agent.ServiceRegister(ars).Wait();//注意:Consult客户端的所有方法几乎都是异步方法,但是都没按照规范加上Async后缀,所以容易误导。记得调用后要Wait()或者await
};
//服务器正常退出的时候的注册事件,这个注册事件就是从Consul注销服务(它是调用的Register方法进行事件注册的)
//它需要通过方法参数注入IApplicationLifetime对象,从这个对象中可以知道,服务器是否退出
appLifetime.ApplicationStopped.Register(() =>
{
using (var consulClient = new ConsulClient(consulConfig))
{
Console.WriteLine("应用退出,开始从consul注销");
consulClient.Agent.ServiceDeregister(serviceId).Wait();//即注销服务编号为serviceId的服务器
}
});
//appLifetime.ApplicationStarted.Register(() => { });//服务启动的注册事件
//appLifetime.ApplicationStopping.Register(() => { }); //服务正在启动中的注册事件
}
private void consulConfig(ConsulClientConfiguration c)
{
c.Address = new Uri("http://127.0.0.1:8500"); //Consul服务的地址,Consul默认端口号就是8500
c.Datacenter = "dc1";
}
}
}
启动项目
服务的调用
1>创建一个控制台项目(获取其他项目)我取名叫ClientProject
2>在项目中安装Consul
using Consul;
using System;
namespace ClientProject
{
class Program
{
static void Main(string[] args)
{
using (var consulClient = new ConsulClient(r => r.Address = new Uri("http://127.0.0.1:8500")))
{
//获取到在Consul中注册的所有服务
var services = consulClient.Agent.Services().Result.Response;
foreach (var service in services.Values)
{
//我们获取到所有的服务器后,自己决定要连接那台服务器(我们可以随机的选择一条服务器,或则采用轮询机制,或其他的方式,总之是达到负载均衡的效果)
Console.WriteLine($"id={service.ID},name={service.Service},ip={service.Address},port={service.Port}");
}
Console.ReadKey();
}
}
}
}