微服务配置文件可视化集中管理 - 第一章
- 一、为什么需要配置文件可视化集中管理.
- 二、成百上千的微服务配置文件解决方案.
- 三、具体实现
- 1.首先模拟配置中心,提供api接口供应用站点拉取配置信息.
- 2.应用站点继承ConfigurationProvider类,重写Load()函数,实现从远程配置中心提供的api接口拉取配置信息.
- 3.新建一个MsydtConfigSource的类,这个类实现IConfigurationSource接口.为了在启动的时候注入我们自己实现的提供器.
- 4.给IConfigurationBuilder定义一个AddMsydtConfig的扩展方法,跟.Net Core自带的几个配置源使用风格保持一致。
- 5.在Program中添加对MsydtConfigBuilderExt类中的扩展方法AddMsydtConfig的调用.
- 6.最后测试.
- 总结
一、为什么需要配置文件可视化集中管理.
不管什么语言的项目,几乎或多或少都会用到配置文件.
.Net Framework时代我们使用App.config、Web.config,到了.Net Core的时代我们使用appsettings.json,这些我们再熟悉不过了。
然而当前,我们部署.net core项目,很多时候是容器化的,并且很多项目采用微服务架构,这些本地文件配置有的时候就不太合适了
为什么不合适呢?主要有以下几方面:
- 当你把项目部署到docker后,你会发现要修改一个配置文件变的非常麻烦。你不得不通过宿主机进入容器内部来修改文件,也许容器内还不带vi等编辑工具,连看都不能看,只有更改后重新编译发布镜像或者在容器中安装vi等工具。
- 我们一般做的是微服务架构,我们通常会启动多个容器实例.一个一个去修改容器的配置,这简直要命.
- 通常我们需要一些热更新的配置文件.打个比方:有一台邮件服务站点,更换了ip地址,其它调用它的站点要更新配置文件,只能一台一台的去更改配置,然后重新启动站点,才会生效.
4.相同的配置各个站点会冗余配置.比如:Redis服务的地址,各个站点都是访问同一个,但是在各个项目里都要配置一遍.
针对上面这些,不友好的配置体验,以下根据亲身实战,分享给同行从业者,我们一起学习,成长.
二、成百上千的微服务配置文件解决方案.
温馨提示:看文章前,最好要先去了解.net core中的IConfiguration,尽量先去看看源码.
编程语言:C#
SDK版本:.NET Core2.2
微服务框架:ocelot
上图是我们的微服务架构图.看到的三台Service,就是具体的业务站点,他们都有自己的配置文件,这里只画了三台,实际生产环境,可能是几十台,几百台,所以“配置中心”就诞生了。
配置中心是微服务的基础设施,它对配置进行集中的管理并对内暴露接口,当应用程序需要的时候通过接口读取。配置通常为json模式(为了兼容.net core项目默认的配置文件是Json),然后通过http接口暴露。
废话不多说直接上解决方案.
- NET Core应用启动时主动调用一次配置中心,获取站点所有的配置信息.
- 新启动NET Core应用能够将自身的IP地址注册到配置中心,便于配置中心配置更改后,通知NET Core应用进行配置热更新.
- 为了兼容NET Core应用取配置的格式,做到配置文件零侵入要继承ConfigurationProvider类,重写Load()函数,实现从远程配置中心拉取配置信息.
上图是在配置中心管理系统中:添加一条配置信息.
环境标签:Debug(用于应用站点,通过这个标识来获取什么环境的配置)
配置标识:mianshiyidiantong(用于应用站点,通过这个标识来获取具体配置信息)
配置信息:具体的NET Core应用站点的Json配置信息详情.
三、具体实现
1.首先模拟配置中心,提供api接口供应用站点拉取配置信息.
代码如下(示例):
[Route("api/[controller]")]
[ApiController]
public class ConfigsController : Controller
{
/// <summary>
/// 获取配置信息
/// </summary>
/// <param name="key">配置标识</param>
/// <param name="dev">环境标签</param>
/// <returns></returns>
public string Get(string key,string dev)
{
//注意:这里只是模拟返回Json配置信息,生产环境:
//这里应该根据配置标识+环境标签
//从配置中心数据库中获取
return
"{\"database\" : \"Server=192.168.10.146;" +
"Database=DAS;" +
"User ID=xxx;Password=xxx;Pooling=true;" +
"Max Pool Size=500;Connection Lifetime=20;\"," +
"\"baseApi\": {\"dk\": \"192.168.10.146\"}}";
}
}
上面的api接口,请求方式为:http://localhost:41000/api/Configs?key=mianshiyidiantong&dev=DEBUG
2.应用站点继承ConfigurationProvider类,重写Load()函数,实现从远程配置中心提供的api接口拉取配置信息.
从现在开始我们真正开始来实现从远处拉取配置信息.当程序启动的时候从配置中心读取配置文件信息,并提供给后面的代码使用配置。
新建一个asp.net core mvc站点来模拟应用站点。
代码如下:
// <summary>
/// 继承ConfigurationProvider类,重写Load()函数
/// </summary>
public class MsydtConfigProvider : ConfigurationProvider
{
/// <summary>
/// 重写Load()函数远程配置中心读取配置信息
/// </summary>
public override async void Load()
{
try
{
var serverAddress = "http://localhost:41000";
var client = new HttpClient();
client.BaseAddress = new Uri(serverAddress);
var response = await client.GetStringAsync("/api/configs?key=mianshiyidiantong&dev=DEBUG");
this.Data = JsonConfigurationFileParser.Parse(response);
}
catch (Exception ex)
{
//write error log
}
}
}
此处已经将我们远程配置中心的配置信息拉取了回来,并重写了Load()函数。这样我们就已经无缝衔接了.net core配置文件的获取方式,完全兼容,之前的获取方式,比如获取配置信息,带层级的以":"分隔的方式获取: var baseApi = _configuration[“baseApi:dk”];
**注意:**这里重写Load()函数时,有句代码:this.Data = JsonConfigurationFileParser.Parse(response);这里的实现,需要更改一下JsonConfigurationFileParser源码,才能达到我们要的效果.具体怎么更改,我在下一章,会详细的贴出代码.
3.新建一个MsydtConfigSource的类,这个类实现IConfigurationSource接口.为了在启动的时候注入我们自己实现的提供器.
代码如下:
public class MsydtConfigSource : IConfigurationSource
{
public IConfigurationProvider Build(IConfigurationBuilder builder)
{
return new MsydtConfigProvider();
}
}
4.给IConfigurationBuilder定义一个AddMsydtConfig的扩展方法,跟.Net Core自带的几个配置源使用风格保持一致。
当调用AddMyConfig的时候给IConfigurationBuilder实例添加一个MyConfigSource的源。
代码如下:
public static class MsydtConfigBuilderExt
{
public static IConfigurationBuilder AddMsydtConfig(this IConfigurationBuilder builder)
{
return builder.Add(new MsydtConfigSource());
}
}
5.在Program中添加对MsydtConfigBuilderExt类中的扩展方法AddMsydtConfig的调用.
在ConfigureAppConfiguration的匿名委托方法中调用AddMsydtConfig扩展方法,这样程序启动的时候会自动使用我们MsydtConfigProvider类中自定义实现的远程拉取的配置信息.
代码如下:
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, configBuiler) =>
{
configBuiler.AddMsydtConfig();
})
.UseStartup<Startup>()
.UseUrls("http://*:41001");
}
到底我们所有的工作都完成了,可以进入测试了.
6.最后测试.
我们在应用站点中能否成功获取到配置中心集中管理的配置信息.
首先我们在应用站点创建一个TestController.
通过构造函数,将IConfiguration注入.
获取方式完全兼容,.net core原来的格式.如:
var database = _configuration[“database”];
var baseApi = _configuration[“baseApi:dk”];
代码如下:
/// <summary>
/// 测试配置文件获取
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class TestController : Controller
{
/// <summary>
/// 构造函数注入
/// </summary>
IConfiguration _configuration;
public TestController(IConfiguration configuration)
{
_configuration = configuration;
}
public List<KeyValuePair<string,string>> Get()
{
var list = new List<KeyValuePair<string, string>>();
var database = _configuration["database"];
var baseApi = _configuration["baseApi:dk"];
list.Add(new KeyValuePair<string, string>("database",database));
list.Add(new KeyValuePair<string, string>("baseApi",baseApi));
return list;
}
}
我们请求这个测试action:http://localhost:41001/Api/Test
请求后:我们断点,发现,注入的IConfiguration 的提供器多了一个MsydtConfigProvider配置提供器,如截图所示:
那按照下面的方式,能否获取到值呢?
var database = _configuration[“database”];
var baseApi = _configuration[“baseApi:dk”];
如图所示:非常完美的获取到了值.
总结
提示:第一章,虽然实现了应用站点的配置信息,通过配置中心集中管理起来.但是我们还有提高的地方:
例如:
- 1.应用站点的配置文件,可能存在更改的情况,这个时候,我们在配置中心,更改了,要通知所有使用这个配置的应用站点.要做到热更新,不要动不动就去重启应用站点(对于流量大的应用,这将会带来收益的极大损伤,老板也不允许你这样干,也许2分钟,就会影响上百单的交易).**这在下一篇将继续讲解.