
我在前文:
《微软Azure配置中心 App Configuration (一):轻松集成到Asp.Net Core》已经介绍了Asp.net Core怎么轻易的接入azure 配置中心App Configuration(下称azure 配置中心);
《微软Azure配置中心 App Configuration (二):Feature Flag 功能开关特性》 讲Asp.net Core功能开关的两种方式的简单使用;
本文重点来讲讲Azure配置中心是怎么配置的动态更新的。
一般对配置中心来说都有动态更新的概念,我这里给个定义:
配置中心的动态更新是指,当用户在配置中心管理后台更新配置后,集成的客户端能以某种形式到配置的更新;
一般有两种模式
本文在前文基础上开始的,有些略过的地方请看前文;
var builder = WebApplication.CreateBuilder(args);var connectionString = builder.Configuration.GetConnectionString("AppConfig");builder.Host.ConfigureAppConfiguration((hostingContext, config) =>{ //配置不同功能 config.AddAzureAppConfiguration(options => { ////启用Label(多环境)支持 //options.Connect(connectionString) // .Select(KeyFilter.Any, LabelFilter.Null)//配置过滤器,读取空Lable的配置 // .Select(KeyFilter.Any, hostingContext.HostingEnvironment.EnvironmentName); //配置过滤器,只读取某个环境的配置 //启用Poll模式的主动更新 options.Connect(connectionString) .Select(KeyFilter.Any, LabelFilter.Null)//配置过滤器,读取空Lable的配置 .Select(KeyFilter.Any, hostingContext.HostingEnvironment.EnvironmentName) //配置过滤器,只读取某个环境的配置 .ConfigureRefresh(refresh => { refresh.Register("TestApp:Settings:Sentinel", refreshAll: true).SetCacheExpiration(new TimeSpan(0, 0, 30)); }); });});这里方法ConfigureRefresh参数:
TestApp:Settings:Sentinel:这就是程序轮询的配置Key;
refreshAll=true: 表示当轮询的配置Key更新时,更新所有配置;
SetCacheExpiration:设置多久时间轮询一次,这里设置了30秒,这也是默认值;
builder.Services.AddAzureAppConfiguration();我们现在Azure配置管理后台设置好key:TestApp:Settings:Sentinel

可以看到初始值==1;
我们新增一个测试的TestKey4==TestKey4-azure
启动程序后,我们无论怎么修改配置后台,都不会程序拿到值始终:TestKey4 ==TestKey4-azure
我们把监控Key:TestApp:Settings:Sentinel设置为2
再次获取可以看到,TestKey4 的值更新了:

OK,轮询模式就是这么朴实无华,却又足以满足大部分需求;
除了轮询的方式动态更新配置外,Azure配置中心也提供了push的方式主动推送配置更新到客户端,不过它的实现流程不太像我们经常遇到的Grpc或者Websocket等那样直连的方式,而是借助Azure消息队列Service Bus实现的。
大体流程:
先创建一个Service Bus的Topic订阅(类似于RabbitMQ的Topic);
Azure配置中心注册一个事件订阅到Service Bus的Topic订阅,当配置修改时触发事件发送一个配置更新消息到Service Bus;
客户端程序订阅了Service Bus的Topic,实时接收配置更新消息并更新本地程序的IConfiguration;
下面我们看看流程怎么实现;
创建Service Bus命名空间

信息自己填

创建Topic
我创建的topic名:config-topic

创建topic订阅
订阅名:config-s1


ok,到这步位置,Service Bus这边基本配置完;
App Configuration下创建事件订阅
填写Topic订阅信息
注意右侧红框,要选择你上步创建的Service Bus 的Topic订阅 config-topic

创建成功

install-package Microsoft.Azure.ServiceBus //ServiceBus 的配置 "AzureServiceBusConfig": { "ConnectionString": "< ConnectionString >", "TopicName": "< Your TopicName >", //我的是config-topic "SubscriptionName": "< Your SubscriptionName >" // 我的是 config-s1 }var builder = WebApplication.CreateBuilder(args);var connectionString = builder.Configuration.GetConnectionString("AppConfig");IConfigurationRefresher _refresher = null;builder.Host.ConfigureAppConfiguration((hostingContext, config) =>{ ////简单使用只配置connection string //config.AddAzureAppConfiguration(connectionString); //配置不同功能 config.AddAzureAppConfiguration(options => { //启用Push模式的主动推送更新配置 options.Connect(connectionString) .Select(KeyFilter.Any, LabelFilter.Null)//配置过滤器,读取空Lable的配置 .Select(KeyFilter.Any, hostingContext.HostingEnvironment.EnvironmentName) //配置过滤器,只读取某个环境的配置 .ConfigureRefresh(refresh => { refresh.Register("TestApp:Settings:Sentinel", refreshAll: true) .SetCacheExpiration(TimeSpan.FromDays(10)); //这个刷新频率要设置特别低了 }); _refresher = options.GetRefresher(); });});TestApp:Settings:Sentinel:只订阅这个key的刷新事件;
SetCacheExpiration:这里的刷新频率设置很低就行;
先写个拓展方法
/// <summary>/// 启用一个Service bus事件处理程序在配置更新时刷新 IConfiguration/// </summary>/// <param name="app">The application.</param>/// <param name="refresher">The refresher.</param>/// <returns></returns>/// <exception cref="System.ArgumentNullException">serviceBusConfig</exception>public static IApplicationBuilder UseAzureConfigChangeEventHandler(this IApplicationBuilder app, IConfigurationRefresher refresher){ var serviceBusConfig = PassportConfig.Get<AzureServiceBusConfig>(nameof(AzureServiceBusConfig)); if (serviceBusConfig == null) { throw new ArgumentNullException(nameof(serviceBusConfig)); } SubscriptionClient serviceBusClient = new SubscriptionClient(serviceBusConfig.ConnectionString, serviceBusConfig.TopicName, serviceBusConfig.SubscriptionName); serviceBusClient.RegisterMessageHandler(handler: (message, cancellationToken) => { // 构建一个 EventGridEvent EventGridEvent eventGridEvent = EventGridEvent.Parse(BinaryData.FromBytes(message.Body)); // 创建PushNotification eventGridEvent.TryCreatePushNotification(out PushNotification pushNotification); // 刷新IConfiguration refresher.ProcessPushNotification(pushNotification); refresher.TryRefreshAsync(); return Task.CompletedTask; }, exceptionReceivedHandler: (exceptionargs) => { Console.WriteLine($"{exceptionargs.Exception}"); return Task.CompletedTask; } ); return app;}然后直接在管道中启用
app.UseAzureConfigChangeEventHandler(_refresher);这个函数的功能是,订阅Service Bus的Topic ,当服务端配置修改时,接收配置更新信息,刷新本地配置;
还是用TestKey4来测试,先运行程序,
本来:TestKey4TestKey4-azure,我们改成:TestKey4TestKey4-azure 2022年8月6日

但怎么刷新程序获取的值都不会更新。
我们打个断点到函数:UseAzureConfigChangeEventHandler(),再更新Key TestApp:Settings:Sentinel
看到,收到配置更新消息命中断点了:

同时,通过Service Bus的后台,我们也已看到配置更新事件消息正确发送:

我们再次获取配置看到确已更新:

OK,服务端基于订阅消息队列获取配置的主动更新方式验证成功;
1、我觉得动态更新配置用主动轮询的方式基本能满足大部分需求(但是每次轮询消耗次数,请设置好轮询间隔时间),基于消息队列的主动推送方式稍微有点麻烦,看需求选用;
2、当配置中心的Key和本地配置文件的Key冲突时,以配置中心为准;
3、总体来说Azure配置中心还是挺香的,除了贵(毕竟Azure 土豪云),价格。
Azure配置中心的基本学习到这里告一段落,后面挖掘到更实用的功能/技巧将再次水文补充;
https://github.com/gebiWangshushu/Hei.Azure.Test
https://docs.microsoft.com/en-us/azure/azure-app-configuration/overview