天天看點

External Configuration Store Pattern 外部配置存儲模式

Move configuration information out of the application deployment package to a centralized location. This pattern can provide opportunities for easier management and control of configuration data, and for sharing configuration data across applications and application instances.

将配置資訊從應用程式部署包中移動到集中位置。這種模式可以提供更容易的管理和控制配置資料的機會,并在應用程式和應用執行個體之間共享配置資料。

Context and Problem 情景和問題

The majority of application runtime environments include configuration information that is held in files deployed with the application, located within the application folders. In some cases it is possible to edit these files to change the behavior of the application after it has been deployed. However, in many cases, changes to the configuration require the application to be redeployed, resulting in unacceptable downtime and additional administrative overhead.

應用程式運作時環境中的大多數包括在應用程式部署的檔案中部署的配置資訊,位于應用程式檔案夾中的。在某些情況下,它可以編輯這些檔案,以改變應用程式後,它已被部署的行為。然而,在許多情況下,結構的變化要求應用程式被重新部署,而導緻不可接受的停機時間和額外的管理費用。

Local configuration files also limit the configuration to a single application, whereas in some scenarios it would be useful to share configuration settings across multiple applications. Examples include database connection strings, UI theme information, or the URLs of queues and storage used by a related set of applications.

本地配置檔案還限制了單個應用程式的配置,而在某些情況下,在多個應用程式中共享配置設定是有用的。例子包括資料庫連接配接字元串,使用者界面主題資訊,或相關的應用程式使用的隊列和存儲的網址。

Managing changes to local configurations across multiple running instances of the application, especially in a cloud-hosted scenario, may also be challenging. It may result in instances using different configuration settings while the update is being deployed.

管理的應用程式的多個運作執行個體,特别是在雲托管的情況下,本地配置的變化,也可能是具有挑戰性的。這可能會導緻在使用不同配置設定的情況下,而更新正在部署的情況下使用。

In addition, updates to applications and components may require changes to configuration schemas. Many configuration systems do not support different versions of configuration information.

此外,對應用程式群組件的更新可能需要更改配置模式。許多配置系統不支援不同版本的配置資訊。

Solution 解決方案

Store the configuration information in external storage, and provide an interface that can be used to quickly and efficiently read and update configuration settings. The type of external store depends on the hosting and runtime environment of the application. In a cloud-hosted scenario it is typically a cloud-based storage service, but could be a hosted database or other system.

存儲在外部存儲的配置資訊,并提供一個接口,可用于快速和有效地讀取和更新配置設定。外部存儲類型取決于應用程式的托管和運作時環境。在雲托管的情況下,它通常是基于雲的存儲服務,但可以是托管的資料庫或其他系統。

The backing store chosen for configuration information should be fronted by a suitable interface that provides consistent and easy to use access in a controlled way that enables reuse. Ideally, it should expose the information in a correctly typed and structured format. The implementation may also need to authorize users’ access in order to protect configuration data, and be flexible enough to allow multiple versions of the configuration (such as development, staging, or production, and multiple release versions of each one) to be stored.

存儲支援,選擇配置資訊應該是通過适當的接口,提供一緻的和容易在一個可控制的方式,使再利用通路。理想情況下,它應該在正确的類型和結構化的格式中公開資訊。實施還可能需要授權使用者通路以保護配置資料,并具有足夠的靈活性,以便允許多個版本的配置(如開發、分期、或生産,以及每一個版本的多個版本)被存儲。

Note:

Many built-in configuration systems read the data when the application starts up, and cache the data in memory to provide fast access and to minimize the impact on application performance. Depending on the type of backing store used, and the latency of this store, it might be advantageous to implement a caching mechanism within the external configuration store. For more information about implementing caching, see the Caching Guidance.

許多内置的配置系統在應用程式啟動時讀取資料,并将資料緩存在記憶體中以提供快速通路,并将其應用性能的影響降到最低。根據所使用的支援存儲類型和該存儲的延遲,它可能有利于在外部配置存儲區内實作緩存機制。有關實作緩存的更多資訊,參見緩存指南。

Figure 1 shows an overview of this pattern. 圖1顯示了該模式的概述。

External Configuration Store Pattern 外部配置存儲模式

Figure 1 - An overview of the External Configuration Store pattern with optional local cache 圖1 -一個可選的本地緩存的外部配置存儲模式的概述

Issues and Considerations 問題與思考

Consider the following points when deciding how to implement this pattern:

在決定如何實作這個模式時,考慮以下幾點:

  • Choose a backing store that offers acceptable performance, high availability, robustness, and can be backed up as part of the application maintenance and administration process. In a cloud-hosted application, using a cloud storage mechanism is usually a good choice to meet these requirements.
  • 選擇一個支援存儲,提供可接受的性能,高可用性,魯棒性,并且可以作為應用維護和管理過程的一部分來備份。在雲托管應用程式中,使用雲存儲機制通常是滿足這些要求的一個很好的選擇。
  • Design the schema of the backing store to allow flexibility in the types of information it can hold. Ensure that it provides for all configuration requirements such as typed data, collections of settings, multiple versions of settings, and any other features that the applications using it may require. The schema should be easy to extend as requirements change in order to support additional settings.
  • 設計支援存儲的架構,以允許靈活的類型的資訊,它可以容納。確定它提供了所有配置要求,如類型化的資料,設定的集合,多個版本的設定,以及任何其他功能,應用程式使用它可能需要。該模式應該是易于擴充的要求更改,以支援額外的設定。
  • Consider the physical capabilities of the backing store, how it relates to the way that configuration information is stored, and the effects on performance. For example, storing an XML document containing configuration information will require either the configuration interface or the application to parse the document in order to read individual settings, and will make updating a setting more complicated, though caching the settings can help to offset slower read performance.
  • 考慮備份存儲的實體功能,它涉及到配置資訊的方式,以及對性能的影響。例如,存儲一個包含配置資訊的文檔将要求配置接口或應用程式來解析該文檔以讀取個人設定,并将使更新設定更複雜,但緩存設定可以幫助抵消讀性能的慢。
  • Consider how the configuration interface will permit control of the scope and inheritance of configuration settings. For example, it may be a requirement to scope configuration settings at the organization, application, and the machine level; to support delegation of control over access to different scopes; and to prevent or allow individual applications to override settings.
  • 考慮如何配置接口将允許控制配置設定的範圍和繼承。例如,它可能是在組織,應用程式和機器級别的範圍配置設定的要求,以支援代表團對通路不同的作用域的控制,并防止或允許單個應用程式重寫設定。
  • Ensure that the configuration interface can expose the configuration data in the required formats such as typed values, collections, key/value pairs, or property bags. However, consider the balance between capabilities and complexity of the API in order to make it useful and yet as easy to use as possible.
  • 確定配置接口可以在所需的格式,如類型的值,集合,鍵/值對,屬性。然而,考慮的功能和複雜度之間的平衡,以使其有用的,但盡可能容易地使用。
  • Consider how the configuration store interface will behave when settings contain errors, or do not exist in the backing store. It may be appropriate to return default settings and log errors. Also consider aspects such as the case sensitivity of configuration setting keys or names, the storage and handling of binary data, and the ways that null or empty values are handled.
  • 考慮如何在設定包含錯誤時,在背景存儲區中設定有錯誤,或不存在。它可能是适當的傳回預設設定和日志錯誤。還考慮了諸如配置設定鍵或名稱、二進制資料的存儲和處理、以及空值或空值處理方式等方面的問題。
  • Consider how you will protect the configuration data to allow access only to the appropriate users and applications. This is likely to be a feature of the configuration store interface, but it is also necessary to ensure that the data in the backing store cannot be accessed directly without the appropriate permission. Ensure strict separation between the permissions required to read and to write configuration data. Also consider whether you need to encrypt some or all of the configuration settings, and how this will be implemented within the configuration store interface.
  • 考慮如何保護配置資料以允許僅允許通路适當的使用者和應用程式。這很可能是配置存儲界面的一個功能,但它也是必要的,以確定在背景存儲的資料不能直接通路沒有适當的權限。確定要求讀寫配置資料之間的權限嚴格分離。還考慮是否需要加密部分或全部配置設定,以及如何在配置存儲界面中實作此配置。
  • Keep in mind that centrally stored configurations, which change application behavior during runtime, are critically important and should be deployed, updated, and managed using the same mechanisms as deploying application code. For example, changes that can affect more than one application must be carried out using a full test and staged deployment approach to ensure that the change is appropriate for all applications that use this configuration. If an administrator simply edits a setting to update one application, it could adversely impact other applications that use the same setting.
  • 請記住,集中存儲配置在運作時更改應用程式行為,是非常重要的,應該部署、更新和管理使用與部署應用程式代碼相同的機制。例如,可以影響一個應用程式的更改必須使用一個完整的測試和部署方法來進行,以確定該更改适合于使用該配置的所有應用程式。如果管理者隻需編輯一個設定以更新一個應用程式,它可能對其他應用程式使用相同的設定産生不利影響。
  • If an application caches configuration information, the application may need to be alerted if the configuration changes. It may be possible to implement an expiration policy over cached configuration data so that this information is automatically refreshed periodically and any changes picked up (and actioned). The Runtime Reconfiguration pattern described elsewhere in this guide may be relevant to your scenario.
  • 如果應用程式緩存配置資訊,則應用程式可能需要提醒如果配置更改。它可以實作對緩存過期政策配置資料,該資訊自動重新整理周期和任何變化拿起(和處理)。在本指南中描述的其他地方的運作時配置模式可能與您的場景有關。

When to Use this Pattern 什麼時候使用這種模式

This pattern is ideally suited for:這種模式非常适合于:

  • Configuration settings that are shared between multiple applications and application instances, or where a standard configuration must be enforced across multiple applications and application instances.
  • 在多個應用程式和應用程式執行個體之間共享的配置設定,或者在多個應用程式和應用程式執行個體中必須強制執行标準配置。
  • Where the standard configuration system does not support all of the required configuration settings, such as storing images or complex data types.
  • 在标準配置系統不支援所有所需的配置設定,如存儲圖像或複雜的資料類型。
  • As a complementary store for some of the settings for applications, perhaps allowing applications to override some or all of the centrally-stored settings.
  • 作為應用程式的某些設定的互補性存儲,也許允許應用程式重寫某些或全部集中存儲的設定。
  • As a mechanism for simplifying administration of multiple applications, and optionally for monitoring use of configuration settings by logging some or all types of access to the configuration store.
  • 作為一種簡化多個應用程式管理的機制,并可選擇使用日志記錄某些或所有類型通路配置存儲的配置設定的監視使用的機制。

Example 例子

In a Microsoft Azure hosted application, a typical choice for storing configuration information externally is to use Azure storage. This is resilient, offers high performance, and is replicated three times with automatic failover to offer high availability. Azure tables provide a key/value store with the capability to use a flexible schema for the values. Azure blob storage provides a hierarchical container-based store that can hold any type of data in individually named blobs.

在一個微軟Azure的托管應用程式中,一個典型的存儲配置資訊的選擇是使用Azure的存儲。這是有彈性的,提供高性能,并重複三次自動故障轉移提供高可用性。Azure表提供了一個鍵/值存儲,使用靈活的模式為值的能力。Azure的BLOB存儲提供了一個分層的基于容器的存儲可以儲存任何類型的資料在單獨命名的斑點。

The following example shows how a configuration store can be implemented over Azure blob storage to store and expose configuration information. The BlobSettingsStore class abstracts blob storage for holding configuration information, and implements the ISettingsStore interface shown in the following code.

下面的示例示範如何配置存儲可以在Azure Blob存儲實作存儲和暴露的配置資訊。的BlobSettingsStore類文摘的BLOB存儲用于儲存配置資訊,并實作了在下面的代碼所示的ISettingsStore接口。

This code is provided in the ExternalConfigurationStore.Cloud project in the ExternalConfigurationStore solution. This solution is available for download with this guidance.

本代碼是在externalconfigurationstore提供。在externalconfigurationstore解雲項目。此解決方案是可供下載下傳的指南。

public interface IsettingsStore
{
  string Version { get; }

  Dictionary<string, string> FindAll();

  void Update(string key, string value);
}      

This interface defines methods for retrieving and updating configuration settings held in the configuration store, and includes a version number that can be used to detect whether any configuration settings have been modified recently. When a configuration setting is updated, the version number changes. The BlobSettingsStore class uses the ETag property of the blob to implement versioning. The ETag property of a blob is updated automatically each time the blob is written.

此接口定義了在配置存儲中檢索和更新配置設定的方法,并且包括可用于檢測最近已修改的任何配置設定的版本号。當配置設定更新時,版本号更改。的blobsettingsstore類使用BLOB的ETag屬性來實作版本控制。一個blob ETag屬性自動更新每次滴寫。

Note:

Note that, by design, this simple solution exposes all configuration settings as string values rather than typed values.

請注意,通過設計,這個簡單的解決方案将所有配置設定為字元串值,而不是類型值。

The ExternalConfigurationManager class provides a wrapper around a BlobSettingsStore object. An application can use this class to store and retrieve configuration information. This class uses the Microsoft Reactive Extensions library to expose any changes made to the configuration through an implementation of the IObservable interface. If a setting is modified by calling the SetAppSetting method, the Changed event is raised and all subscribers to this event will be notified.

externalconfigurationmanager類提供的包裹一blobsettingsstore對象。一個應用程式可以使用這個類來存儲和檢索配置資訊。這類使用微軟反應擴充庫暴露了配置通過對iobservable接口的一個實作的任何變化。如果設定是通過調用setappsetting方法改性,提高了事件和所有使用者對該事件将被通報。

Note that all settings are also cached in a Dictionary object inside the ExternalConfigurationManager class for fast access. The SetAppSetting method updates this cache, and the GetSetting method that an application can use to retrieve a configuration setting reads the data from the cache (if the setting is not found in the cache, it is retrieved from the BlobSettingsStore object instead).

請注意,所有的設定也緩存在字典對象裡面的externalconfigurationmanager類快速通路。的setappsetting方法更新緩存,和getsetting方法,應用程式可以使用檢索配置設定讀取緩存中的資料(如果設定不在緩存中,發現它是從blobsettingsstore對象代替)。

The GetSettings method invokes the CheckForConfigurationChanges method to detect whether the configuration information in blob storage has changed by examining the version number and comparing it with the current version number held by the ExternalConfigurationManager object. If one or more changes have occurred, the Changed event is raised and the configuration settings cached in the Dictionary object are refreshed. This is an application of the Cache-Aside pattern.

getsettings方法調用checkforconfigurationchanges法來檢測是否在Blob存儲配置資訊已認證審查的版本号與目前版本号的對象比較externalconfigurationmanager舉行了。如果發生了一個或多個更改,則将更改事件和在字典對象中緩存的配置設定更新。這是一個應用程式緩存的預留模式。

The following code sample shows how the Changed event, the SetAppSettings method, the GetSettings method, and the CheckForConfigurationChanges method are implemented

下面的代碼示例示範如何改變事件的setappsettings方法的getsettings方法和checkforconfigurationchanges方法的實施

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);
    }
  }
}      

The ExternalConfigurationManager class also provides a property named Environment. The purpose of this property is to support varying configurations for an application running in different environments, such as staging and production.

An ExternalConfigurationManager object can also query the BlobSettingsStore object periodically for any changes (by using a timer). The StartMonitor and StopMonitor methods illustrated in the code sample below start and stop the timer. The OnTimerElapsed method runs when the timer expires and invokes the CheckForConfigurationChanges method to detect any changes and raise the Changed event, as described earlier.

一個externalconfigurationmanager對象也可以查詢blobsettingsstore對象定期更改(使用定時器)。startmonitor和stopmonitor方法在下面的代碼示例說明了啟動和停止計時器。的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();
      ...
    }    
  }  
  ...
}      

The ExternalConfigurationManager class is instantiated as a singleton instance by the ExternalConfiguration class shown below.

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; }
  }
}      

The following code is taken from the WorkerRole class in the ExternalConfigurationStore.Cloud project. It shows how the application uses the ExternalConfiguration class to read and update a setting.

下面的代碼是在externalconfigurationstore從workerrole.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();
}      

The following code, also from the WorkerRole class, shows how the application subscribes to configuration events.

下面的代碼,也從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));
  ...
}      

Related Patterns and Guidance 相關模式和指導

The following pattern may also be relevant when implementing this pattern:

  • Runtime Reconfiguration Pattern. In addition to storing configuration externally, it is useful to be able to update configuration settings and have the changes applied without restarting the application. The Runtime Reconfiguration pattern describes how to design an application so that it can be reconfigured without requiring redeployment or restarting.

This pattern has a sample application associated with it. You can download the "Cloud Design Patterns – Sample Code" from the Microsoft Download Center at http://aka.ms/cloud-design-patterns-sample.