.net core 3.1 基于ocelot实现API网关
Ocelot是一个用.NET Core实现的开源API网关,它功能强大,包括了:路由、请求聚合、服务发现、认证、鉴权、限流熔断,缓存等。
接下来,会使用ocelot 结合consul ,polly ,cachemanager 实现负载均衡,服务发现,限流熔断和缓存功能。(本文只做记录,就直接贴完整代码,不分别测试了)
新建ApiGateWay项目,nuget安装Ocelot,Ocelot.Provider.Consul,Ocelot.Provider.Polly,Ocelot.Cache.CacheManager
注:我这里用的ocelot版本是14.1.0 ,高版本请参考官方文档调整哈
新增ocelot.json,配置相关参数
{ // 转发路由,数组中的每个元素都是某个服务的一组路由转发规则 "ReRoutes": [ { "ServiceName": "Summer.Webapi", //对应consul配置的ServiceName // Uri方案,http、https "DownstreamScheme": "http", // 下游(服务提供方)服务路由模板 "DownstreamPathTemplate": "/api/{path}", // 上游(客户端,服务消费方)请求路由模板 "UpstreamPathTemplate": "/Summer/{path}", "UpstreamHttpMethod": [ "Get", "Post" ], "LoadBalancerOptions": { "Type": "RoundRobin" //轮询 }, "UseServiceDiscovery": true, "RateLimitOptions": { "ClientWhitelist": [ "admin" ], // 白名单 "EnableRateLimiting": true, // 是否启用限流 "Period": "1m", // 统计时间段: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": "" } } ], // 全局配置,此节点的配置会覆盖ReRoutes,可以在这里设置一些通用的配置 "GlobalConfiguration": { "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 } } }
在Startup.cs 中新增如下代码:
public void ConfigureServices(IServiceCollection services) { var config = new ConfigurationBuilder().AddJsonFile("ocelot.json").Build(); services.AddOcelot(config) .AddCacheManager(x => { x.WithDictionaryHandle(); }) .AddConsul().AddPolly(); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseOcelot().Wait(); }
配置完ApiGateway,接下来配置Webapi,每个Webapi都新增服务注册,通过consul服务发现并定时做健康检测
新增consul服务注册扩展类库 ConsulBuilder,方便各个项目引用,接下来直接贴代码:
// consul服务注册扩展类 public static class ConsulRegistrationExtensions { public static void AddConsul(this IServiceCollection service) { // 读取服务配置文件 var config = new ConfigurationBuilder().AddJsonFile("consulconfig.json").Build(); service.Configure<ConsulServiceOptions>(config); } public static IApplicationBuilder UseConsul(this IApplicationBuilder app) { // 获取主机生命周期管理接口 var lifetime = app.ApplicationServices.GetRequiredService<IHostApplicationLifetime>(); // 获取服务配置项 var serviceOptions = app.ApplicationServices.GetRequiredService<IOptions<ConsulServiceOptions>>().Value; // 服务ID必须保证唯一 serviceOptions.ServiceId = Guid.NewGuid().ToString(); var consulClient = new ConsulClient(configuration => { //服务注册的地址,集群中任意一个地址 configuration.Address = new Uri(serviceOptions.ConsulAddress); }); // 获取当前服务地址和端口,配置方式 var uri = new Uri(serviceOptions.ServiceAddress); // 节点服务注册对象 var registration = new AgentServiceRegistration() { ID = serviceOptions.ServiceId, Name = serviceOptions.ServiceName,// 服务名 Address = uri.Host, Port = uri.Port, // 服务端口 Check = new AgentServiceCheck { // 注册超时 Timeout = TimeSpan.FromSeconds(5), // 服务停止多久后注销服务 DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), // 健康检查地址 HTTP = $"{uri.Scheme}://{uri.Host}:{uri.Port}{serviceOptions.HealthCheck}", // 健康检查时间间隔 Interval = TimeSpan.FromSeconds(10), } }; // 注册服务 consulClient.Agent.ServiceRegister(registration).Wait(); // 应用程序终止时,注销服务 lifetime.ApplicationStopping.Register(() => { consulClient.Agent.ServiceDeregister(serviceOptions.ServiceId).Wait(); }); return app; } }
// Consul配置模型类 public class ConsulServiceOptions { // 服务注册地址(Consul的地址) public string ConsulAddress { get; set; } // 服务ID public string ServiceId { get; set; } // 服务名称 public string ServiceName { get; set; } // 健康检查地址 public string HealthCheck { get; set; } //站点地址 public string ServiceAddress { get; set; } }
在Webapi 项目中引用ConsulBuilder类库,然后在Startup.cs 中新增如下代码:
新增consulconfig.json ,属性设置为始终复制
{ "ConsulAddress": "http://127.0.0.1:8500", //consul 服务器地址 "ServiceName": "Summer.Webapi", //服务名称,ApiGateway中配置的ServiceName对应这里 "HealthCheck": "/Health", //健康检查地址 "ServiceAddress": "http://localhost:58420" //webapi 地址 }
假如要启动多个webapi,拷贝代码,将ServiceAddress 改为不同的端口,然后使用命令行启动
PS D:\work\demo\core\SummerCore3.1\Summer.WebApi\bin\Debug\netcoreapp3.1> dotnet .\Summer.Webapi.dll --urls "http://loca
lhost:58420"
配置好后,开始运行,
先开启consul: consul.exe agent -dev
然后启动多个webapi
访问localhost:8500 ,可以看到已经服务发现两个webapi
测试一下是否正常运行,访问http://localhost:58420/api/user/userlist
运行ApiGateway
PS D:\work\demo\core\SummerCore3.1\Summer.ApiGateway\bin\Debug\netcoreapp3.1> dotnet .\Summer.ApiGateway.dll --urls "htt
p://localhost:7000"
访问http://localhost:7000/Summer/user/userlist
可以看到,API网关已经正常映射到localhost:58420的Webapi
其他效果,例如负载均衡,限流熔断可以自行结合配置参数做测试
本文代码主要参考zilor老师公开课源码