云计算设计模式(十八)——重试模式

云计算设计模式(十八)——重试模式

启用应用程序来处理预期的,暂时的失败时,它会尝试连接到由透明的重试操作了以前失败的期望,失败的原因是瞬时的服务或网络资源。这种模式可以提高应用程序的稳定性。

背景和问题

该通信的应用程序与在云中运行的元素必须是可能发生在这样的环境中的瞬时故障敏感。这些故障包括网络连接的过程中出现时,一个服务是忙碌的瞬时损失的组件和服务中,服务的临时不可用,或超时。

这些故障一般是自校正的,如果经过一个合适的延迟被重复触发一个故障的动作很可能是成功的。例如,数据库服务,它正在处理大量并发请求可以实现节流策略,暂时拒绝,直到它的工作量有所缓和任何进一步的请求。试图访问该数据库的应用程序可能无法连接,但如果它经过一个合适的延迟再次尝试它可能会成功。

解决方案

在云中,瞬时故障的情况并不少见和应用应该被设计为优雅和透明地处理它们,减少的影响,这种故障可能对应用程序正在执行业务任务。

如果一个应用程序检测到故障时,它试图将请求发送到远程服务,它可以通过使用以下策略处理失败:
•如果故障指示故障不是瞬时的或不太成功,如果重复(例如,所造成的无效提供凭据的认证失败是不可能成功的,无论是多少次未遂),应用程序应中止操作和报告一个合适的异常。
•如果报道的具体故障是不寻常的或罕见的,这可能是由于反常的情况,如网络数据包成为损坏,同时它被发送。在这种情况下,应用程序可以再次立即重试失败的请求,因为相同的故障是不可能被重复和请求将可能是成功的。
•如果故障是由一种更加普遍的连接,或“忙”的失败,网络或服务可能需要在短期内同时连接问题纠正或工作的积压被清除。应用程序应该等待请求重试前一个合适的时间。

对于比较常见的短暂故障,重试期间,应选择以传播从应用程序中尽可能均匀的多个实例的请求。这可以减少繁忙的业务持续过载的可能性。如果一个应用程序的多个实例不断轰击与重试请求的服务,则可能需要该服务更长的时间来恢复。

如果请求仍然失败,应用程序可以等待进一步的时期,再次尝试。如果需要的话,这个过程可以重复而增加重试的延迟,直到请求的某一最大数目已经尝试都失败了。延迟时间可以逐步增加,或可使用的定时策略,如指数回退,取决于故障的性质和可能性,这将在这段时间内被校正。

图1示出了这种模式。如果尝试后的预定数量的请求不成功,应用程序应将故障为异常,并相应地处理它。

图1 - 使用重试模式中调用托管服务的操作

应用程序应该换所有试图访问远程服务,实现重试政策配套上面列出的策略之一的代码。发送到不同的服务请求会受到不同的政策,有的供应商提供封装这种方法库。这些库通常执行的政策是参数化的,而应用程序开发人员可以指定,如重试次数和重试之间的时间项的值。

在检测故障和重试失败的操作都应该记录这些故障的详细信息的应用程序的代码。这个信息可能是有用的运算符。如果一个服务被频繁报道为不可用或忙,往往是因为该服务已耗尽其资源。则可以减少与这些故障发生时通过换算出该服务的频率。例如,如果数据库服务正在不断超载,它可能是有利的分区数据库和负载分散到多个服务器。

注意:

微软Azure提供了重试模式的广泛支持。该模式与实践瞬态故障处理块允许应用程序通过一系列的重试策略来处理许多Azure服务瞬态故障。微软实体框架版本6提供了用于重新尝试数据库操作。此外,许多在Azure
Service Bus和Azure存储的API透明地执行重试逻辑。

问题和注意事项

在决定如何实现这个模式时,您应考虑以下几点:
•重试政策应进行调整,以满足应用和故障性质的业务需求。它可能是更好一些非关键操作失败快而不是重试几次,并影响应用程序的吞吐量。例如,在试图访问远程服务的交互式Web应用程序,这可能是更好的重试之后用重试之间只有一个短的延迟的数量较少失败,并显示一个适当的消息给用户(例如,“请稍后“),再次尝试阻止应用程序变得反应迟钝。对于批处理应用程序,它可以是更合适的,以增加重试尝试的次数与尝试之间的指数增加的延迟。
•与尝试之间最小的延迟和大量的重试的高攻击重试的政策,可能会进一步降低正在接近运行或容量的占用。此重试策略也可能会影响应用程序的响应,如果它被不断地在尝试执行失败的操作,而不是做有用功。
•如果后一个显著次数的重试请求仍然失败,则可能是更好的应用程序,以防止进一步的请求将要在相同的资源为一个周期,并简单地立即报告故障。当期限届满后,该应用程序可以暂时允许通过一个或多个请求,看看他们是否成功。对于这一策略的详细信息,请参阅断路器格局。
•在由它实现了一个重试策略可能需要为幂等的应用程序调用的服务的操作。例如,发送到服务的请求可以被接收和处理成功,但是,由于瞬时故障,它可能无法发送响应,指示该处理已完成。然后在应用程序的重试逻辑可能试图重复上没有接收到所述第一请求的假定该请求。
•一个请求到服务失败可能由于各种原因而提出不同的异常,根据故障的性质。一些例外可指示故障,可以非常迅速地得到解决,而另一些可能表明该故障持续时间更长。可能是有益的重试策略,调整基于所述异常的类型的重试尝试之间的时间。
•考虑如何重试的操作是事务的一部分,会影响整体交易的一致性。这可能是有用的微调对于事务性操作的重试政策,最大限度地取得成功的机会,并减少需要撤消所有交易步骤。
•确保所有重试代码是完全针对各种故障条件下进行测试。检查它不会严重影响应用程序的性能或可靠性,导致在服务和资源的过度负荷,或产生竞态条件或瓶颈。
•实现只在一个失败的操作的全方面了解重试逻辑。例如,如果包含的重试策略任务调用另一个任务还包含一个重试策略,这个额外的重试的层可加长的延迟的处理。它可能是更好的配置的低级任务失败快速并报告失败返回调用它的任务的原因。然后这个更高级别的任务可以决定如何处理是根据它自己的策略失效。
•记录所有的连接故障,提示了重试,使潜在的问题与该应用程序,服务或资源可以被识别是很重要的。
•研究是最有可能发生于一个服务或资源发现,如果它们有可能是持久或终端的故障。如果是这样的话,它可能是更好地处理该故障为异常。该应用程序可以报告或记录该异常,然后试图通过调用另一个服务,持续或者(如果有一个可用的),或通过提供降级功能。关于如何检测和处理持久故障的更多信息,请参阅断路器格局。

何时使用这个模式

使用这种模式:
•当一个应用程序可能会经历短暂的故障,因为它与远程服务进行交互,或访问远程资源。这些故障预计将是短暂的,并重复了以前没有能够成功的后续尝试的请求。

这种模式可能不适合:
•当故障很可能是持久的,因为这可能会影响应用程序的响应性。该应用程序可以简单地是浪费时间和资源试图重复请求是最有可能失败。
•对于处理故障是不因瞬时故障,如在应用程序的业务逻辑引起错误的内部的异常。
•作为一种替代解决系统中的可扩展性问题。如果一个应用程序有频繁的“忙”的故障,这是通常指示被访问的服务或资源应相应加大。

例子

本实施例说明的重试模式的实现。该OperationWithBasicRetryAsync方法,如下所示,通过TransientOperationAsync方法异步调用外部服务(该方法的细节将特定于服务,并从样本代码被省略)。

private int retryCount = 3;
...

public async Task OperationWithBasicRetryAsync()
{
  int currentRetry = 0;

  for (; ;)
  {
    try
    {
      // Calling external service.
      await TransientOperationAsync();

      // Return or break.
      break;
    }
    catch (Exception ex)
    {
      Trace.TraceError("Operation Exception");

      currentRetry++;

      // Check if the exception thrown was a transient exception
      // based on the logic in the error detection strategy.
      // Determine whether to retry the operation, as well as how
      // long to wait, based on the retry strategy.
      if (currentRetry > this.retryCount || !IsTransient(ex))
      {
        // If this is not a transient error
        // or we should not retry re-throw the exception.
        throw;
      }
    }

    // Wait to retry the operation.
    // Consider calculating an exponential delay here and
    // using a strategy best suited for the operation and fault.
    Await.Task.Delay();
  }
}

// Async method that wraps a call to a remote service (details not shown).
private async Task TransientOperationAsync()
{
  ...
}

调用此方法的声明被包裹在一个循环一个try/
catch块中封装。如果调用TransientOperationAsync方法成功,没有抛出异常的for循环退出。如果TransientOperationAsync方法失败,catch块检查为失败的原因,并且如果它被认为是一个瞬时错误代码等待一个短暂的延时,然后重试该操作。

在for循环还跟踪该操作已经尝试的次数,并且如果代码失败三次异常被认为是更持久。如果该异常是不是暂时的,或者是长久的,catch处理抛出的异常。此异常退出for循环,应捕获调用该OperationWithBasicRetryAsync方法的代码。

该IsTransient方法,如下所示,检查是否有特定的一组是相关的,其中所述代码运行的环境的异常。一过异常的定义可以根据被访问的资源,并在其上执行的操作环境的不同而不同。

private bool IsTransient(Exception ex)
{
  // Determine if the exception is transient.
  // In some cases this may be as simple as checking the exception type, in other
  // cases it may be necessary to inspect other properties of the exception.
  if (ex is OperationTransientException)
    return true;

  var webException = ex as WebException;
  if (webException != null)
  {
    // If the web exception contains one of the following status values
    // it may be transient.
    return new[] {WebExceptionStatus.ConnectionClosed,
                  WebExceptionStatus.Timeout,
                  WebExceptionStatus.RequestCanceled }.
            Contains(webException.Status);
  }

  // Additional exception checking logic goes here.
  return false;
}

 

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

时间: 2024-10-25 18:14:43

云计算设计模式(十八)——重试模式的相关文章

设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述         在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查找.排序等,一种常用的方法是硬编码(Hard Coding)在一个类中,如需要提供多种查找算法,可以将这些算法写到一个类中,在该类中提供多个方法,每一个方法对应一个具体的查找算法:当然也可以将这些查找算法封装在一个统一的方法中,通过if-else-或者case等条件判断语

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

云计算设计模式(八)--外部配置存储模式 移动配置信息从应用部署包到一个集中位置.这个模式可以提供机会,以便管理和配置数据的控制,以及用于跨应用程序和应用程序实例共享的配置数据. 背景和问题 大多数应用程序运行时环境包括位于应用程序文件夹内的在部署应用程序文件保持配置信息.在某些情况下也能够编辑这些文件来改变该应用程序的行为,它已经被部署之后.然而,在许多情况下,改变配置所需要的应用程序被重新部署,从而导致不可接受的停机时间和额外的管理开销. 本地配置文件还配置限制为单个应用程序,而在某些情况下

设计模式 ( 十九 ) 模板方法模式Template method(类行为型)

设计模式 ( 十九 ) 模板方法模式Template method(类行为型) 1.概述 在面向对象开发过程中,通常我们会遇到这样的一个问题:我们知道一个算法所需的关键步骤,并确定了这些步骤的执行顺序.但是某些步骤的具体实现是未知的,或者说某些步骤的实现与具体的环境相关. 例子1:银行业务办理流程 在银行办理业务时,一般都包含几个基本固定步骤: 取号排队->办理具体业务->对银行工作人员进行评分. 取号取号排队和对银行工作人员进行评分业务逻辑是一样的.但是办理具体业务是个不相同的,具体业务可能

设计模式的解析和实现(C++)之十八-Iterator模式

作用: 提供一种方法顺序访问一个聚合对象中各个元素,,而又不需暴露该对象的内部表示. UML结构图: 解析: Iterator几乎是大部分人在初学C++的时候就无意之中接触到的第一种设计模式,因为在STL之中,所有的容器类都有与之相关的迭代器.以前初学STL的时候,时常在看到讲述迭代器作用的时候是这么说的:提供一种方式,使得算法和容器可以独立的变化,而且在访问容器对象的时候不必暴露容器的内部细节,具体是怎么做到这一点的呢?在STL的实现中,所有的迭代器(Iterator)都必须遵照一套规范,这套

设计模式 ( 十四 ) 迭代器模式Iterator(对象行为型)

1.概述 类中的面向对象编程封装应用逻辑.类,就是实例化的对象,每个单独的对象都有一个特定的身份和状态.单独的对象是一种组织代码的有用方法,但通常你会处理一组对象或者集合. 集合不一定是均一的.图形用户界面框架中的 Window 对象可以收集任意数量的控制对象 - Menu.Slider 和 Button.并且,集合的实现可以有多种方式:PHP 数字是一个集合,但也是一个散列表,一个链接列表,一个堆栈以及队列. 例子1:电视遥控器的频道遍历 2.问题 如何操纵任意的对象集合?  如一个列表(Li

云计算设计模式(十九)——运行重构模式

云计算设计模式(十九)--运行重构模式 设计应用程序,使得它可以在不需要重新部署或者重新启动应用程序重新配置.这有助于保持可用性并减少停机时间. 背景和问题 一个主要目的为重要的应用,如商业和企业网站是尽量减少停机时间以及由此引发的中断给客户和用户.但是,有时有必要重新配置应用程序改变特定行为或设置,而在部署和使用.因此,它是用于该应用程序被设计成这样一种方式,以允许在运行时要应用这些配置的变化,并为应用程序,以检测所述变化并且尽快地应用它们的部件的优点. 该种要应用可能被调整记录,以协助与应用

云计算设计模式(二十)——调度程序代理管理者模式

云计算设计模式(二十)--调度程序代理管理者模式 协调一系列在分布式服务集和其他远程资源的的行为,试图透明地处理故障,如果这些操作失败,或撤销,如果系统不能从故障中恢复执行工作的影响.这种模式可以分布式系统中增加弹性和灵活性,使之恢复和重试失败是由于短暂的异常,持久的故障和处理故障等操作. 背景和问题 应用程序执行其包括多个步骤,其中的一些可以调用远程服务或访问远程资源的任务.各个步骤可以是相互独立的,但它们是由实现该任务的应用程序逻辑编排. 只要有可能,应用程序应该确保任务运行完成和解决远程访

云计算设计模式(十五)——管道和过滤器模式

云计算设计模式(十五)--管道和过滤器模式 分解,执行复杂处理成一系列可重复使用分立元件的一个任务.这种模式可以允许执行的处理进行部署和独立缩放任务元素提高性能,可扩展性和可重用性. 背景和问题 一个应用程序可能需要执行各种关于它处理的信息不同复杂的任务.一个简单,但不灵活的方式来实施这个应用程序可以执行此处理为单一模块.然而,这种方法有可能减少用于重构代码,对其进行优化,或者重新使用它,如果是在应用程序中其他地方所需要的相同的处理的部件的机会. 图1通过使用单片式的方式示出了与处理数据的问题.

云计算设计模式(十六)——优先级队列模式

云计算设计模式(十六)--优先级队列模式 优先发送到服务,以便具有较高优先级的请求被接收和高于一个较低优先级的更快速地处理请求.这种模式是在应用程序是有用的,它提供不同的服务级别保证或者针对独立客户. 背景和问题 应用程序可以委托给其他服务的具体任务;例如,为了执行后台处理或与其他应用程序或服务的整合.在云中,消息队列通常用于将任务委派给后台处理.在许多情况下,请求由服务接收的顺序是不重要的.然而,在某些情况下,可能需要优先考虑的具体要求.这些要求必须早于较低优先级的其他可能先前已发送由应用程序