寫在前面
我在前文:
《微軟Azure配置中心 App Configuration (一):輕鬆集成到Asp.Net Core》已經介紹了Asp.net Core怎麼輕易的接入azure 配置中心App Configuration(下稱azure 配置中心);
《微軟Azure配置中心 App Configuration (二):Feature Flag 功能開關特性》 講Asp.net Core功能開關的兩種方式的簡單使用;
本文重點來講講Azure配置中心是怎麼配置的動態更新的。
概念定義
一般對配置中心來說都有動態更新的概念,我這裏給個定義:
配置中心的動態更新是指,當用戶在配置中心管理後臺更新配置後,集成的客戶端能以某種形式到配置的更新;
一般有兩種模式
- 1、客戶端輪詢;
- 2、服務端主動推送更新;包括但不限於Grpc(Nacos),Websocket等方式;
客戶端輪詢模式
本文在前文基礎上開始的,有些略過的地方請看前文;
1、修改集成方式
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秒,這也是默認值;
2、注入服務
builder.Services.AddAzureAppConfiguration();
3、驗證
我們現在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;
下面我們看看流程怎麼實現;
1、先創建Service Bus的Topic訂閱
創建Service Bus命名空間
信息自己填
創建Topic
我創建的topic名:config-topic
創建topic訂閱
訂閱名:config-s1
ok,到這步位置,Service Bus這邊基本配置完;
2、創建配置中心的事件訂閱到topic訂閱
App Configuration下創建事件訂閱
填寫Topic訂閱信息
注意右側紅框,要選擇你上步創建的Service Bus 的Topic訂閱 config-topic
創建成功
3、Asp.Net Core中集成
安裝包
install-package Microsoft.Azure.ServiceBus
新增配置信息
//ServiceBus 的配置
"AzureServiceBusConfig": {
"ConnectionString": "< ConnectionString >",
"TopicName": "< Your TopicName >", //我的是config-topic
"SubscriptionName": "< Your SubscriptionName >" // 我的是 config-s1
}
修改ConfigureService做集成
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:這裏的刷新頻率設置很低就行;
修改IApplicationBuilder集成
先寫個拓展方法
/// <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