什么是程序设计里的 backoff pattern

Posted JerryWangSAP

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了什么是程序设计里的 backoff pattern相关的知识,希望对你有一定的参考价值。

Backoff pattern 是一种程序设计模式,通常用于处理因高负载或故障而导致的请求失败或错误。该模式基于一种简单的策略,即当请求失败时,等待一段时间后重试,等待时间逐渐增加,直到成功或达到最大重试次数为止。

在实际应用中,Backoff pattern 通常会包含以下几个要素:

初始等待时间:在第一次重试之前等待的时间,通常是一个较短的固定时间。

等待时间递增因子:每次重试时等待时间的增加因子,通常是一个固定的倍数或增量。

最大等待时间:达到该等待时间后不再进行重试,防止过度等待或死循环。

最大重试次数:达到该重试次数后停止重试,防止无限重试或死循环。

Backoff pattern 的优点是能够在高负载或故障情况下有效地处理请求失败,并减轻服务器负载。然而,该模式也存在一些缺点,例如可能会导致响应时间变慢,因为每次失败都需要等待一段时间后才会重试,并且需要在客户端上实现复杂的逻辑来处理重试。

一个简单的实现 Backoff pattern 的例子可以是以下的伪代码:

def make_request():
    retries = 0
    while retries < MAX_RETRIES:
        try:
            response = send_request()
            return response
        except Exception as e:
            if retries == MAX_RETRIES - 1:
                raise e
            retries += 1
            wait_time = INITIAL_WAIT_TIME * (BACKOFF_FACTOR ** retries)
            wait_time = min(wait_time, MAX_WAIT_TIME)
            time.sleep(wait_time)

Spartacus 里的 backoff 机制的一个例子:

下面是一个使用 Angular HttpClient 实现 backoff pattern 的 TypeScript 代码示例:

import  Injectable  from \'@angular/core\';
import  HttpClient  from \'@angular/common/http\';
import  Observable, throwError  from \'rxjs\';
import  retryWhen, delay, take, mergeMap  from \'rxjs/operators\';

@Injectable(
  providedIn: \'root\'
)
export class DataService 

  constructor(private http: HttpClient)  

  getData(url: string): Observable<any> 
    return this.http.get(url).pipe(
      retryWhen(errors => errors.pipe(
        // 每秒重试一次,最多重试 3 次
        delay(1000),
        take(3),
        // 如果是 500 错误,则进行重试
        mergeMap(response => 
          if (response.status === 500) 
            return throwError(response);
          
          return response;
        )
      ))
    );
  


在这个示例中,我们定义了一个名为 DataService 的服务,该服务使用 Angular HttpClient 来获取数据。我们使用 retryWhen 操作符来实现 backoff pattern,它将在发生错误时重试 HTTP 请求。

在 retryWhen 中,我们使用 delay 操作符来指定每次重试之间的延迟时间,这里设置为 1000 毫秒。我们还使用 take 操作符来指定最大重试次数,这里设置为 3 次。

在 mergeMap 操作符中,我们检查响应的状态码是否为 500。如果是,我们使用 throwError 操作符将错误抛出,触发 retryWhen 中的重试逻辑。如果响应状态码不是 500,则直接返回响应。

因此,这个示例中的 backoff pattern 实现了在 HTTP 请求失败时进行重试,最多重试 3 次,每次重试之间延迟 1 秒。

菜鸟理解的工厂模式(Factory Pattern)是什么样子的?

直接开始说了,不浪费园友宝贵的时间!

什么是工厂模式?

 

  在学习前,先问一下:“它是什么?”。

  工厂模式,它是项目里面常用的设计模式之一。

  它是属于创建型模式,简单的理解创建型模式就是将实例化工作交给另外一个对象来完成。

  工厂模式(又称静态工厂模式 Static Factory Method),它算是软件设计模式中最简单的模式了。  

为了解决什么问题?

 

  工厂模式使代码清晰,降低耦合度,调用者通过 接口/抽象类来获得想要的实例化,而无需关心细节上是如何实现的。

  工厂模式是一种典型的解耦模式,迪米特法则在工厂模式中表现的尤为明显。

  (说的比较简单,看了多个网站与博客,我个人认为这句话是工厂模式要解决的最根本的问题,如果有兴趣,可以去看一下其它文章。)

 

什么时候使用?

 

  工厂模式属于创建类模式,在同的条件下创建不同的对象实例时,可以使用工厂方法模式。

  简单的对象,特别是只需要通过new就可以完成创建的对象,无需使用工厂模式。(就是复杂的时候才用工厂,简单不需要用,反而增加程序的复杂度。)

 

实践加深理解:

 

  我请大家去饭店吃饭,有东北菜(我是东北yin),浙江菜,北京菜等等等等,我把你们带进饭店,然后点了东北菜。这个过程,其实就是工厂模式的一种实现。

  首先,不管它是什么菜系的饭店,首先它必须是个“饭店”,必须会做菜(简单描述一下),以下是代码实践过程。

  

  一、我们创建一个饭店的接口类,里面只有一个动作,用来规定所有饭店都必须会做菜!!!

    /// <summary>
    /// 饭店接口类
    /// </summary>
    public interface IRestaurants
    {

        /// <summary>
        ///  每个饭店必须会做饭
        /// </summary>
        /// <returns></returns>
        string Cook();
    }
View Code

  二、接下来创建几个菜系的具体饭店。

    /// <summary>
    /// 北京饭店
    /// </summary>
    class Beijing : IRestaurants
    {
        public string Cook()
        {
            return "给你北京菜";
        }
    }
View Code
    /// <summary>
    /// 东北饭店
    /// </summary>
    class Dongbei : IRestaurants
    {
        public string Cook()
        {
            return "给你东北菜";
        }
    }
View Code
    /// <summary>
    /// 浙江饭店
    /// </summary>
    class Zhejiang : IRestaurants
    {
        public string Cook()
        {
            return "给你浙江菜";
        }
    }
View Code

  三、菜馆有了,接下来这个就是简单工厂模式里的重点了。如何让这些饭店能够正确的给我上菜呢?(如果读者说去东北饭店肯定不能给上北京菜,那请您出门右拐,跪哭!!!)

    这时就需要有个“工厂”来协助我要告诉什么饭店做菜了(创建哪个饭店的实例)。

    /// <summary>
    /// 饭店工厂类,根据名字创建饭店的实例。
    /// </summary>
    public class RestaurantSimpleFactory
    {
        public IRestaurants GiveMe(string name)
        {
            switch (name)
            {
                case "Dongbei":
                    return new Dongbei();
                case "Beijing":
                    return new Beijing();
                case "Zhejiang":
                    return new Zhejiang();
                default:
                    return new Dongbei();
            }
        }
    }
View Code

  四、准备工作完毕,可以上菜了。

    public class Program
    {
        static void Main(string[] args)
        {
            //创建饭店工厂实例
            var restaurantSimpleFactory = new RestaurantSimpleFactory();
            //使用饭店接口招收实现它的饭店实例
            IRestaurants restaurant = restaurantSimpleFactory.GiveMe("Dongbei");
            string cookWhat = restaurant.Cook();
            Console.WriteLine("饭店:" + cookWhat);
            Console.ReadLine();
        }
    }
View Code

 


 

图解:这是根据我个人的理解画的导图,可能与网络上大牛们的不太一样。

 

 


Tag:简单工厂中还包含了另一种实现,“工厂方法”,接下来深入学习一下。

如果我的理解有误,想喷就喷没关系,别骂我就好!可能在您的愤怒中会学习到我没有理解的。谢谢观看!

以上是关于什么是程序设计里的 backoff pattern的主要内容,如果未能解决你的问题,请参考以下文章

聊聊cortex的Backoff

supervisor控制台运行出错,BACKOFF Exited too quickly

FlinkFlink 消费 kafka retries和retry.backoff.ms 引起问题

python http requests失败重试方法, 退避算法(Retrying HTTP Requests with Backoff)

python http requests失败重试方法, 退避算法(Retrying HTTP Requests with Backoff)

AWS 中的错误重试和指数退避 Error Retries and Exponential Backoff in AWS