Consul在.Net Core中初体验
2019-12-01

简介

在阅读本文前我想您应该对微服务架构有一个基本的或者模糊的了解

Consul是一个服务管理软件,它其实有很多组件,包括服务发现配置共享键值对存储等

本文主要讲解Consul的服务注册服务发现以及集群的配置

参考资料:

https://blog.csdn.net/younger_china/article/details/79462530

https://www.cnblogs.com/shanyou/p/6286207.html

服务发现

假设有服务A,B,C.服务A需要调用服务B和C,传统的方式我们需要在服务A中记录服务B和C的ip及端口号。这些配置一般写在配置文件等地方存储。

这种做法有两个显而易见的缺点:1.如果将来B的ip改变了就需要修改所有调用者的ip配置。 2.难以做负载均衡

而服务发现就是用来解决这个问题的,怎么解决呢?请看下面这张图

这张图中在服务消费者和服务生产者之间加了一个服务注册中心的模块,用上面的服务器ABC来举例,服务B在发布的时候会在注册中心注册,注册中心会记录服务B的名字及ip地址。当服务A请求服务B的时候,只需要带着服务B的名字来注册中心查询即可。集群情况下,注册中心会有多个服务B。同时注册中心会定期检查每一个服务否可以正常访问,移除不可访问的服务。(健康检查)

总的来说,服务发现就是通过一个标志来获取服务列表,并且服务列表可随着每个服务的上线或下线动态变更

Consul术语及解释

下面列出几个consul中出现频率较高的术语

Agent,Agent是长期运行在每个consul集群成员节点上守护进程。通过命令consul agent启动。Agent有client和server两种模式。由于每个节点都必须运行agent,所有节点要么是client要么是server。所有的Agent都可以可以调用DNS或HTTP API,并负责检查和维护服务同步。client 运行client模式的Agent,将所有的RPCs转发到Server。Client是相对无状态的。Client唯一所做的是在后台参与LAN gossip pool。只消耗少量的资源,少量的网络带宽。Server 运行Server模式的Agent,参与Raft quorum,维护集群的状态,响应RPC查询,与其他数据中心交互WAN gossip,转发查询到Leader或远程数据中心。

datacenter 数据中心的定义似乎是显而易见的,有一些细节是必须考虑的。例如,在EC2,多个可用性区域是否被认为组成了单一的数据中心?我们定义数据中心是在同一个网络环境中——私有的,低延迟,高带宽。这不包括基于公共互联网环境,但是对于我们而言,在同一个EC2的多个可用性区域会被认为是一个的数据中心。

关于client和server我搞了好久才搞明白,实际上client不存储数据,发送到client的请求,client都会转发给它绑定的server,也就是说client必须绑定server。server会存储数据,如果只有一个server并在上面注册了一个服务,这个server挂了然后你又重启了,那么这个服务的注册信息仍然保存在server上。

如果你在一台服务器上运行了一个server,它会默认有一个client绑定到server上,并且地址是127.0.0.1

consul安装

consul下载地址:https://www.consul.io/downloads.html

我用的win10 系统,所以下载的最后一个windows64位的,下载下来有个exe文件,随便放个到一个文件夹下就可以了。

进入cmd,转到consul的存放目录,打命令就可以了。

或者可以把consul的目录路径加入到Path环境变量中,就不用每次到目录下打命令了

启动consul

上面说过,consul可以以client和server的方式启动

Server:consul agent -server -bootstrap-expect 1 -data-dir=C:consul -node=n1 -bind=192.168.3.233 -ui-dir=C:consuldist -client=0.0.0.0

Client:consul agent -bootstrap-expect 1 -data-dir=C:consul -node=n1 -bind=192.168.3.233 -ui-dir=C:consuldist

-server去掉就是client模式了

consul agent:启动consul的命令,要么是server要么是client-bootstrap-expect:期望的server节点数目,如果集群中的server节点小于这个数据,集群则失效,并且该server也失效,一直等到集群中的数目达到相应的数量才生效,如果是1的话,代表一个server就可以了-data-dir:data存放的目录,server会保存一些配置缓存等信息,存在此目录下-node:该节点的名称,急群众名称必须唯一-client:代表该server对外暴漏的client地址,0.0.0.0代表我可以通过:127.0.0.1和192.168.3.233访问,不设置的话默认是:127.0.0.1-bind:这是设置集群中server之间互相通信的地址,必须可以互相访问到-ui-dir:设置webui的界面,理论上通过命令可以查看到我们需要的任何信息,但是通过ui来查看更直观

搭建集群

我开启了两台虚拟机和本机一共是三台机器,所以我搭建了三个server节点

Ser1:consul agent -server -bootstrap-expect=3 -data-dir=C:consul -node=node1 -bind=192.168.3.233 -client=0.0.0.0

Ser2:consul agent -server -bootstrap-expect=3 -data-dir=C:consul -node=node2 -join=192.168.3.233 -bind=192.168.3.201 -client=0.0.0.0

Ser3: consul agent -server -bootstrap-expect=3 -data-dir=C:consul -node=node3 -join=192.168.3.233 -bind=192.168.3.243 -client=0.0.0.0

-join:表示加入到哪个集群内,ser2中我们指定加入到了ser1中,这时候ser1和ser2组成了集群,ser3我们可以指定加入到ser1和ser2,不管加入哪个最终这三个server都组成了一个集群,最终三个server商量了一下选出了一个leader

服务注册

可以通过命令来注册服务,因为最终是要在.net core上使用,所以我就直接贴上.net core中的相关代码

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifeTime) { string ip = Configuration["ip"]; string port = Configuration["port"]; string serviceName = "MsgService"; string serviceId = serviceName + Guid.NewGuid(); Action<ConsulClientConfiguration> ConsulConfig = (config) => { config.Address = new Uri("http://192.168.3.201:8500"); //服务注册的地址,集群中任意一个地址 config.Datacenter = "dc1"; }; using (var consulClient = new ConsulClient(ConsulConfig)) { AgentServiceRegistration asr = new AgentServiceRegistration { Address = ip, Port = Convert.ToInt32(port), ID = serviceId, Name = serviceName, Check = new AgentServiceCheck { DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), HTTP = $"http://{ip}:{port}/api/Health",//健康检查访问的地址 Interval = TimeSpan.FromSeconds(10), //健康检查的间隔时间 Timeout = TimeSpan.FromSeconds(5), //多久代表超时 }, }; consulClient.Agent.ServiceRegister(asr).Wait(); } //注销Consul appLifeTime.ApplicationStopped.Register(() => { using (var consulClient = new ConsulClient(ConsulConfig)) { consulClient.Agent.ServiceDeregister(serviceId).Wait(); //从consul集群中移除服务 } }); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseHsts(); } app.UseHttpsRedirection(); app.UseMvc(); }

运行程序后向consul集群注册了一个服务,访问集群的任何一个ip都可取到该服务的ip。客户端查询服务的代码如下:

static void Main(string[] args) { using (var consul = new Consul.ConsulClient(c => { c.Address = new Uri("http://192.168.3.233:8500"); //Consul地址 })) { var services = consul.Catalog.Service("MsgService").Result.Response; foreach (var s1 in services) { Console.WriteLine($"ID={s1.ServiceID},Service={s1.ServiceName},Addr={s1.Address},Port={s1.ServicePort}"); } } }

这样我们一个基本的consul集群就可以正常使用了

对于consul和服务发现目前还只是刚刚开始接触。还是有很多问题暂时没有搞明白。

比如客户端连接的server突然挂了怎么办如何切换到另一个server?以及一个服务下线了如何通知客户端删除缓存等等。还请大家不吝赐教

, 1, 0, 9);