【NET CORE微服務一條龍應用】第一章 網關使用與配置

簡介

  微服務的系統應用中,網關係統使用的是ocelot,ocelot目前已經比較成熟了mysql

  ocelot就不作介紹了,等總體介紹完後再進行各種擴展介紹,ocelot源碼地址:https://github.com/ThreeMammals/Ocelotnginx

  ocelot目前由不少功能組件組成,每一個組件均可以根據本身的實際狀況進行擴展(暫時不作過多介紹)git

  本文主要介紹ocelot網關使用中我的認爲應該最早處理的東西github

健康檢查

  在實際的應用中網關項目都會部署多臺,而後經過nginx進行軟負載,在更新部署網關項目的過程當中服務確定是沒法使用,這個時候咱們就須要利用nginx的健康檢查機制進行控制redis

  網關須要給nginx提供一個健康檢查地址,ocelot使用的url path地址進行路由匹配,當匹配不到時會返回404,因此咱們須要單獨處理一個健康檢查地址sql

  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             else
10             {
11                     await next.Invoke();
12             }
13      }
14 };
15 app.UseOcelot(conf).Wait();

網關和路由配置

  網關的配置包含四個部分,ReRoutes、DynamicReRoutes、Aggregates、GlobalConfiguration,json

  ocelot配置的獲取默認是使用配置文件的方式,上面已經說了網關通常都會部署多臺,使用文件配置仍是存在必定弊端api

  ocelot的配置獲取方法是IFileConfigurationRepository接口,因此若是咱們實現了此接口就能夠知足配置存儲方式的擴展,目前已擴展mysql和redis,代碼以下app

  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中配置的更新是使用本身的實現來完成配置的熱更新,方式以下

 一、配置文件方式是經過配置文件的IOptionsMonitor的OnChange方式從新加載配置信息

 二、第三方存儲方式是經過默認實現的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數據庫就能夠了

  具體代碼就不貼了,後續會進行具體介紹,管理項目地址:github地址,截幾張管理圖

 

相關文章
相關標籤/搜索