博客
关于我
3. .NET5微服务添加Consul中间件
阅读量:492 次
发布时间:2019-03-07

本文共 7460 字,大约阅读时间需要 24 分钟。

什么是Consul

在上一篇文章中引入了
Ocelot,客户端的调用变得简单的,但是对于网关层来说,每新增一个接口,或者服务实例,我都需要把网关在重新更新发布,这样无疑增加了网关层的负担,如果说我能自动识别服务实例,并且不需要把每个接口都写一遍,那我的网关岂不是只需要更新一次就好,不管你服务实例怎么增加,接口怎么增加,我都能自动识别。

Consul就可以自动做到服务的注册与发现,那怎么注册发现呢,其实Consul是一个单独的进程,启动Consul之后,在服务里向Consul去注册,意思就是告诉Consul,我是用户服务实例1,我的地址是 localhost:5050,我启动了,你把我加入到你的名单中,然后Consul就把用户服务实例1加入名单中了。接着用户实例2,用户实例3都加入到Consul的名单中了。

这时候,网关就不直接去调用服务实例了,网关还不知道有哪些服务实例呢,它需要先去问Consul,我想要用户服务实例,你把你所有的用户服务实例地址都给我,然后Consullocalhost:5051localhost:5052localhost:5053,等地址都给了网关,然后网关在按照一定的策略,比如轮询,随机等算法去获取对应的服务实例地址,然后再去请求。

在这里插入图片描述

所以Consul做的事情很简单,就是管理各个服务实例的地址,当网关或者谁要地址了,就通过名字把当前名字下服务实例地址全部返回。

Consul除了可以做服务的发现,还可以做服务的移除,关键字是健康检查,或者说心跳检查,当服务实例注册到Consul时,会同时提供一个健康检查地址,Consul就可以按照用户设定的时间,比如说每5秒向健康检查地址发送一个请求,若你能正常响应了,我就认为你还活着,若没响应,或者没按规定时间内响应,Consul会认为服务已经挂掉了,就把这个服务实例从当前的服务名称下进行移除,下次网关再要地址了,Consul不会把已经挂掉的地址在返回了。

Consul的安装与启动

Consul的官网地址地址: https://www.consul.io

下载好之后就是一个Consul.exe文件,这是Windows环境下的,其他环境请自行查找资料。

在这里插入图片描述
然后把当前Consul.exe上一级文件夹地址加入到环境变量中,这样不用每次都进入到这个文件夹去启动了。
在这里插入图片描述
启动Consul,打开Terminal,输入

consul.exe agent -dev

若能出现Consul agent running,说明Consul 启动成功了。

在这里插入图片描述
这时可以打开浏览器,端口号默认8500,若能出现网页,说明Consul 正常了。
在这里插入图片描述

代码实战

服务实例

Consul已经准备好了,那接下来就应该把服务注册到Consul中了,由于多个服务都需要注册,所以单独把注册到Consul的代码封装为一个类库,其他项目去引用即可。新建类库,ConsulBuilder,然后添加两个文件。

添加Consul 的nuget包

ConsulRegistrationExtensions.cs

using System;using Microsoft.AspNetCore.Builder;using Microsoft.Extensions.Configuration;using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Hosting;using Microsoft.Extensions.Options;using Consul;using ConsulBuilder;namespace ConsulBuilder{       public static class ConsulRegistrationExtensions    {           public static IApplicationBuilder AddConsul(this IApplicationBuilder app, ConsulServiceOptions consulServiceOptions)        {               var consulClient = new ConsulClient(x =>            {                   // consul服务地址,默认安装consul后端口为8500                x.Address = new Uri(consulServiceOptions.ConsulAddress);            });            var registration = new AgentServiceRegistration()            {                   ID = Guid.NewGuid().ToString(),                Name = consulServiceOptions.ServiceName,// 服务名                Address = consulServiceOptions.ServiceIP, // 服务绑定IP(也就是你这个项目运行的ip地址)                Port = consulServiceOptions.ServicePort, // 服务绑定端口(也就是你这个项目运行的端口)                Check = new AgentServiceCheck()                {                       DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5),//服务启动多久后注册                    Interval = TimeSpan.FromSeconds(10),//健康检查时间间隔                    HTTP = consulServiceOptions.ServiceHealthCheck,//健康检查地址                    Timeout = TimeSpan.FromSeconds(5)                }            };            // 服务注册            consulClient.Agent.ServiceRegister(registration).Wait();            return app;        }    }}

ConsulServiceOptions.cs

namespace ConsulBuilder{       // Consul配置模型类    public class ConsulServiceOptions    {           ///         /// 服务名称        ///         public string ServiceName {    get; set; }        ///         /// 服务IP        ///         public string ServiceIP {    get; set; }        ///         /// 服务端口        ///         public int ServicePort {    get; set; }        ///         /// 服务健康检查地址        ///         public string ServiceHealthCheck {    get; set; }        ///         /// Consul 地址        ///         public string ConsulAddress {    get; set; }    }}

接下来,我们以用户服务举例,首先引用ConsulBuilder类库,接着修改Startup.cs文件的Configure方法。

//获取关于Consul的配置节点            var consulSection = Configuration.GetSection("Consul");            var consulOption = new ConsulServiceOptions            {                   ServiceName = consulSection["ServiceName"],                ServiceIP = consulSection["ServiceIP"],                ServicePort = Convert.ToInt32(consulSection["ServicePort"]),                ServiceHealthCheck = consulSection["ServiceHealthCheck"],                ConsulAddress = consulSection["ConsulAddress"]            };            //注册consul服务            app.AddConsul(consulOption);

修改appsetting.json

//Consul的配置  "Consul": {       "ServiceName": "UserService",    "ServiceIP": "localhost",    "ServicePort": 5050,    "ServiceHealthCheck": "https://localhost:5050/api/HealthCheck",    "ConsulAddress": "http://127.0.0.1:8500"  },

OK ,这样我们的服务在启动时就会自动注册到Consul了.

至于HealthCheck,代码如下,其实是直接返回了Ok(),即可。

using Microsoft.AspNetCore.Mvc;using System;using System.Collections.Generic;using System.Linq;using System.Threading.Tasks;namespace EasyShop.UserService.Controllers{       [Route("api/[controller]")]    [ApiController]    public class HealthCheckController:ControllerBase    {           ///         /// 健康检查地址        ///         /// 
public IActionResult HealthCheck() { return Ok(); } }}

其他服务的配置过程一样,不在赘述,

网关

若服务实例可以正常被Consul发现,接下来就需要修改网关下的Ocelot.json文件,由Consul提供服务实例地址,而不是直接在json文件中配置。

添加nuget包。

Ocelot.json 修改后如下。

{     // 转发路由,数组中的每个元素都是某个服务的一组路由转发规则  "Routes": [    {         "ServiceName": "UserService", //对应consul配置的ServiceName      // Uri方案,http、https      "DownstreamScheme": "https",      // 下游(服务提供方)服务路由模板      "DownstreamPathTemplate": "/api/user/{path}",      // 上游(客户端,服务消费方)请求路由模板      "UpstreamPathTemplate": "/user/{path}",      "UpstreamHttpMethod": [ "Get", "Post" ],      "LoadBalancerOptions": {           "Type": "RoundRobin" //轮询           },      "UseServiceDiscovery": true,      "RateLimitOptions": {           "ClientWhitelist": [ "admin" ], // 白名单        "EnableRateLimiting": true, // 是否启用限流        "Period": "1s", // 统计时间段:1s, 5m, 1h, 1d        "PeriodTimespan": 15, // 多少秒之后客户端可以重试        "Limit": 2 // 在统计时间段内允许的最大请求数量      },      "QoSOptions": {           "ExceptionsAllowedBeforeBreaking": 2, // 允许多少个异常请求        "DurationOfBreak": 15000, // 熔断的时间,单位为毫秒        "TimeoutValue": 5000 // 如果下游请求的处理时间超过多少则视如该请求超时      },      "FileCacheOptions": {    // cache response data - ttl: 10s   10秒内相同url请求直接返回缓存数据        "TtlSeconds": 10,        "Region": ""      }      //,身份认证      //"AuthenticationOptions": {         //  "AuthenticationProviderKey": "ApiGatewayKey",      //  "AllowedScopes": [ "UserService" ]      //}    }  ],  "GlobalConfiguration": {       "BaseUrl": "https://localhost:44335",    "ReRouteIsCaseSensitive": false,    "ServiceDiscoveryProvider": {         "Host": "localhost",      "Port": 8500,      "Type": "Consul" //由Consul提供服务发现    },    "RateLimitOptions": {         "DisableRateLimitHeaders": false, // Http头  X-Rate-Limit 和 Retry-After 是否禁用      "QuotaExceededMessage": "Too many requests, are you OK?", // 当请求过载被截断时返回的消息      "HttpStatusCode": 999, // 当请求过载被截断时返回的http status      "ClientIdHeader": "client_id" // 用来识别客户端的请求头,默认是 ClientId    }  }}

Routes是一个数组,可以配置多个服务实例。在配置里我们可以看到有这么一个配置。"UseServiceDiscovery": true ,这就表示采用服务发现的地址。而在GlobalConfiguration里,配置了Consul的地址。

Startup.cs 修改如下

public void ConfigureServices(IServiceCollection services)        {               //允许跨域请求            services.AddCors(options =>            {                   //this defines a CORS policy called "default"                options.AddPolicy("default", policy =>                {                       policy.WithOrigins("http://localhost:8088")                        .AllowAnyHeader()                        .AllowAnyMethod();                });            });            services.AddOcelot(Configuration).AddConsul().AddPolly();        }

和之前的区别在于,之前只引入了 Ocelot,而这次还引入了ConsulPollyConfigure配置不变。

项目地址:https://gitee.com/limeng66/easy-shop

转载地址:http://xppcz.baihongyu.com/

你可能感兴趣的文章
Mysql下载以及安装(新手入门,超详细)
查看>>
MySQL不会性能调优?看看这份清华架构师编写的MySQL性能优化手册吧
查看>>
MySQL不同字符集及排序规则详解:业务场景下的最佳选
查看>>
Mysql不同官方版本对比
查看>>
MySQL与Informix数据库中的同义表创建:深入解析与比较
查看>>
mysql与mem_细说 MySQL 之 MEM_ROOT
查看>>
MySQL与Oracle的数据迁移注意事项,另附转换工具链接
查看>>
mysql丢失更新问题
查看>>
MySQL两千万数据优化&迁移
查看>>
MySql中 delimiter 详解
查看>>
MYSQL中 find_in_set() 函数用法详解
查看>>