# 云計算設計模式(十九)——運行重構模式
設計應用程序,使得它可以在不需要重新部署或者重新啟動應用程序重新配置。這有助于保持可用性并減少停機時間。
## 背景和問題
一個主要目的為重要的應用,如商業和企業網站是盡量減少停機時間以及由此引發的中斷給客戶和用戶。但是,有時有必要重新配置應用程序改變特定行為或設置,而在部署和使用。因此,它是用于該應用程序被設計成這樣一種方式,以允許在運行時要應用這些配置的變化,并為應用程序,以檢測所述變化并且盡快地應用它們的部件的優點。
該種要應用可能被調整記錄,以協助與應用程序調試問題,交換使用不同數據存儲的連接字符串,或者打開或關閉特定的部分或應用程序的功能的粒度配置變化的例子。
## 解決方案
為實施這一模式的解決方案依賴于應用程序托管環境中可用的功能。典型地,應用程序代碼將響應于由檢測到的變化對應用程序配置時,主機基礎設施提出的一個或多個事件。這通常是上載新的配置文件,或響應于改變通過管理門戶的配置或者通過訪問的API的結果。
碼處理的配置變化事件可以檢查變化,并將其應用到該應用程序的組件。有必要對這些部件進行檢測和反應的變化,因此它們的值通常會被公開為可寫的屬性或方法,在事件處理程序的代碼可以設置為新值,或執行。從這一點來說,該部件應使用新的值,以便在需要改變應用程序的行為發生。
如果這是不可能的部件,以應用更改在運行時,這將是必要的,重新啟動該應用程序,從而當應用程序啟動時再次這些更改應用。在一些托管環境中它可能會檢測到這些類型的變化,并指出對環境的應用程序必須重新啟動。在其他情況下,可能有必要執行該分析的設置更改,并強制必要的應用程序重新啟動時的代碼。
圖1示出了本模式的概述。

圖1 - 此模式的基本概述
大多數環境中暴露響應配置更改引發的事件。在那些不這樣做,定期檢查更改配置并應用這些變化將是必要的輪詢機制。它也可能有必要重新啟動應用程序,如果變化不能在運行時被應用。例如,有可能以比較在預設的時間間隔一個配置文件的日期和時間,并運行代碼以應用更改時的較新版本中找到。另一種方法是,其中包含一個控制中的應用程序的管理用戶界面,或使一個安全端點可以從應用程序外部進行訪問,其執行讀取,并應用更新的配置的代碼。
或者,該應用程序可以反應以在環境中的一些其他變化。例如,發生于特定的運行時錯誤可能會改變日志配置自動收集更多的信息,或者代碼可以使用當前日期讀取和應用主題,反映了季節或特殊事件。
## 問題和注意事項
在決定如何實現這個模式時,請考慮以下幾點:
- 配置設置必須存儲在部署的應用程序之外,使得它們可以在不需要整個包被重新部署更新。典型的設置被存儲在配置文件中,或者在外部存儲庫中,如一個數據庫或網絡存儲。訪問運行時配置機制,應嚴格控制,以及使用時的嚴格審核。
- 如果托管的基礎設施不會自動檢測配置更改的事件,揭露這些事件對應用程序代碼,您必須實現一種替代機制來檢測和應用更改。這可以是通過輪詢機制,或者通過暴露交互式控制或端點發起更新過程。
- 如果您需要實現一個輪詢機制,考慮如何經常檢查更新的配置應該發生。長輪詢間隔將意味著變化可能不被應用了一段時間。短的間隔可能會產生不利影響,通過吸收現有的計算和I / O資源的操作。
- 如果是應用程序的多個實例,附加的考慮因素,這取決于如何變化進行檢測。如果改變是通過由宿主基礎結構引發的事件自動檢測到,這些變化可能不被同時應用的所有實例進行檢測。這意味著,某些情況下,將要使用的原始配置為一個周期,而有些則使用新的設置。如果該更新是通過輪詢機制檢測到,這必須以保持一致性通信改變到所有實例。
- 一些配置的變化可能要求應用程序重新啟動,甚至要求托管服務器重新啟動。您必須確定這些類型的配置設置和執行的每一個相應的操作。例如,要求應用程序重新啟動的變化可能會自動執行此操作,或者它可能是管理員負責發起重新啟動在適當的時間時,應用過大的負荷和應用程序可以處理的其他實例下是不的負載。
- 更新并確認他們是成功的,而更新的應用程序實例正在執行正確,將更新應用到所有實例之前的分階段部署計劃。由此,能夠防止應發生錯誤的應用程序的總的中斷。凡更新需要重新啟動或應用程序的重新啟動,特別是在應用程序有一個顯著啟動或熱身的時候,用一個分階段部署的方式,以防止多個實例脫機在同一時間。
- 考慮如何將回滾造成的問題配置更改,或導致申請失敗。例如,它應該能夠滾動的等待輪詢間隔,以檢測所述變化背部的變化立即代替。
- 考慮如何配置設置的位置可能會影響應用程序的性能。例如,你應該處理將發生,如果您使用外部存儲不可用的錯誤,當應用程序啟動時,或配置更改將被應用,比如用一個默認的配置或通過本地緩存的設置在服務器和重用這些值而重試訪問遠程數據存儲。
- 高速緩存可以幫助減少延遲,如果一個組件需要多次訪問配置設置。然而,當配置改變時,應用程序代碼將需要無效緩存設置,該組件必須使用更新后的設置。
## 何時使用這個模式
這種模式非常適合于:
- 應用程序,而您必須避免一切不必要的停機時間,同時仍然能夠將更改應用到應用程序配置。
- 環境,揭露事件自動提出的主要配置更改時。通常,這是當檢測到一個新的配置文件,或者更改了現有的配置文件。
- 應用的地方,往往配置更改和變化可以應用于組件,而不要求應用程序重新啟動,或無需托管服務器必須重新啟動。
這種模式可能不是合適的,如果運行時組件的設計使得它們只能在初始化時被配置,并更新這些部件的努力不能相比,重新啟動應用程序和持久的一個短的停機時間是合理的。
## 例子
微軟 Azure 云服務的角色發現和揭露被提了兩個事件,當主機環境檢測變化的 ServiceConfiguration.cscfg 文件:
- RoleEnvironment.Changing。引發此事件被檢測到的結構變化后,但在此之前它被施加到該應用程序。你可以處理查詢的變化,并取消運行時重新配置的活動。如果取消了變化,網頁或輔助角色將自動以使新配置被應用程序使用的重新啟動。
- RoleEnvironment.Changed。引發此事件后,應用程序的配置得到了應用。可以處理該事件來查詢所應用的改變。
當取消在 RoleEnvironment.Changing 事件改變要表示到 Azure,一個新的設置不能被應用于該應用程序正在運行時,并且它必須以使用新的值被重新啟動。有效地,你會取消更改只有在您的應用程序或組件無法反應在運行時改變,需要重新啟動才能使用新的值。
> 注意: 欲了解更多信息,請參閱 RoleEnvironment.Changing 事件并使用 RoleEnvironment.Changing 事件 MSDN 上。
處理 RoleEnvironment.Changing 和 RoleEnvironment.Changed 事件,你通常會添加一個自定義處理該事件。例如,從你可以下載本手冊的例子運行時重新配置的解決方案的 Global.asax.cs 類下面的代碼顯示了如何添加一個名為 RoleEnvironment_Changed 到事件處理鏈中的自定義函數。這是從實施例的的 Global.asax.cs 文件。
> 注意: 這種模式的例子是,在 RuntimeReconfiguration 解決方案的 RuntimeReconfiguration.Web 項目。
~~~
protected void Application_Start(object sender, EventArgs e)
{
ConfigureFromSetting(CustomSettingName);
RoleEnvironment.Changed += this.RoleEnvironment_Changed;
}
~~~
在 Web 或工作的角色,你可以在處理 RoleEnvironment.Changing 事件的作用的 OnStart 事件處理程序中使用類似的代碼。這是從實施例的 WebRole.cs 文件。
~~~
public override bool OnStart()
{
// Add the trace listener. The web role process is not configured by web.config.
Trace.Listeners.Add(new DiagnosticMonitorTraceListener());
?
RoleEnvironment.Changing += this.RoleEnvironment_Changing;
return base.OnStart();
}
~~~
要注意的是,在網頁的角色的情況下,所述的 OnStart 事件處理程序中從 Web 應用程序本身的單獨進程中運行。這就是為什么你通常會處理在 Global.asax 文件中 RoleEnvironment.Changed 事件處理程序,讓您可以更新您的 Web 應用程序的運行時配置,而 RoleEnvironment.Changing 事件中的角色本身。在輔助角色的情況下,您可以訂閱雙方 RoleEnvironment.Changing和RoleEnvironment.Changed 的 OnStart 事件處理程序中的事件。
> 注意: 可以在服務配置文件中存儲自定義的配置設置,在自定義配置文件,在數據庫中,如在虛擬機中的 Azure SQ L數據庫或 SQL Server,或者在天青 blob 和表存儲。您需要創建一個可以訪問自定義配置設置和應用程序內設置組件的屬性,這些適用于應用程序通常代碼。
例如,下面的自定義函數讀取設置,其名稱作為參數傳遞,從 Azure 的服務配置文件中的值,然后將它應用到一個名為 SomeRuntimeComponent 運行時組件的當前實例。這是從實施例的的 Global.asax.cs 文件
~~~
private static void ConfigureFromSetting(string settingName)
{
var value = RoleEnvironment.GetConfigurationSettingValue(settingName);
SomeRuntimeComponent.Instance.CurrentValue = value;
}
~~~
**注意**
一些配置設置,如那些用于 Windows 標識框架,不能存儲在 Azure 服務配置文件中,并且必須在 App.config 或 Web.config 文件。
在Azure中,一些配置的變化檢測,并自動應用。這包括在 Diagnostics.wadcfg 文件寡婦天青診斷系統,它指定的信息類型來收集和如何保持日志文件的結構。因此,它僅需要編寫處理添加到服務配置文件的自定義設置的代碼。你的代碼應該:
- 從更新的配置應用自定義設置您的應用程序在運行時的相應組件,使他們的行為體現了新的配置。
- 取消改變,以指示到 Azure 新的值不能在運行時應用,該應用程序必須按順序重新開始對要應用的變化。
例如,從你可以下載本手冊的例子運行時重新配置的解決方案 WebRole.cs 類下面的代碼顯示了如何使用 RoleEnvironment.Changing 事件取消所有設置的更新,除了可應用于那些在運行時,不需要重新啟動。此示例允許在運行時應用無需重新啟動應用程序(使用此設置將能夠讀取新的值,并相應地在運行時改變其行為的組成部分)更改為“CustomSetting”的設置。任何其他更改的配置將自動使網頁或工作的角色重新啟動。
~~~
private void RoleEnvironment_Changing(object sender,
RoleEnvironmentChangingEventArgs e)
{
var changedSettings = e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>()
.Select(c => c.ConfigurationSettingName).ToList();
Trace.TraceInformation("Changing notification. Settings being changed: "
+ string.Join(", ", changedSettings));
?
if (changedSettings
.Any(settingName => !string.Equals(settingName, CustomSettingName,
StringComparison.Ordinal)))
{
Trace.TraceInformation("Cancelling dynamic configuration change (restarting).");
?
// Setting this to true will restart the role gracefully. If Cancel is not
// set to true, and the change is not handled by the application, the
// application will not use the new value until it is restarted (either
// manually or for some other reason).
e.Cancel = true;
}
Else
{
Trace.TraceInformation("Handling configuration change without restarting. ");
}
}
~~~
注意:這種方法證明了好的做法,因為它確保了更改應用程序代碼不知道任何設置(因此不能確保它可以在運行時應用)將導致重新啟動。如果更改任何一個被取消,該角色將被重新啟動。
然后可以檢測到并應用于應用程序的組件的新的配置后已被接受由 Azure 的框架更新未在 RoleEnvironment.Changing 事件處理程序取消。例如,在該示例解決方案的 Global.asax 文件以下代碼處理 RoleEnvironment.Changed 事件。它檢查每個配置設置,并且當它找到名為“CustomSetting”的設置,調用一個函數(前面所示),該應用新的設置,以在應用程序中的適當組件。
~~~
private void RoleEnvironment_Changed(object sender,
RoleEnvironmentChangedEventArgs e)
{
Trace.TraceInformation("Updating instance with new configuration settings.");
?
foreach (var settingChange in
e.Changes.OfType<RoleEnvironmentConfigurationSettingChange>())
{
if (string.Equals(settingChange.ConfigurationSettingName,
CustomSettingName,
StringComparison.Ordinal))
{
// Execute a function to update the configuration of the component.
ConfigureFromSetting(CustomSettingName );
}
}
}
~~~
需要注意的是,如果你不取消配置的變化,但不將新值應用到您的應用程序組件,那么更改將不會生效的下一次重新啟動應用程序之前。這可能會導致不可預測的行為,尤其是當所述宿主角色實例由 Azure 的自動重啟在其日常維護操作,在該點的新的設定值將被應用的一部分。
- 前言
- (一)—— 緩存預留模式
- (二)—— 斷路器模式
- (三)—— 補償交易模式
- (四)——消費者的競爭模式
- (五)——計算資源整合模式
- (六)——命令和查詢職責分離(CQRS)模式
- (七)——事件獲取模式
- (八)——外部配置存儲模式
- (九)—— 聯合身份模式
- (十)——守門員模式
- (十一)—— 健康端點監控模式
- (十二)—— 索引表模式
- (十三)——領導人選舉模式
- (十四)——實體化視圖模式
- (十五)—— 管道和過濾器模式
- (十六)——優先級隊列模式
- (十七)—— 基于隊列的負載均衡模式
- (十八)—— 重試模式
- (十九)——運行重構模式
- (二十)—— 調度程序代理管理者模式
- (二十一)——Sharding 分片模式
- (二十二)——靜態內容托管模式
- (二十三)——Throttling 節流模式
- (二十四)—— 仆人鍵模式