【NET CORE微服務一條龍應用】第一章 閘道器使用與配置

船頭尺發表於2021-09-09

簡介

  微服務的系統應用中,閘道器係統使用的是ocelot,ocelot目前已經比較成熟了

  ocelot就不做介紹了,等整體介紹完後再進行各類擴充套件介紹,ocelot原始碼地址:

  ocelot目前由很多功能元件組成,每個元件都可以根據自己的實際情況進行擴充套件(暫時不做過多介紹)

  本文主要介紹ocelot閘道器使用中個人認為應該最先處理的東西

健康檢查

  在實際的應用中閘道器專案都會部署多臺,然後透過nginx進行軟負載,在更新部署閘道器專案的過程中服務肯定是無法使用,這個時候我們就需要利用nginx的健康檢查機制進行控制

  閘道器需要給nginx提供一個健康檢查地址,ocelot使用的url path地址進行路由匹配,當匹配不到時會返回404,所以我們需要單獨處理一個健康檢查地址

  Ocelot提供了一箇中介軟體配置替換的方法OcelotPipelineConfiguration,我們對OcelotPipelineConfiguration的PreErrorResponderMiddleware中介軟體方法進行擴充套件,程式碼如下:

圖片描述

 1 var conf = new OcelotPipelineConfiguration() 2 { 3       PreErrorResponderMiddleware = async (ctx, next) => 4       { 5             if (ctx.HttpContext.Request.Path.Equals(new PathString("/"))) 6             { 7                     await ctx.HttpContext.Response.WriteAsync("ok"); 8             } 9             else10             {11                     await next.Invoke();12             }13      }14 };15 app.UseOcelot(conf).Wait();

圖片描述

閘道器和路由配置

  閘道器的配置包含四個部分,ReRoutes、DynamicReRoutes、Aggregates、GlobalConfiguration,

  ocelot配置的獲取預設是使用配置檔案的方式,上面已經說了閘道器一般都會部署多臺,使用檔案配置還是存在一定弊端

  ocelot的配置獲取方法是IFileConfigurationRepository介面,所以如果我們實現了此介面就可以滿足配置儲存方式的擴充套件,目前已擴充套件mysql和redis,程式碼如下

  redis:

圖片描述

 1 public class RedisFileConfigurationRepository: IFileConfigurationRepository 2     { 3         private readonly RedisClient _redisClient; 4         private readonly string _apiGatewayKey; 5         private readonly string _redisConnection; 6  7         public RedisFileConfigurationRepository(RedisClient redisClient, string apiGatewayKey, string redisConnection) 8         { 9             _redisClient = redisClient;10             _apiGatewayKey = apiGatewayKey;11             _redisConnection = redisConnection;12         }13 14         public async Task<Response<FileConfiguration>> Get()15         {16             var redis = _redisClient.GetDatabase(_redisConnection, 11);17 18             var json = await redis.StringGetAsync($"ApiGatewayConfig:{_apiGatewayKey}");19 20             if(json.IsNullOrEmpty)21                 return new OkResponse<FileConfiguration>(new FileConfiguration { });22 23             var fileConfig = JsonConvert.DeserializeObject<FileConfiguration>(json);24 25             return new OkResponse<FileConfiguration>(fileConfig);26         }27 28         public async Task<Response> Set(FileConfiguration fileConfiguration)29         {30             return await Task.FromResult(new OkResponse());31         }32     }

圖片描述

mysql:

圖片描述

  1 public class MySqlFileConfigurationRepository : IFileConfigurationRepository  2     {  3         private readonly IDbRepository<ConfigurationInfo> _configDbRepository;  4         private readonly IDbRepository<ReRouteInfo> _routeDbRepository;  5         private readonly string _apiGatewayKey;  6   7         public MySqlFileConfigurationRepository(IDbRepository<ConfigurationInfo> configDbRepository, IDbRepository<ReRouteInfo> routeDbRepository, string apiGatewayKey)  8         {  9             _configDbRepository = configDbRepository; 10             _routeDbRepository = routeDbRepository; 11             _apiGatewayKey = apiGatewayKey; 12         } 13  14         public async Task<Response<FileConfiguration>> Get() 15         { 16             var st = DateTime.Now; 17             var fileConfig = new FileConfiguration(); 18             var configInfo = await _configDbRepository.GetFirstAsync(it => it.GatewayKey == _apiGatewayKey); 19             if (configInfo != null) 20             { 21                 // config 22                 var fgc = new FileGlobalConfiguration 23                 { 24                     BaseUrl = configInfo.BaseUrl, 25                     DownstreamScheme = configInfo.DownstreamScheme, 26                     RequestIdKey = configInfo.RequestIdKey, 27                 }; 28                 if (!string.IsNullOrWhiteSpace(configInfo.HttpHandlerOptions)) 29                     fgc.HttpHandlerOptions = ToObject<FileHttpHandlerOptions>(configInfo.HttpHandlerOptions); 30                 if (!string.IsNullOrWhiteSpace(configInfo.LoadBalancerOptions)) 31                     fgc.LoadBalancerOptions = ToObject<FileLoadBalancerOptions>(configInfo.LoadBalancerOptions); 32                 if (!string.IsNullOrWhiteSpace(configInfo.QoSOptions)) 33                     fgc.QoSOptions = ToObject<FileQoSOptions>(configInfo.QoSOptions); 34                 if (!string.IsNullOrWhiteSpace(configInfo.RateLimitOptions)) 35                     fgc.RateLimitOptions = ToObject<FileRateLimitOptions>(configInfo.RateLimitOptions); 36                 if (!string.IsNullOrWhiteSpace(configInfo.ServiceDiscoveryProvider)) 37                     fgc.ServiceDiscoveryProvider = ToObject<FileServiceDiscoveryProvider>(configInfo.ServiceDiscoveryProvider); 38                 fileConfig.GlobalConfiguration = fgc; 39  40                 // reroutes 41                 var reRouteResult = await _routeDbRepository.GetListAsync(it => it.GatewayId == configInfo.GatewayId && it.State == 1); 42                 if (reRouteResult.Count > 0) 43                 { 44                     var reroutelist = new List<FileReRoute>(); 45                     foreach (var model in reRouteResult) 46                     { 47                         var m = new FileReRoute() 48                         { 49                             UpstreamHost = model.UpstreamHost, 50                             UpstreamPathTemplate = model.UpstreamPathTemplate, 51  52                             DownstreamPathTemplate = model.DownstreamPathTemplate, 53                             DownstreamScheme = model.DownstreamScheme, 54  55                             ServiceName = model.ServiceName, 56                             Priority = model.Priority, 57                             RequestIdKey = model.RequestIdKey, 58                             Key = model.Key, 59                             Timeout = model.Timeout, 60                         }; 61                         if (!string.IsNullOrWhiteSpace(model.UpstreamHttpMethod)) 62                             m.UpstreamHttpMethod = ToObject<List<string>>(model.UpstreamHttpMethod); 63                         if (!string.IsNullOrWhiteSpace(model.DownstreamHostAndPorts)) 64                             m.DownstreamHostAndPorts = ToObject<List<FileHostAndPort>>(model.DownstreamHostAndPorts); 65                         if (!string.IsNullOrWhiteSpace(model.SecurityOptions)) 66                             m.SecurityOptions = ToObject<FileSecurityOptions>(model.SecurityOptions); 67                         if (!string.IsNullOrWhiteSpace(model.CacheOptions)) 68                             m.FileCacheOptions = ToObject<FileCacheOptions>(model.CacheOptions); 69                         if (!string.IsNullOrWhiteSpace(model.HttpHandlerOptions)) 70                             m.HttpHandlerOptions = ToObject<FileHttpHandlerOptions>(model.HttpHandlerOptions); 71                         if (!string.IsNullOrWhiteSpace(model.AuthenticationOptions)) 72                             m.AuthenticationOptions = ToObject<FileAuthenticationOptions>(model.AuthenticationOptions); 73                         if (!string.IsNullOrWhiteSpace(model.RateLimitOptions)) 74                             m.RateLimitOptions = ToObject<FileRateLimitRule>(model.RateLimitOptions); 75                         if (!string.IsNullOrWhiteSpace(model.LoadBalancerOptions)) 76                             m.LoadBalancerOptions = ToObject<FileLoadBalancerOptions>(model.LoadBalancerOptions); 77                         if (!string.IsNullOrWhiteSpace(model.QoSOptions)) 78                             m.QoSOptions = ToObject<FileQoSOptions>(model.QoSOptions); 79                         if (!string.IsNullOrWhiteSpace(model.DelegatingHandlers)) 80                             m.DelegatingHandlers = ToObject<List<string>>(model.DelegatingHandlers); 81                         reroutelist.Add(m); 82                     } 83                     fileConfig.ReRoutes = reroutelist; 84                 } 85             } 86             Console.WriteLine((DateTime.Now - st).TotalMilliseconds); 87             return new OkResponse<FileConfiguration>(fileConfig); 88         } 89  90         public async Task<Response> Set(FileConfiguration fileConfiguration) 91         { 92             return await Task.FromResult(new OkResponse()); 93         } 94  95         /// <summary> 96         /// 將Json字串轉換為物件 97         /// </summary> 98         /// <param name="json">Json字串</param> 99         private T ToObject<T>(string json)100         {101             if (string.IsNullOrWhiteSpace(json))102                 return default(T);103             return JsonConvert.DeserializeObject<T>(json);104         }105     }

圖片描述

可以看到四項配置裡並不是全部都進行可配置化,如果有需求可以自行增加欄位實現

redis的儲存是大json方式,而mysql是一條一條的,因為配置的管理是以mysql為主,然後同步到其他儲存介質中的

閘道器配置的更新

 有載入就有更新,在ocelot中配置的更新是使用自己的實現來完成配置的熱更新,方式如下

 1、配置檔案方式是透過配置檔案的IOptionsMonitor的OnChange方式重新載入配置資訊

 2、第三方儲存方式是透過預設實現的FileConfigurationPoller方法定時(預設1s)取獲取配置資訊的

 所以我們擴充套件的獲取配置形式,在註冊的時候要把FileConfigurationPoller HostedService一同注入進去,程式碼如下

圖片描述

 1 public static IOcelotBuilder AddConfigStoredInRedis(this IOcelotBuilder builder, string apiGatewayKey, string redisConnectionString) 2         { 3             builder.Services.AddSingleton<RedisClient>(); 4             builder.Services.AddHostedService<FileConfigurationPoller>(); 5             builder.Services.AddSingleton<IFileConfigurationRepository>(sp => 6             { 7                 return new RedisFileConfigurationRepository(sp.GetRequiredService<RedisClient>(), apiGatewayKey, redisConnectionString); 8             }); 9             return builder;10         }

圖片描述

其中涉及到Bucket.DbContext和Bucket.Redis元件很簡單,也可自行實現

配置的管理

  其實最開始的時候,使用的是consul儲存配置,然後透過閘道器自帶的配置介面進行配置的管理,但是在ocelot的一次升級的時候出現了一個問題(配置資訊丟失),雖然當時修改了ocelot的原始碼解決了,後來還是決定擴充套件儲存方式,所以上面的獲取配置介面的set方法都不實現了

  上面已經說了是已mysql進行配置儲存然後同步到其他介質上,所以我們只要維護好mysql資料庫就可以了

  具體程式碼就不貼了,後續會進行具體介紹,管理專案地址:,截幾張管理圖

 圖片描述

圖片描述

圖片描述

原文出處:https://www.cnblogs.com/tianxiangzhe/p/10336923.html 

作者:  

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/3016/viewspace-2820883/,如需轉載,請註明出處,否則將追究法律責任。

相關文章