互联网热潮下,“微服务”技术架构已经成为一项高端技术。顾名思义,它将传统的大型企业服务拆分为独立的小型服务。当拆分服务的数量逐渐增多时,我们会发现服务地址很难管理。传统方法通常通过配置文件或数据库来存储它们。这种手动维护方式显然不够灵活。如果某个服务出现故障,系统不会及时通知,只能等待维护。人员加工。这时候如果有一个中间件来进行服务发现,显然会非常灵活。
在.Net平台上使用“微服务”进行服务发现时,Cosul目前是一个不错的选择。
什么是领事
Consul是一个服务网格解决方案,提供服务发现、配置管理等功能。它是一个分布式、高可用的服务管理架构。
主要功能:
服务发现:Consul通过DNS或HTTPAPI接口提供服务。服务通过Consul中心统一获取调用服务的地址,而不是传统模式下服务间调用的“硬编码”配置管理。
服务注册:Consul提供了两种注册服务的方式。第一个是在服务启动时通过HttpAPI注册的,第二个是通过json配置文件注册的。
健康检查:服务一旦注册到Consul的客户端节点下,Consul就会按照服务注册时配置的时间间隔主动请求服务,获取服务的健康状态。如果发现不健康的服务,该服务将从consul中注销。
Key/Value存储:应用程序可以根据自己的需要使用Consul提供的Key/Value存储。Consul提供了简单易用的HTTP接口,可以与其他工具结合实现动态配置、特征标记、leader选举等功能。
一张简单的图来理解Consul
客户端节点
client代表consul的客户端模式,即客户端模式。
1)客户端节点负责将请求转发给服务器节点,不保存任何信息。
2)提供服务健康检查
3)客户端节点支持任意扩展,数量不限。
服务器节点
Server代表consul的服务器模式,即服务器模式。
1)服务器节点接收客户端的转发请求,并将信息持久化到本地,以便出现故障时方便排查。
2)consul集群中至少有一台服务器。官方建议服务器节点数量为3个或5个。服务器集群解决了单点问题。服务器需要选举一个账本,服务器账本负责服务器集群之间的信息同步。
3)采用Raft一致性协议,保证服务器节点之间数据的一致性
consul节点之间的通信
Consul使用GossIP协议来管理成员关系并向整个集群广播消息,包括两个gossip池。LAN池用于同一数据中心内部通信,WAN池用于多个数据中心之间的通信。有多个LAN池,只有1个WAN池。
从上图我们会发现consul建议以集群的形式部署。不过很多人刚接触学习的时候,并没有那么多机器模拟。服务器单节点模式可行吗?
答案当然是可行的,但弊端也很明显。首先,肯定会存在单点故障。其次,如果注册的服务过多,服务器需要不断向服务发送请求并进行健康检查。显然,大量的高频请求会对consul节点造成很大的影响。
如果只有一个服务器节点,那么它实际上既充当客户端又充当服务器。在本文中,我们将使用服务器单节点模式和最简单的应用来学习如何在.netcore中使用consul。
准备environment.netcore3.1、consul部署包
首先下载consul,官方地址:
解压后我们会发现它是一个exe程序,掌握一些常用的cmd命令即可。
本地环境consul启动CMD命令:
首先cd到consul.exe所在目录
然后输入consulagent-server-bootstrap-expect=1-node=service1-bind=127.0.0.1-data-dir=./data-client=0.0.0.0-ui-config-dir=./config
常用参数说明:
-server:表示consul代理模式,有两个选项-server和-client
-bootstrap-expect:数据中心期望提供的服务器节点数量。直到指定数量的服务器全部启动后集群才会启动
-node:集群中的节点名,同一个集群中唯一,默认为主机名
-bind:绑定集群内部通信的地址,表示节点监听的地址。该地址必须可供集群中的所有节点访问。默认是0.0.0.0
-client:绑定客户端的IP地址,默认为127.0.0.1,可以绑定多个。0.0.0.0表示任何人都可以访问它。
-data-dir:用于存储Agent状态的目录
-ui:启用网络用户界面
-config-dir:配置目录,会加载该目录下的.hcl或.json格式的配置。注意,子路径不会被加载
启动consul后,我们可以通过访问consuld的UI页面
使用HTTP方法注册.netcore服务
创建一个新的API项目
Nuget添加consul依赖包
添加Consul参数配置
{'ConsulConfig':{'ServiceName':'WebApi1','ServiceIP':'localhost','ServicePort':6000,'HealthCheck':'/healthcheck','ConsulAddress':''}}
登记服务
publicvoidConfigure(IApplicationBuilderapp,IWebHostEnvironmentenv){if(env.IsDevelopment()){app.UseDeveloperExceptionPage();}app.UseRouting();//添加consul服务注册app.UseConsul();app.UseEndpoints(endpoints={endpoints.MapControllers();});}
Consul服务注册具体实现逻辑
publicstaticclassConsulExtensions{publicstaticIApplicationBuilderUseConsul(thisIApplicationBuilderapp){//获取consul配置实例varconsulConfig=app.ApplicationServices.GetRequiredServiceIOptionsConsulOptions().Value;//获取应用程序生命周期事件varlifetime=app.ApplicationServices.GetRequiredServiceIHostApplicationLifetime();varconsulClient=newConsulClient(c={//consul服务注册地址c.Address=newUri(consulConfig.ConsulAddress);});//服务注册配置varregistration=newAgentServiceRegistration(){ID=Guid.NewGuid().ToString(),Name=consulConfig.ServiceName,//服务名称Address=consulConfig.ServiceIP,//服务IPPort=consulConfig.ServicePort,//ServiceportCheck=newAgentServiceCheck(){DeregisterCriticalServiceAfter=TimeSpan.FromSeconds(5),//服务启动后多长时间注册服务Interval=TimeSpan.FromSeconds(10),//健康检查时间间隔HTTP=$'',//健康检查地址Timeout=TimeSpan.FromSeconds(5)//超时}};//服务注册consulClient.Agent.ServiceRegister(registration).Wait();//应用程序生命周期结束时取消注册.ApplicationStopping.Register(()={consulClient.Agent.ServiceDeregister(registration.ID).Wait();});返回应用程序;}}
1)使用IOptions管理配置类ConsulOptions,并将配置文件中的配置反序列化为配置类的实例
2)AgentServiceRegistration代理服务注册类,实例化注册服务配置。
健康检查接口
[Route('[controller]')][ApiController]publicclassHealthCheckController:ControllerBase{///summary///健康检查接口////summary///returns/returns[HttpGet]publicIActionResultGet()=Ok();}
consul节点会按照配置的时间间隔定期请求健康检查接口,获取服务健康状态。
服务启动
查看consulUI页面我们会发现显示了我们注册的服务WebApi1的信息
那么如何实现服务发现呢?
正常情况下,如果服务B调用服务A,需要在服务B中进行配置,指向服务A的地址,也就是上面提到的“硬编码”配置方式。在这种模式下,如果部署了多个服务A,那么需要管理多个地址,而服务B本身无法知道某个服务A宕机而放弃请求。
Consul为我们提供了便利。现在服务B不需要关心服务A的具体服务地址以及服务A是否健康。服务B直接请求consul服务地址,告诉它我要访问服务A,Consul会启动服务发现机制,找到所有已注册且健康的服务A,然后选择其中一个返回给服务B,然后服务B会根据服务A发起请求的具体地址返回给服务B。Consul帮助我们管理服务地址和服务健康检查。
接下来我们来模拟consul的服务发现。
服务发现
创建一个新的API项目
Nuget添加consul依赖包
模拟服务发现
[HttpGet][Route('/consul')]publicvoidReuestConsul(){//获取Consul配置地址varconsulAddress=_configuration['ConsulAddress']?ToString();using(varconsulClient=newConsulClient(x=x.Address=newUri(consulAddress))){//根据服务获取服务注册名webApi1。获取consul注册的服务varservices=consulClient.Catalog.Service('WebApi1').Result.Response;if(services!=nullservices.Any()){//模拟随机机器发出请求。这只是一个测试。您可以选择合适的负载均衡框架。随机r=newRandom();intindex=r.Next(services.Count());varservice=services.ElementAt(index);using(HttpClientclient=newHttpClient()){//请求服务WebApi1varresponse=client.GetAsync($'').Result;字符串结果=response.Content.ReadAsStringAsync()。结果;}}}}
1)ConsulClient实例化consul服务节点
2)
consulClient.Catalog.Service("服务名称").Result.Response根据服务名称获取conusl注册的所有服务地址信息。
好了,本文主要采用服务器单节点模式,给大家介绍consul的特点,并使用.netcore来注册服务,模拟服务发现。
我相信,用自己的双手去尝试,就会有所思考,有所收获。