0%

.net core 使用Consul

什么是Consul

Consul是一个服务网格(微服务间的 TCP/IP,负责服务之间的网络调用、限流、熔断和监控)解决方案,它是一个一个分布式的,高度可用的系统,而且开发使用都很简便。它提供了一个功能齐全的控制平面,主要特点是:服务发现、健康检查、键值存储、安全服务通信、多数据中心。

Consul是用Go开发的分布式服务协调管理的工具,它提供了服务发现,健康检查,Key/Value存储等功能,并且支持跨数据中心的功能。consul提供的一些关键特性:

  • service discovery:consul通过DNS或者HTTP接口使服务注册和服务发现变的很容易,一些外部服务,例如saas提供的也可以一样注册。
  • health checking:健康检测使consul可以快速的告警在集群中的操作。和服务发现的集成,可以防止服务转发到故障的服务上面。
  • key/value storage:一个用来存储动态配置的系统。提供简单的HTTP接口,可以在任何地方操作。
  • multi-datacenter:无需复杂的配置,即可支持任意数量的区域。

Consul的应用

服务注册与发现

其实服务注册与发现的原理很简单。

当我们在本机运行Consul时,他会自动监听8500端口;然后我们通过一个开源类库(这个开源类库可以在nuget上检索到,文章下面会介绍),调用其下不同的方法来向这个Consul进程发送TCP消息,来注册服务或者发现服务。

Consul进程在接收到注册消息时,就把注册的服务信息存储到本地磁盘或内存(因为我没有具体去调查Consul存储数据是否使用了数据库,但我们都知道数据库的数据也是保存在本地磁盘的,所以,它肯定是把数据存进磁盘或者内存中了)。

数据中心

Consul存储数据的地方,官方为其命名为数据中心,也就是上面说的保存我们注册的服务信息的本地磁盘或者内存。

Consul提供负载均衡的集群

Consul的集群也很好理解,在我们成功启动Consul以后,它除了监听8500端口以外,它还监听了一个8031端口。

这个8031端口就是用于Consul集群相互通信的。

我们都知道集群是要两台以上的电脑的,所以,我们就必须找到两台或以上的电脑安装Consul中间件。

然后,使用Consul的命令行,将两台电脑连接到一起,这样集群就形成了。

在集群内每台电脑上安装的Consul中间件,我们统称为服务器代理(Agent);当集群启动后,会在多个代理服务器之间选举出一个Leader。

选举Leader自然就是服务器代理之间的通信了,也就是通过上面提到的8031端口通信的。

选举了Leader,服务器代理就可以将自身的负载信息发送给Leader了,这样客户端调用Consul检索服务数据时,就可以去性能最优的那台机器上获取信息了。(注:这个就是举例说明,并非Consul的负载均衡的真实处理模式)

代码例子

服务注册与发现

我们新建一个 api Service

在 startup.cs 中的 Configure 增加如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
string ip = Configuration["ip"];//部署到不同服务器的时候不能写成127.0.0.1或者0.0.0.0,因为这是让服务消费者调用的地址
int port = int.Parse(Configuration["port"]);//获取服务端口
var client = new ConsulClient(ConfigurationOverview); //回调获取
var result = client.Agent.ServiceRegister(new AgentServiceRegistration()
{
ID = "ServerNameFirst" + Guid.NewGuid(),//服务编号保证不重复
Name = "MsgServer",//服务的名称
Address = ip,//服务ip地址
Port = port,//服务端口
Check = new AgentServiceCheck //健康检查
{
DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后反注册
Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔,或者称为心跳间隔(定时检查服务是否健康)
HTTP = $"http://{ip}:{port}/api/Health",//健康检查地址
Timeout = TimeSpan.FromSeconds(5)//服务的注册时间
}
});
1
2
3
4
5
6
7
private static void ConfigurationOverview(ConsulClientConfiguration obj)
{
//consul的地址
obj.Address = new Uri("http://192.168.1.37:8500");
//数据中心命名
obj.Datacenter = "dc1";
}

客户端调用

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
38
39
40
41
42
static List<string> Urls = new List<string>();

static void Main(string[] args)
{
Console.WriteLine("开始输出当前所有服务地址");
Catalog_Nodes().GetAwaiter().GetResult();
//Console.WriteLine(HelloConsul().GetAwaiter().GetResult());
Console.WriteLine("开始随机请求一个地址服务地址");
int index = new Random().Next(Urls.Count);
string url = Urls[index];

Console.WriteLine("请求的随机地址:" + url);
HttpClient client = new HttpClient();
var result = client.GetAsync(url).Result;
//string result = HttpClientHelpClass.PostResponse(url, param, out string statusCode);
Console.WriteLine("返回状态:" + result.StatusCode);
Console.WriteLine("返回结果:" + result.Content);
Console.ReadLine();
}
public static async Task Catalog_Nodes()
{
var client = new ConsulClient(ConfigurationOverview);
var nodeList = await client.Agent.Services();
var url = nodeList.Response.Values;

foreach (var item in url)
{
string Address = item.Address;
int port = item.Port;
string name = item.Service;
Console.WriteLine($"地址:{Address}:{port},name:{name}");
Urls.Add($"http://{Address}:{port}/weatherforecast");
}
}

private static void ConfigurationOverview(ConsulClientConfiguration obj)
{
//consul的地址
obj.Address = new Uri("http://192.168.1.37:8500");
//数据中心命名
obj.Datacenter = "dc1";
}

运行即可看到 我们已经成功调用了Consul,也成功的获取到了服务信息。

参考:
https://www.cnblogs.com/shanyou/archive/2015/08/09/4714838.html
https://www.cnblogs.com/kiba/p/11941731.html
https://www.cnblogs.com/yanbigfeg/p/9199590.html