本文共 7460 字,大约阅读时间需要 24 分钟。
Ocelot
,客户端的调用变得简单的,但是对于网关层来说,每新增一个接口,或者服务实例,我都需要把网关在重新更新发布,这样无疑增加了网关层的负担,如果说我能自动识别服务实例,并且不需要把每个接口都写一遍,那我的网关岂不是只需要更新一次就好,不管你服务实例怎么增加,接口怎么增加,我都能自动识别。 Consul
就可以自动做到服务的注册与发现,那怎么注册发现呢,其实Consul
是一个单独的进程,启动Consul
之后,在服务里向Consul
去注册,意思就是告诉Consul
,我是用户服务实例1,我的地址是 localhost:5050
,我启动了,你把我加入到你的名单中,然后Consul
就把用户服务实例1加入名单中了。接着用户实例2,用户实例3都加入到Consul的名单中了。
这时候,网关就不直接去调用服务实例了,网关还不知道有哪些服务实例呢,它需要先去问Consul
,我想要用户服务实例,你把你所有的用户服务实例地址都给我,然后Consul
把 localhost:5051
,localhost:5052
,localhost:5053
,等地址都给了网关,然后网关在按照一定的策略,比如轮询,随机等算法去获取对应的服务实例地址,然后再去请求。
Consul
做的事情很简单,就是管理各个服务实例的地址,当网关或者谁要地址了,就通过名字把当前名字下服务实例地址全部返回。 Consul
除了可以做服务的发现,还可以做服务的移除,关键字是健康检查,或者说心跳检查,当服务实例注册到Consul
时,会同时提供一个健康检查地址,Consul
就可以按照用户设定的时间,比如说每5秒向健康检查地址发送一个请求,若你能正常响应了,我就认为你还活着,若没响应,或者没按规定时间内响应,Consul
会认为服务已经挂掉了,就把这个服务实例从当前的服务名称下进行移除,下次网关再要地址了,Consul
不会把已经挂掉的地址在返回了。
Consul
的官网地址地址: https://www.consul.io
下载好之后就是一个Consul.exe
文件,这是Windows环境下的,其他环境请自行查找资料。
Consul.exe
上一级文件夹地址加入到环境变量中,这样不用每次都进入到这个文件夹去启动了。 Consul
,打开Terminal,输入 consul.exe agent -dev
若能出现Consul agent running
,说明Consul
启动成功了。
Consul
正常了。 Consul
已经准备好了,那接下来就应该把服务注册到Consul
中了,由于多个服务都需要注册,所以单独把注册到Consul
的代码封装为一个类库,其他项目去引用即可。新建类库,ConsulBuilder
,然后添加两个文件。
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
,而这次还引入了Consul
和Polly
。 Configure
配置不变。
项目地址:https://gitee.com/limeng66/easy-shop
转载地址:http://xppcz.baihongyu.com/