The best index retry is retracted and jitter

1 Overview

In this tutorial, we will explore how to use two different strategies to improve client retries: exponential back and jitter.

2. Retry

In a distributed system, the network communication between a plurality of component failures may occur at any time.

Client applications by enabling retrying to deal with these failures.

Imagine a client application we have a remote service call - PingPongService .

interface PingPongService {
    String call(String ping) throws PingPongServiceException;
}

If PingPongService return a PingPongServiceException , the client application must be retried. In the following options which we will consider ways to achieve the client retries.

3. Resilience4j Retry

In our example, we will use Resilience4j library, especially its retry module. We need to add resilience4j-retry module to pom.xml :

<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-retry</artifactId>
</dependency>

Review on retried, do not forget to check out our Resilience4j guidelines .

4. Exponential Back

The client application must be responsible to implement and try again. When the case of the client without waiting for the call failed retry , they may cause the system overwhelmed, and has led to further downgrade the beleaguered service.

Exponential back-off is a common policy processing failed retries network calls. Briefly, the client wait between successive retries and longer time interval:

wait_interval = base * multiplier^n

among them,

  • base is the initial interval, i.e., waiting for the first retry
  • n is the number of failures has occurred
  • multiplier is an arbitrary multiplier can be replaced with any suitable value

In this way, we provide a breathing space for the system to recover from a failure or intermittent problems more severe in.

We can use Resilience4j retry exponential backoff algorithm, by configuring its IntervalFunction , the function accepts initialInterval and multiplier The .

Retry mechanism using IntervalFunction as a sleep function:

IntervalFunction intervalFn =
  IntervalFunction.ofExponentialBackoff(INITIAL_INTERVAL, MULTIPLIER);

RetryConfig retryConfig = RetryConfig.custom()
  .maxAttempts(MAX_RETRIES)
  .intervalFunction(intervalFn)
  .build();
Retry retry = Retry.of("pingpong", retryConfig);

Function<String, String> pingPongFn = Retry
    .decorateFunction(retry, ping -> service.call(ping));
pingPongFn.apply("Hello");

Let's simulate a real-world scenario, suppose we have several clients simultaneously call PingPongService :

ExecutorService executors = newFixedThreadPool(NUM_CONCURRENT_CLIENTS);
List<Callable> tasks = nCopies(NUM_CONCURRENT_CLIENTS, () -> pingPongFn.apply("Hello"));
executors.invokeAll(tasks);

Let's look at NUM_CONCURRENT_CLIENTS = remote call logs 4:

[thread-1] At 00:37:42.756
[thread-2] At 00:37:42.756
[thread-3] At 00:37:42.756
[thread-4] At 00:37:42.756

[thread-2] At 00:37:43.802
[thread-4] At 00:37:43.802
[thread-1] At 00:37:43.802
[thread-3] At 00:37:43.802

[thread-2] At 00:37:45.803
[thread-1] At 00:37:45.803
[thread-4] At 00:37:45.803
[thread-3] At 00:37:45.803

[thread-2] At 00:37:49.808
[thread-3] At 00:37:49.808
[thread-4] At 00:37:49.808
[thread-1] At 00:37:49.808

Here we can see a clear pattern - the client waits for the exponential growth of the interval, but in each retry (conflict), they invoke a remote service at the same time.

img

We only solves part of the problem - we do not restart the remote service, however, replaced over time spread out the workload, we work more interval, idle longer. This behavior is similar to the thundering herd problem .

5. Introduction Jitter

In our previous method, the client waiting time gradually longer, but still are synchronized. Add jitter to provide a way to interrupt synchronization across clients, in order to avoid conflict. In this method, we have to wait for a random interval increases.

wait_interval = (base * 2^n) +/- (random_interval)

Which, random_interval is added (or subtracted) to break the synchronization between the client.

We will not go into the computer system of random intervals, but must be separated peak randomized space to smoother distribution of client calls.

We can configure a random backoff index IntervalFunction , it also accepts a randomizationFactor , so Resilience4j retry with jitter using an exponential backoff:

IntervalFunction intervalFn = 
  IntervalFunction.ofExponentialRandomBackoff(INITIAL_INTERVAL, MULTIPLIER, RANDOMIZATION_FACTOR);

Let's go back to our real scene, and view the log with a shake of the remote call:

[thread-2] At 39:21.297
[thread-4] At 39:21.297
[thread-3] At 39:21.297
[thread-1] At 39:21.297

[thread-2] At 39:21.918
[thread-3] At 39:21.868
[thread-4] At 39:22.011
[thread-1] At 39:22.184

[thread-1] At 39:23.086
[thread-5] At 39:23.939
[thread-3] At 39:24.152
[thread-4] At 39:24.977

[thread-3] At 39:26.861
[thread-1] At 39:28.617
[thread-4] At 39:28.942
[thread-2] At 39:31.039

Now we have a better spread. We have to eliminate conflicts and free time, and an almost constant rate of client calls end, unless the initial surge occurs.

img

Note: We exaggerate the interval illustrations, in reality, we will have a smaller gap.

6 Conclusion

In this tutorial, we explore how to increase the use of dithering method exponential backoff to improve client applications to retry failed calls. Source code of this example can be used in tutorial GitHub found on.

Original: https://www.baeldung.com/resilience4j-backoff-jitter

Author: Priyank Srivastava

Translator: Queena

September welfare, public concern number backstage reply: 004, receive translations in August highlights! Go on welfare Re: 001, 002, 003 can receive!



img

Guess you like

Origin www.cnblogs.com/liululee/p/11569565.html