我的第一个微服务系列(四):使用Consul来做服务注册与发现

  Consul是一种提供具有服务发现,配置和分段功能的全功能控制平面的服务网格解决方案,其主要功能有:

  1. 服务发现:Consul的客户端可以注册服务,例如api或mysql,其他客户端可以使用Consul来发现给定服务的提供者。使用DNS或HTTP,应用程序可以轻松找到它们所依赖的服务。
  2. 健康监测:Consul客户端可以提供与给定服务相关的任意数量的健康检查,可以使用此信息来监控集群运行状况,服务发现组件使用该信息将流量路由远离不健康的主机。
  3. 键值存储:应用程序可以将Consul的分层键/值存储用于任何目的,包括动态配置,功能标记,协调,领导者选举等。简单的HTTP API使其易于使用。
  4. Secure Service Communication: Consul可以为服务生成和分发TLS证书,以建立相互的TLS连接。意图可用于定义允许哪些服务进行通信。可以使用可以实时更改的意图轻松管理服务分段,而不是使用复杂的网络拓扑和静态防火墙规则。
  5. 多数据中心: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来建立映射。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Threading.Tasks;

namespace User.API.Dtos
{
    public class DnsEndpoint
    {
        public string Address { get; set; }

        public int Port { get; set; }

        public IPEndPoint ToIPEndPoint()
        {
            return new IPEndPoint(IPAddress.Parse(Address), Port);
        }
    }
}
namespace User.API.Dtos
{
    public class ConsulOptions
    {
        public string HttpEndpoint { get; set; }

        public DnsEndpoint DnsEndpoint { get; set; }
    }
}
namespace User.API.Dtos
{
    public class ServiceDiscoveryOptions
    {
        public string ServiceName { get; set; }

        public ConsulOptions Consul { get; set; }
    }
}

  接着在Startup.cs中添加注入

services.AddOptions();
services.Configure<ServiceDiscoveryOptions>(Configuration.GetSection("ServiceDiscovery"));
services.AddSingleton<IConsulClient>(p => new ConsulClient(cfg =>
{
     var serviceConfiguration = p.GetRequiredService<IOptions<ServiceDiscoveryOptions>>().Value;

     if (!string.IsNullOrEmpty(serviceConfiguration.Consul.HttpEndpoint))
     {
          // if not configured, the client will use the default value "127.0.0.1:8500"
          cfg.Address = new Uri(serviceConfiguration.Consul.HttpEndpoint);
     }
}));

  最后就是在User.Api启动时将其注册到Consul中,停止时删除注册了,代码如下

        public void Configure(IApplicationBuilder app
            ,IHostingEnvironment env
            ,IApplicationLifetime applicationLifetime
            ,ILoggerFactory loggerFactory
            ,IOptions<ServiceDiscoveryOptions> serviceOptions
            ,IConsulClient consul)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }//启动时向consul注册服务
            applicationLifetime.ApplicationStarted.Register(()=> {
                RegisterService(app, serviceOptions, consul, applicationLifetime);
            });

            app.UseMvc();
        }

        /// <summary>
        /// 注册服务
        /// </summary>
        /// <param name="app"></param>
        /// <param name="serviceOptions"></param>
        /// <param name="consul"></param>
        /// <param name="applicationLifetime"></param>
        private void RegisterService(IApplicationBuilder app,
            IOptions<ServiceDiscoveryOptions> serviceOptions,
            IConsulClient consul,
            IApplicationLifetime applicationLifetime)
        {
            var features = app.Properties["server.Features"] as FeatureCollection;
            var addresses = features.Get<IServerAddressesFeature>()
                .Addresses
                .Select(p => new Uri(p));

            foreach (var address in addresses)
            {
                var serviceId = $"{serviceOptions.Value.ServiceName}_{address.Host}:{address.Port}";

                var httpCheck = new AgentServiceCheck()
                {
                    DeregisterCriticalServiceAfter = TimeSpan.FromMinutes(1),
                    Interval = TimeSpan.FromSeconds(30),
                    HTTP = new Uri(address, "HealthCheck").OriginalString
                };

                var registration = new AgentServiceRegistration()
                {
                    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);
                });
            }
        }

        /// <summary>
        /// 清除服务
        /// </summary>
        /// <param name="consul"></param>
        /// <param name="serviceId"></param>
        private void DeRegisterService(IConsulClient consul,string serviceId)
        {
            consul.Agent.ServiceDeregister(serviceId).GetAwaiter().GetResult();
        }

  为了consul可以监控user.api的运行情况,在User.Api中创建一个controller

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;

namespace User.API.Controllers
{
    [Route("[Controller]")]
    public class HealthCheckController : Controller
    {
        [HttpGet("")]
        [HttpHead("")]
        public void Get()
        {
            
        }
    }
}

  到这里,User.Api注册成功了,接下来就是要在User.Identity中调用User.Api了,我们将用到Polly做熔断重试,下篇再讲。

 

 

 

  

  

 

 

 

 

 

 

 

 

 

 

 

 

  

posted @ 2020-12-07 22:49  柠檬笔记  阅读(292)  评论(0)    收藏  举报