首页 > 代码库 > 云计算设计模式(八)——外部配置存储模式

云计算设计模式(八)——外部配置存储模式

云计算设计模式(八)——外部配置存储模式


移动配置信息应用部署到一个集中位置这个模式可以提供机会,以便管理和配置数据控制,以及用于跨应用程序和应用程序实例共享的配置数据。

背景和问题


大多数应用程序运行时环境包括位于应用程序文件夹内的部署应用程序文件保持配置信息在某些情况下也能够编辑这些文件来改变该应用程序的行为,已经被部署之后然而,在许多情况下,改变配置所需要的应用程序被重新部署,从而导致不可接受的停机时间和额外的管理开销。

本地配置文件配置限制为单个应用程序,而在某些情况下将是有用的,以在多个应用程序之间共享的配置设置。例子包括数据库连接字符串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));
  ...
}

本文翻译自MSDN:http://msdn.microsoft.com/en-us/library/dn589803.aspx

 

 

 

 

云计算设计模式(八)——外部配置存储模式