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显示了该模式的概述。

IC709572

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接口。

Dn589803.note(en-us,PandP.10).gifNote:

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

Note:

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.

posted @ 2016-04-22 22:09  迪克猪  阅读(819)  评论(0编辑  收藏  举报