现在软件就业环境不景气,各行各业都忙着裁员优化。作为一个小开发,咱也不能光等着别人来优化咱,也得想办法优化下自己。就拿手头上的工作来说吧,我发现我的微服务应用里,既有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服务,又可以免去每次服务部署时繁琐的网关配置。

首先第一个任务就是解决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 提交了合并请求。

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

  1. 服务发现之consul的介绍、部署和使用

    什么是服务发现 微服务的框架体系中,服务发现是不能不提的一个模块.我相信了解或者熟悉微服务的童鞋应该都知道它的重要性.这里我只是简单的提一下,毕竟这不是我们的重点.我们看下面的一幅图片:     图中 ...

  2. 服务发现 - consul 的介绍、部署和使用

    什么是服务发现 相关源码: spring cloud demo 微服务的框架体系中,服务发现是不能不提的一个模块.我相信了解或者熟悉微服务的童鞋应该都知道它的重要性.这里我只是简单的提一下,毕竟这不是 ...

  3. 服务发现 - consul 的介绍、部署和使用(转)

    什么是服务发现 相关源码: spring cloud demo 微服务的框架体系中,服务发现是不能不提的一个模块.我相信了解或者熟悉微服务的童鞋应该都知道它的重要性.这里我只是简单的提一下,毕竟这不是 ...

  4. 服务发现之consul理论整理_结合Docker+nginx+Tomcat简单部署案例

    目录 一.理论概述 服务发现的概念简述 consul简述 二.部署docker+consul+Nginx案例 环境 部署 三.测试 四.总结 一.理论概述 服务发现的概念简述 在以前使用的是,N台机器 ...

  5. Ocelot+Consul实现微服务架构

    API网关 API 网关一般放到微服务的最前端,并且要让API 网关变成由应用所发起的每个请求的入口.这样就可以明显的简化客户端实现和微服务应用程序之间的沟通方式.以前的话,客户端不得不去请求微服务A ...

  6. Api网关Kong集成Consul做服务发现及在Asp.Net Core中的使用

    写在前面   Api网关我们之前是用 .netcore写的 Ocelot的,使用后并没有完全达到我们的预期,花了些时间了解后觉得kong可能是个更合适的选择. 简单说下kong对比ocelot打动我的 ...

  7. 服务发现:Zookeeper vs etcd vs Consul

    [编者的话]本文对比了Zookeeper.etcd和Consul三种服务发现工具,探讨了最佳的服务发现解决方案,仅供参考. 如果使用预定义的端口,服务越多,发生冲突的可能性越大,毕竟,不可能有两个服务 ...

  8. Ocelot + Consul + Registrator 基于Docker 实现服务发现、服务自动注册

    目录 1. Consul集群搭建 1.1 F&Q Consul官方推荐的host网络模式运行 2. Registrator服务注册工具 2.1 F&Q Registrator悬挂服务 ...

  9. Ocelot + Consul实践

    关于Consul(https://www.consul.io)是一个分布式,高可用,支持多数据中心的服务发现和配置共享的服务软件,由 HashiCorp 公司用 Go 语言开发, 基于 Mozilla ...

  10. 服务发现:Zookeeper vs etcd vs Consul 参考自http://dockone.io/article/667

    服务发现:Zookeeper vs etcd vs Consul [编者的话]本文对比了Zookeeper.etcd和Consul三种服务发现工具,探讨了最佳的服务发现解决方案,仅供参考. 如果使用预 ...

随机推荐

  1. 如何将 IPhone 的文件导入 Linux

    如何将 IPhone 的文件导入 Linux 完全免费方案. 方法一: 使用 Koder 的 Local File Access 功能 这方法不需要在 Linux 端做任何配置. IPhone 端 安 ...

  2. 【Azure 应用服务】调用Azure Function经常提示超时的分析

    问题描述 Azure Data Factory 通过 Pipeline 调用Azure Function Http Trigger时遇到返回错误" 500 - The request tim ...

  3. Spring事务(六)-只读事务

    @Transactional(readOnly=true)就可以把事务方法设置成只读事务.设置了只读事务,事务从开始到结束,将看不见其他事务所提交的数据.这在某种程度上解决了事务并发的问题.一个方法内 ...

  4. vscode 格式化 vue 和 js代码 vetur prettier beautify

    这个文档 不涉及eslint 只专注自动格式化 格式化个性化需求: js中 自动去分号 js中 双引号变单引号 最大空换行数 是2 vue template中 属性自动折行 vue 的自动格式化 需要 ...

  5. Rust GUI库 egui 的简单应用

    目录 简介 简单示例 创建项目 界面设计 切换主题 自定义字体 自定义图标 经典布局 定义导航变量 实现导航界面 实现导航逻辑 实现主框架布局 调试运行 参考资料 简介 egui(发音为"e ...

  6. linux命令行下使用代理

    有两种方法: 1.curl -x <proxy_ip>:<proxy_port> <real_website> 举例:curl -x 12.99.109.52:80 ...

  7. jquery之获取某个元素上的事件

    jquery的给元素绑定的事件可以用data方法取出来 通过$(element).data("events")来获取 // 比如给一个button绑定两个click事件 $(&qu ...

  8. C++ 萃取机 Iterator Traits

    Iterator Traits 萃取出 Iterator 的性质:迭代器种类.迭代器所指数据类型.迭代器距离类型.迭代器所指数据引用.迭代器所指数据指针.根据不同的迭代器种类可以采取不同的算法策略.但 ...

  9. 一个简单的RTMP服务器实现 --- RTMP与H264

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  10. dubbo 泛化调用场景下,如何调用下游的泛型对象入参

    dubbo泛化调用时,除了java原生的collection,map泛型对象,业务自定义的泛型对象是不支持泛化调用的,无法正确的填充下游数据对象.两种解法: 泛化调用的时候把泛型具体类型的全限定类路径 ...