consul:啥?我被优化没了?AgileConfig+Yarp替代Ocelot+Consul实现服务发现和自动网关配置

  • consul:啥?我被优化没了?AgileConfig+Yarp替代Ocelot+Consul实现服务发现和自动网关配置已关闭评论
  • 89 次浏览
  • A+
所属分类:.NET技术
摘要

现在软件就业环境不景气,各行各业都忙着裁员优化。作为一个小开发,咱也不能光等着别人来优化咱,也得想办法优化下自己。就拿手头上的工作来说吧,我发现我的微服务应用里,既有AgileConfig这个日志组件,又有一个Consul 服务发现组件。本来吧他俩也没啥事,各干个的。但是,我在操作AgileConfig的时候发现了一个事
然后我又一百度发现了这个AgileConfig 1.6.0 发布 – 支持服务注册与发现 – Agile.Zhou – 博客园 (cnblogs.com),有点意思。稍微一思索,我们现在的微服务解决方案里网关用的ocelot+consul 作为HTTP api网关,同时 还是用了 yarp做 grpc的网关,明显可以看出来有一套多余的网关在这里。基于目前的情况,我是一直想优化掉 ocelot+consul这个组合。改用 agileConfig+yarp,奈何前期对微服务机制不是很熟悉,有堆坑要填。现在看到agileconfig的服务列表,又勾起了我这个优化的想法。说干就干,我理想的目标是可以直接从agileconfig上获取到所有注册的服务,然后用代码来动态给yarp添加代理配置。这样既可以优化掉一个consul服务,又可以免去每次服务部署时繁琐的网关配置。

现在软件就业环境不景气,各行各业都忙着裁员优化。作为一个小开发,咱也不能光等着别人来优化咱,也得想办法优化下自己。就拿手头上的工作来说吧,我发现我的微服务应用里,既有AgileConfig这个日志组件,又有一个Consul 服务发现组件。本来吧他俩也没啥事,各干个的。但是,我在操作AgileConfig的时候发现了一个事consul:啥?我被优化没了?AgileConfig+Yarp替代Ocelot+Consul实现服务发现和自动网关配置
然后我又一百度发现了这个AgileConfig 1.6.0 发布 - 支持服务注册与发现 - Agile.Zhou - 博客园 (cnblogs.com),有点意思。稍微一思索,我们现在的微服务解决方案里网关用的ocelot+consul 作为HTTP api网关,同时 还是用了 yarp做 grpc的网关,明显可以看出来有一套多余的网关在这里。基于目前的情况,我是一直想优化掉 ocelot+consul这个组合。改用 agileConfig+yarp,奈何前期对微服务机制不是很熟悉,有堆坑要填。现在看到agileconfig的服务列表,又勾起了我这个优化的想法。说干就干,我理想的目标是可以直接从agileconfig上获取到所有注册的服务,然后用代码来动态给yarp添加代理配置。这样既可以优化掉一个consul服务,又可以免去每次服务部署时繁琐的网关配置。

首先第一个任务就是解决yarp如何用代码实现动态配置的问题。bing 里搜索 yarp 动态配置 ,优先看博客园的博主发的文章,事实上我也就只看了这一篇Welcome to YARP - 2.2 配置功能 - 配置提供者(Configuration Providers) - coding-y - 博客园 (cnblogs.com) 。完美,问题解决。下面就是代码时间。

通过上面两篇文章我们知道,agileconfig会提供一个IDiscoveryService 接口来供程序获取注册的服务信息。同时 yarp也提供了从内存中提供配置的 InMemoryConfigProvider ,那我们只需要在agileconfig 注册之后 通过 IDisconverService接口 获取所有已注册服务,然后再让yarp应用上内存中的配置即可实现服务注册后自动配置代理的需求。

下面我们动动手指头 按下 ctrl c ,ctrl v实现如下代码:代码不具备通用性 需要进一步优化 建议已给出。

using AgileConfig.Client; using AgileConfig.Client.RegisterCenter; using Newtonsoft.Json.Linq;  using Yarp.ReverseProxy.Configuration; using Yarp.ReverseProxy.Transforms;  namespace Microsoft.Extensions.DependencyInjection {     public static class AgileConfigProxyConfigProviderExtend     {         const string NotProxyStr = "notProxy";         const string TransformsStr = "Transforms";         static readonly ILogger _Logger = LoggerFactory.Create(b => { }).CreateLogger("AgileConfigProxyConfigProviderExtend");         public static RouteConfig[] GetRoutes(this IDiscoveryService discoveryService)         {             var routes = new List<RouteConfig>();             foreach (var item in discoveryService.Services)             {                 if (item.MetaData.Any(r=>r.Equals(NotProxyStr, StringComparison.OrdinalIgnoreCase)))                 {                     continue;                 }                 var route = new RouteConfig                 {                     RouteId = item.ServiceId,                     ClusterId = item.ServiceName,                     Match = new RouteMatch                     {                         Path = $"/{item.ServiceName}/{{**all}}"                     }                 };                 //.WithTransformPathRouteValues(pattern: new PathString("/{**all}"))                 try                 {                     var transformStr = item.MetaData.FirstOrDefault(r => r.StartsWith(TransformsStr));                     if (transformStr is not null)                     {                         var jobj = JObject.Parse(transformStr.Split(':')[1]);                         foreach (var k in jobj)                         {                             route.WithTransform(d => d.Add(k.Key, k.Value?.ToString() ?? ""));                         }                     }                 }                 catch (Exception e)                 {                     _Logger.LogError(e,"生成路由【转换】配置时出错");                 }                  routes.Add(route);                 _Logger.LogTrace("添加路由{RouteId}", route.RouteId);             }             return routes.ToArray();         }         public static ClusterConfig[] GetClusters(this IDiscoveryService discoveryService)         {             var clusters = new List<ClusterConfig>();             var proxyServices = discoveryService.Services                                     .Where(r => !r.MetaData.Any(r => r.Equals(NotProxyStr, StringComparison.OrdinalIgnoreCase)))                                     .GroupBy(p => p.ServiceName);              foreach (var item in proxyServices)             {                 var destinations = new Dictionary<string, DestinationConfig>(StringComparer.OrdinalIgnoreCase);                 foreach (var service in item)                 {                     destinations.Add(service.ServiceId, new DestinationConfig() {                         Address=service.AsHttpHost()                     });                 }                  clusters.Add(new ClusterConfig                 {                     ClusterId = item.Key,                     Destinations = destinations                 });             }              return clusters.ToArray();         }         //可以再加一个重载 支持传入一个委托 来自定义构造配置。         public static IReverseProxyBuilder LoadFromAgileConfigByInMemoryConfigProvider(this IReverseProxyBuilder builder, ConfigClient client)         {             var discoveryService = client.DiscoveryService();             discoveryService ??= new DiscoveryService(client, LoggerFactory.Create(b => b.SetMinimumLevel(LogLevel.Information)));              var configProvider = new InMemoryConfigProvider(discoveryService.GetRoutes(), discoveryService.GetClusters());              builder.Services.AddSingleton(configProvider);             builder.Services.AddSingleton<IProxyConfigProvider>(configProvider);              discoveryService.ReLoaded += () =>             {                 configProvider.Update(discoveryService.GetRoutes(), discoveryService.GetClusters());             };             return builder;         }     } } 

现在只需要调用如下代码,即可给原有的yarp服务加上自动生成代理配置的功能了。

builder.Services.AddReverseProxy()//添加ReverseProxy相关服务到DI  .LoadFromAgileConfigByInMemoryConfigProvider((ConfigClient)client); 

注意:注册AgileConfig时候请使用 UseAgileConfig()方法注册。Addxxx方法会导致无法获取到agileConfig上的已注册服务对信息。
代码已传gitee:https://gitee.com/dotnetfans/yarp-auto-proxy.-agile-config
同时也个给agileConfig 提交了合并请求。