1. 程式人生 > >雲端計算設計模式(八)——外部配置儲存模式

雲端計算設計模式(八)——外部配置儲存模式

雲端計算設計模式(八)——外部配置儲存模式


移動配置資訊應用部署到一個集中位置這個模式可以提供機會,以便管理和配置資料控制,以及用於跨應用程式和應用程式例項共享的配置資料。

背景和問題


大多數應用程式執行時環境包括位於應用程式資料夾內的部署應用程式檔案保持配置資訊在某些情況下也能夠編輯這些檔案來改變該應用程式的行為,已經被部署之後然而,在許多情況下,改變配置所需要的應用程式被重新部署,從而導致不可接受的停機時間和額外的管理開銷。

本地配置檔案配置限制為單個應用程式,而在某些情況下將是有用的,以在多個應用程式之間共享的配置設定。例子包括資料庫連線字串UI主題的資訊或佇列

和儲存所使用的一組相關應用程式的URL

變更管理應用程式的多個執行例項的本地配置尤其是在雲託管的情況也可能是具有挑戰性的可能會導致使用不同的配置設定的例項,而更新正被部署

另外,更新應用程式和元件可能需要更改的配置方案許多配置系統不支援不同版本配置資訊。

解決方案


儲存外部儲存器中的配置資訊,並提供可用於快速和有效地讀取和更新的配置設定的介面。外部儲存的型別取決於應用程式主機執行時環境。在一個雲託管的情況下是一個典型的基於雲的儲存服務,但可能是一個託管資料庫或其他系統

選擇用於配置資訊備份儲存通過適當的介面,它提供了一個可控制的方式,使回用保持一致和易於使用的

訪問朝向理想情況下,應該公開鍵入正確,結構化的格式的資訊。的實施可能需要對使用者進行授權,以保護結構的資料訪問並且具有足夠的靈活性,以允許要被儲存的多個版本的配置(例如,開發分段生產,並且每一個的多個發行版本)


注意:

許多內建的系統配置中讀取資料時,應用程式啟動和快取記憶體記憶體中的資料提供快速訪問,並儘量減少對應用程式效能的影響。根據所使用的後備儲存器的型別,以及該商店的等待時間,這可能是有利的,以實現外部配置儲存器內的快取記憶體機制有關實現快取的詳細資訊,請參閱快取指導



圖1示出了本模式的概述。

圖1  - 外部配置儲存模式可選本地快取概述

問題和注意事項


在決定如何實現這個模式時,請考慮以下幾點
選擇一個後備儲存,提供可接受的效能高可用性,健壯性和可備份作為應用程式的維護和管理過程的一部分在一個雲託管的應用程式使用雲端儲存的機制通常是一個不錯的選擇,以滿足這些要求
•設計後備儲存架構允許在資訊能夠儲存型別的靈活性。確保它提供了一種使用可以要求該申請的所有配置的要求,例如輸入資料中,設定的集合多個版本設定,以及任何其他功能。該模式應該是易於擴充套件需求,以支援更多的設定更改
•考慮後備儲存的物理效能它與配置資訊的儲存方式以及對效能的影響例如儲存一個包含XML檔案的配置資訊要求使用配置介面應用程式解析該檔案讀取各個設定,將使得更新的設定更加複雜,儘管快取記憶體中的設定可有助於抵消較慢的讀取效能
•考慮如何配置介面將允許配置設定的範圍和繼承的控制權。例如,它可能是一個要求的範圍的配置設定在組織,應用程式和裝置的水平;支援訪問不同範圍的控制下放;並且,以防止允許單獨的應用程式,以覆蓋設定
•確保配置介面可以在需要的格式的配置資料暴露,如輸入的集合鍵/值對或財產然而考慮能力和API的複雜性之間的平衡,以使其有用的,但儘可能地易於使用。
•考慮配置儲存介面將如何表現時,設定有誤沒有內部儲存存在。可能是適當的,返回預設設定和記錄錯誤。也可以考慮,如配置設定按鍵或者名稱二進位制資料的儲存和處理以及null或空處理方式的情況下,靈敏度方面
•考慮如何將保護配置資料僅允許訪問相應的使用者和應用程式很可能是在配置儲存器介面的一個特徵,但它也是必要的,以確保後備儲存器中的資料不能被直接訪問,而不適當的許可權確保讀取和寫入配置資料所需的許可權之間的嚴格分離也可以考慮是否需要加密部分配置設定或全部以及如何配置儲存介面中實現
請記住,集中儲存配置,這在執行時改變應用程式的行為非常重要的,並應部署更新並使用相同的機制,部署應用程式程式碼進行管理。例如可能會影響多個應用程式的更改,必須進行使用一個完整的測試分階段部署的方式,以確保變化是適用於所有使用該配置的應用程式。如果管理員簡單地進行編輯的設定來更新一個應用程式,它可以產生不利使用相同設定的其他應用程式的影響。
如果應用程式的快取記憶體的配置資訊,應用程式可能需要的,如果配置更改被提醒有可能實現過期策略快取中的配置資料,使這些資訊被自動定期重新整理任何更改拿起付諸行動本指南中其他地方所描述執行模式重構可能有關您的方案

何時使用這個模式


這種模式非常適合於
多個應用程式和應用程式例項或在標準配置中,必須跨多個應用程式和應用程式例項執行之間共享配置設定
•在標準配置的系統不支援所有所需的配置設定,儲存影象複雜的資料型別。
•作為補充商店的一些應用程式的設定,或許允許應用程式重寫一些集中儲存或所有設定
•作為一種機制,通過記錄的部分或全部型別的訪問配置儲存監控使用的配置設定簡化了多個應用程式管理以及可選

例子


微軟Azure託管應用用於從外部儲存配置資訊的典型的選擇是使用Azure儲存是有彈性的提供高效能重複3自動故障切換提供高可用性 Azure的表格提供了一個鍵/值儲存使用一個靈活的架構價值的能力。 Azure的Blob儲存提供了一個分層的基於容器的儲存,可以儲存任何型別單獨命名的blob資料。

下面的示例顯示瞭如何配置儲存可以通過Azure的Blob儲存來實現儲存和揭露的配置資訊BlobSettingsStore文摘Blob儲存用於儲存配置資訊並實現在下面的程式碼所示ISettingsStore介面。

注意:

此程式碼ExternalConfigurationStore解決方案ExternalConfigurationStore.Cloud專案提供該解決方案可用於下載本指導意見

public interface IsettingsStore
{
  string Version { get; }

  Dictionary<string, string> FindAll();

  void Update(string key, string value);
} 

該介面定義的方法,用於檢索和更新在配置儲存中保持的配置設定並且包括可用於檢測是否有任何配置設定最近已修改的版本號。何時配置設定被更新時,版本號的變化BlobSettingsStore類使用BLOBETag的屬性來實現的版本一個blobETag的屬性將BLOB寫入每一次自動更新。

注意:

需要注意的是按照設計,這個簡單的解決方案,展現了所有的配置設定字串值,而不是型別的值
ExternalConfigurationManager類提供了圍繞BlobSettingsStore物體的包裝。應用程式可以使用這個類來儲存和檢索配置資訊這個類使用Microsoft擴充套件庫來揭露的IObservable介面的實現做出任何配置更改如果設定是通過呼叫SetAppSetting修改更改的事件引發,所有訂閱者此事件將被通報
請注意,所有的設定也快取到ExternalConfigurationManager快速訪問內部Dictionary物件SetAppSetting方法更新該快取記憶體中,並且應用程式可以使用以檢索配置設定GetSetting方法從快取記憶體中讀取資料(如果未快取記憶體中找到該設定,它從BlobSettingsStore物件檢索代替)
所述的getSettings方法呼叫CheckForConfigurationChanges的方法來檢測Blob儲存的配置資訊是否通過檢查版本,並將它與所述ExternalConfigurationManager物件保持當前的版本號進行比較已經改變。如果一個或多個已經發生了變化,改變的事件引發,並快取在Dictionary物件的配置設定被重新整理。這是快取除了圖案的應用
下面的程式碼示例演示如何更改的情況下,SetAppSettings方法方法的getSettingsCheckForConfigurationChanges方法實現

public class ExternalConfigurationManager : IDisposable
{
  // An abstraction of the configuration store.
  private readonly ISettingsStore settings;
  private readonly ISubject<KeyValuePair<string, string>> changed;
  ...
  private Dictionary<string, string> settingsCache;
  private string currentVersion;
  ...
  public ExternalConfigurationManager(ISettingsStore settings, ...)
  {
    this.settings = settings;
    ...
  }
  ...
  public IObservable<KeyValuePair<string, string>> Changed
  {
    get { return this.changed.AsObservable(); }
  }
  ...
  public void SetAppSetting(string key, string value)
  {
    ...
    // Update the setting in the store.
    this.settings.Update(key, value);

    // Publish the event.
    this.Changed.OnNext(
         new KeyValuePair<string, string>(key, value));

    // Refresh the settings cache.
    this.CheckForConfigurationChanges();
  }

  public string GetAppSetting(string key)
  {
    ...
    // Try to get the value from the settings cache.  
    // If there is a miss, get the setting from the settings store.
    string value;
    if (this.settingsCache.TryGetValue(key, out value))
    {
      return value;
    }
            
    // Check for changes and refresh the cache.
    this.CheckForConfigurationChanges();

    return this.settingsCache[key];
  }
  ...
  private void CheckForConfigurationChanges()
  {
    try
    {

      // Assume that updates are infrequent. Lock to avoid
      // race conditions when refreshing the cache.
      lock (this.settingsSyncObject)
      {          {
        var latestVersion = this.settings.Version;

        // If the versions differ, the configuration has changed.
        if (this.currentVersion != latestVersion)
        {
          // Get the latest settings from the settings store and publish the changes.
          var latestSettings = this.settings.FindAll();
          latestSettings.Except(this.settingsCache).ToList().ForEach(
                                kv => this.changed.OnNext(kv));

          // Update the current version.
          this.currentVersion = latestVersion;

          // Refresh settings cache.
          this.settingsCache = latestSettings;
        }
      }
    }
    catch (Exception ex)
    {
      this.changed.OnError(ex);
    }
  }
}

注意:

ExternalConfigurationManager類還提供了一個名為Environment屬性此屬性的目的是為了支援不同的配置不同的環境中臨時和生產執行的應用程式

一個ExternalConfigurationManager物件可以定期查詢BlobSettingsStore物件的任何變化通過使用定時器StartMonitorStopMonitor方法如下圖所示啟動程式碼示例和停止計時器OnTimerElapsed方法當定時器到期時,並呼叫CheckForConfigurationChanges方法來檢測的任何變化,並提高變更的情況下,如前面所描述執行

public class ExternalConfigurationManager : IDisposable
{
  ...
  private readonly ISubject<KeyValuePair<string, string>> changed;
  private readonly Timer timer;
  private ISettingsStore settings;
  ...
  public ExternalConfigurationManager(ISettingsStore settings, 
                                      TimeSpan interval, ...)
  {
    ...

    // Set up the timer.
    this.timer = new Timer(interval.TotalMilliseconds)
    {
      AutoReset = false;
    };
    this.timer.Elapsed += this.OnTimerElapsed;

    this.changed = new Subject<KeyValuePair<string, string>>();
    ...    
  }

  ...
        
  public void StartMonitor()
  {
    if (this.timer.Enabled)
    {
      return;
    }

    lock (this.timerSyncObject)
    {
      if (this.timer.Enabled)
      {
        return;
      }
      this.keepMonitoring = true;

      // Load the local settings cache.
      this.CheckForConfigurationChanges();

      this.timer.Start();
    }
  }

  public void StopMonitor()
  {
    lock (this.timerSyncObject)
    {
      this.keepMonitoring = false;
      this.timer.Stop();
    }
  }

  private void OnTimerElapsed(object sender, EventArgs e)
  {
    Trace.TraceInformation(
          "Configuration Manager: checking for configuration changes.");

    try
    {
      this.CheckForConfigurationChanges();
    }
    finally
    {
      ...
      // Restart the timer after each interval.
      this.timer.Start();
      ...
    }    
  }  
  ...
}

ExternalConfigurationManager類被例項化作為ExternalConfiguration如下所示的單一例項。

public static class ExternalConfiguration
{
  private static readonly Lazy<ExternalConfigurationManager> configuredInstance 
                            = new Lazy<ExternalConfigurationManager>(
    () =>
    {
      var environment = CloudConfigurationManager.GetSetting("environment");
      return new ExternalConfigurationManager(environment);
    });

  public static ExternalConfigurationManager Instance
  {
    get { return configuredInstance.Value; }
  }
}

下面的程式碼取自WorkerRoleExternalConfigurationStore.Cloud專案顯示瞭如何在應用程式使用ExternalConfiguration類讀取和更新設定。

public override void Run()
{
  // Start monitoring for configuration changes.
  ExternalConfiguration.Instance.StartMonitor();

  // Get a setting.
  var setting = ExternalConfiguration.Instance.GetAppSetting("setting1");
  Trace.TraceInformation("Worker Role: Get setting1, value: " + setting);

  Thread.Sleep(TimeSpan.FromSeconds(10));

  // Update a setting.
  Trace.TraceInformation("Worker Role: Updating configuration");
  ExternalConfiguration.Instance.SetAppSetting("setting1", "new value");

  this.completeEvent.WaitOne();
}


下面的程式碼也是從WorkerRole展示瞭如何應用訂閱配置事件。

public override bool OnStart()
{ 
  ...
  // Subscribe to the event.
  ExternalConfiguration.Instance.Changed.Subscribe(
     m => Trace.TraceInformation("Configuration has changed. Key:{0} Value:{1}", 
          m.Key, m.Value),
     ex => Trace.TraceError("Error detected: " + ex.Message));
  ...
}