1.前言

上一篇我们讨论了云计算设计模式之重试模式,了解了如何封装一个服务来负责处理瞬时连接失败时的问题.这一篇,我们来讨论下如何在系统运行时对系统进行配置而不需要重启系统,从而提升系统的高可用性.

2.概念

通常系统配置都是在一个系统配置文件中(app.config/web.config),在系统启动后,配置文件里面的内容会被加载到系统的某个配置对象中,如果修改配置而不重启系统,那么配置是无法生效的.尤其在复杂系统中,一次配置的更改引起的系统重启可能造成很大的影响.那么如何解决这个问题呢?

一个通常的做法是设计一种对系统配置的轮询侦测机制,一旦发现系统配置有更改,则把相应的配置更改应用到相关的组件.具体如何根据配置文件更改的内容决定哪些组件需要重新启用配置,则需要建立相应的规则.如果能够在运行时应用配置,则不需要重启,否则组件需要重启.下图描述了这种机制.


大部分的应用部署环境会暴露出配置更改的事件,如果部署环境没有提供这种机制,那么必须有一种轮询机制来监测配置的更改。一旦侦测到更改,通过运行时应用配置或者重启的方式来使用新的配置.

3.需要考虑的问题

使用这种模式需要考虑以下几个问题:

1)系统配置信息必须存储在系统外部,一旦需要更新配置不需要再次更新应用的部署.

2)如果应用的宿主环境没有提供侦测配置更改并暴露出相应的事件接口的时候,应用就必须实现轮询的机制来侦测配置的更改.

3)如果应用自己实现对配置的侦测,就需要慎重考虑轮询的频度.

4)如果应用有多个实例同时在运行,就需要慎重考虑何时该启用新配置了.

5)有些应用需要应用程序重启,甚至系统重启,必须慎重处理这些不同的情形.

6)最好建立预发布环境确认系统配置的更改确实生效,减少出错的机会.

7)必须考虑如何回滚配置更改.一次更改可能涉及到多个配置,一旦失败就需要回滚.

8)考虑配置的位置对系统性能的影响.

9)使用缓存能够确保组件应用可以连接到缓存,但是缓存必须具备侦测配置更改后自动更新缓存的功能.

4.何时使用

1)应用程序必须避免非必须的中断服务.

2)应用程序的宿主环境必须具有对配置更改有侦测能力.

3)应用程序的更改能够在运行时应用配置而无需重启,或者不需要系统重启.

5.Example

Microsoft Azure Cloud Services 的角色侦测和提供了两个配置更改的事件.一旦对ServiceConfiguration.cscfg更改将会触发这两个事件:

1)RoleEnvironment.Changing. This event is raised after a configuration change is detected, but before it is applied to the application. You can handle the event to query the changes and to cancel the runtime reconfiguration. If you cancel the change, the web or worker role will be restarted automatically so that the new configuration is used by the application.

2)RoleEnvironment.Changed. This event is raised after the application configuration has been applied. You can handle the event to query the changes that were applied.

当在RoleEnvironment.Changing取消了对配置的更改时,这将通知Azure,这个配置的更改无法在运行时应用,必须重启系统来实现.所以,仅仅在配置无法在运行时修改而必须重启系统时才在RoleEnvironment.Changing中取消操作.

为了处理RoleEnvironment.Changed事件,必须添加该事件的自定义Handler,通常是在Application_start的时候指定handler.下面的代码演示了这种做法:

protected void Application_Start(object sender, EventArgs e)
{
  ConfigureFromSetting(CustomSettingName);
  RoleEnvironment.Changed += this.RoleEnvironment_Changed;
}
在web role 或者 work role中在OnStart方法中指定 oleEnvironment.Changing 的handler,下面的代码演示了这种做法:
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();
}
值得注意的是,web role 或者 work role 的OnStart方法运行在每个role的process中,而app_start运行即可在运行时修改配置。翻译过来可能看得不是那么明白,相反原文可能更加清晰地表达了这个意思:

Be aware that, in the case of web roles, the OnStart event handler runs in a separate process from the web application process itself. This is why you will typically handle the RoleEnvironment.Changed event handler in the Global.asax file so that you can update the runtime configuration of your web application, and the RoleEnvironment.Changing event in the role itself. In the case of a worker role, you can subscribe to both theRoleEnvironment.Changing and RoleEnvironment.Changed events within the OnStart event handler.

在下面的例子中,用户自己实现的修改配置的方法将配置名称作为参数传入进来,然后把配置应用到当前实例.

private static void ConfigureFromSetting(string settingName)
{
  var value = RoleEnvironment.GetConfigurationSettingValue(settingName);
  SomeRuntimeComponent.Instance.CurrentValue = value;
}
在Windows Azure中,某些配置的更改会被自动侦测到并应用到实例中.Windows Azure  diagnostics 的配置(在Diagnostics.wadcfg)中,该文件配置了哪些信息需要被监控及如何写日志.因此只需要代码实现这个方法即可,所以代码需要实现:

1)在运行状态下将新的配置应用到相关的组件,以便系统的行为应用了新的配置.

2)在运行状态下无法更改的配置,需要取消配置更新动作,通知Azure新的配置无法在运行状态下更新,应用程序必须重启来应用更新.

In Azure, some configuration changes are detected and applied automatically. This includes the configuration of the Widows Azure diagnostics system in the Diagnostics.wadcfg file, which specifies the types of information to collect and how to persist the log files. Therefore, it is only necessary to write code that handles the custom settings you add to the service configuration file. Your code should either:

Apply the custom settings from an updated configuration to the appropriate components of your application at runtime so that their behavior reflects the new configuration.

* Cancel the change to indicate to Azure that the new value cannot be applied at runtime, and that the application must be restarted in order for the change to be applied.

For example, the following code from the WebRole.cs class in the Runtime Reconfiguration solution of the examples you can download for this guide shows how you can use the RoleEnvironment.Changing event to cancel the update for all settings except the ones that can be applied at runtime without requiring a restart. This example allows a change to the settings named “CustomSetting” to be applied at runtime without restarting the application (the component that uses this setting will be able to read the new value and change its behavior accordingly at runtime). Any other change to the configuration will automatically cause the web or worker role to restart.

必须重启进行更新的情形:

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. ");
  }
}
无需重启即可启用新配置的情形:

Updates that are not cancelled in the RoleEnvironment.Changing event handler can then be detected and applied to the application components after the new configuration has been accepted by the Azure framework. For example, the following code in the Global.asax file of the example solution handles the RoleEnvironment.Changed event. It examines each configuration setting and, when it finds the setting named “CustomSetting”, calls a function (shown earlier) that applies the new setting to the appropriate component in the application.

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 );
    }
  }
}
Note that if you fail to cancel a configuration change, but do not apply the new value to your application component, then the change will not take effect until the next time that the application is restarted. This may lead to unpredictable behavior, particularly if the hosting role instance is restarted automatically by Azure as part of its regular maintenance operations—at which point the new setting value will be applied.

6.相关阅读

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

  • External Configuration Store Pattern. Moving configuration information out of the application deployment package to a centralized location can provide opportunities for easier management and control of configuration data, and sharing configuration data across applications and application instances. The External Configuration Store pattern explains how you can do this.











Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐