Inleiding
In softwareontwikkeling is betrouwbare retry-logica essentieel voor het omgaan met intermitterende storingen, zoals netwerkproblemen of tijdelijke uitval. Onlangs kwam ik een codebase tegen waarin een ontwikkelaar een for
lus gebruikte met een vaste tijdsinterval om mislukte bewerkingen opnieuw te proberen. Hoewel deze aanpak eenvoudig lijkt, mist ze de veerkracht die nodig is voor toepassingen in de echte wereld. Daar komt Exponential Backoff om de hoek kijken—een strategie die is ontworpen om opnieuw proberen slimmer en efficiënter te maken.
In dit artikel bekijken we hoe Exponential Backoff werkt, de voordelen ten opzichte van een basis retry-lus en hoe je het kunt implementeren om de betrouwbaarheid van je systeem te vergroten. Ik zal je ook door een praktisch voorbeeld leiden met behulp van een e-mailverzendmodule, waarin ik laat zien hoe je Exponential Backoff kunt gebruiken om een meer veerkrachtige foutafhandeling te waarborgen.
Wat is Exponential Backoff?
Exponential Backoff is een retry-strategie waarbij de wachttijd tussen herhaalpogingen exponentieel toeneemt na elke mislukking. In plaats van op vaste intervallen opnieuw te proberen, wacht elke volgende poging langer dan de vorige—typisch verdubbelt de vertraging elke keer. Bijvoorbeeld, als de initiële vertraging 1 seconde is, zullen de volgende herhalingen plaatsvinden na 2, 4, 8 seconden, enzovoort. Deze aanpak helpt de belasting van het systeem te verminderen en minimaliseert het risico om externe services te overweldigen tijdens drukke periodes.
Door meer tijd tussen herhalingen toe te staan, geeft Exponential Backoff tijdelijke problemen de kans om op te lossen, wat leidt tot een efficiëntere foutafhandeling en verbeterde stabiliteit van de applicatie.
Voordelen en nadelen van Exponential Backoff
Voordelen:
-
Verminderde Systeembelasting: Door herhalingen te spreiden, minimaliseert Exponentiële Terugval de kans op overbelasting van servers, wat vooral nuttig is voor het omgaan met snelheidslimieten of tijdelijke storingen.
-
Efficiënte Foutafhandeling: De toenemende vertraging geeft tijdelijke problemen meer tijd om natuurlijk op te lossen, waardoor de kans op een succesvolle herhaling verbetert.
-
Verbeterde Stabiliteit: Vooral voor systemen met veel verkeer voorkomt het een vloed van herhalingspogingen, waardoor applicaties soepel blijven draaien zonder overmatige hulpbronnen te verbruiken.
Nadelen:
- Verhoogde Latentie: Met elke herhaling die steeds langer duurt, kan Exponentiële Terugval leiden tot vertragingen, vooral als er veel herhalingen nodig zijn voordat er succes is.
Belangrijke Toepassingsgevallen voor Exponentiële Terugval
Exponentiële Terugval is bijzonder nuttig in scenario’s waar systemen interactie hebben met externe diensten of grote hoeveelheden verkeer beheren. Hier zijn enkele andere veelvoorkomende gebruiksgevallen:
-
Rate-Limited APIs: Sommige API’s hebben snelheidslimieten, waardoor verzoeken binnen een bepaalde tijd worden beperkt. Exponential Backoff helpt om directe herhalingen te vermijden die de limiet zouden kunnen overschrijden, door tijd te geven om de limiet te resetten.
-
Netwerkinstabiliteit: In geval van tijdelijke netwerkstoringen of time-outs helpt exponentiële vertraging door langer te wachten tussen pogingen, waardoor het netwerk kan stabiliseren.
-
Databaseverbindingen: Bij het verbinden met databases onder zware belasting helpt exponentiële vertraging door verdere overbelasting te voorkomen door herhalingen te vertragen, waardoor de database tijd heeft om te herstellen.
-
Wachtrij-systemen: In berichtenwachtrij-systemen, als een bericht mislukt vanwege een fout, kan het gebruik van Exponential Backoff voor herhalingen voorkomen dat er snel opnieuw wordt verwerkt en tijd geven om tijdelijke problemen op te lossen.
Bouwen van een Basis E-mail Verzenderservice met Exponentiële Backoff
Om Exponentiële Backoff te demonstreren, bouwen we een basis e-mail verzender die opnieuw probeert e-mails te verzenden als er een fout optreedt. Dit voorbeeld laat zien hoe Exponentiële Backoff het herhaalproces verbetert in vergelijking met een eenvoudige for-loop.
import nodemailer from "nodemailer";
import { config } from "../common/config";
import SMTPTransport from "nodemailer/lib/smtp-transport";
const emailSender = async (
subject: string,
recipient: string,
body: string
): Promise<boolean> => {
const transport = nodemailer.createTransport({
host: config.EMAIL_HOST,
port: config.EMAIL_PORT,
secure: true,
auth: { user: config.EMAIL_SENDER, pass: config.EMAIL_PASSWORD },
} as SMTPTransport.Options);
const mailOptions: any = {
from: config.EMAIL_SENDER,
to: recipient,
subject: subject,
};
const maxRetries = 5; // maximum number of retries before giving up
let retryCount = 0;
let delay = 1000; // initial delay of 1 second
while (retryCount < maxRetries) {
try {
// send email
await transport.sendMail(mailOptions);
return true;
} catch (error) {
// Exponential backoff strategy
retryCount++;
if (retryCount < maxRetries) {
const jitter = Math.random() * 1000; // random jitter(in seconds) to prevent thundering herd problem
const delayMultiplier = 2
const backOffDelay = delay * delayMultiplier ** retryCount + jitter;
await new Promise((resolve) => setTimeout(resolve, backOffDelay));
} else {
// Log error
console.log(error)
return false; // maximum number of retries reached
}
}
}
return false;
};
Afstemmen van Exponentiële Backoff Parameters
Het implementeren van Exponentiële Backoff omvat het aanpassen van bepaalde parameters om ervoor te zorgen dat de herhaalstrategie goed werkt voor de behoeften van uw applicatie. De volgende belangrijke parameters beïnvloeden het gedrag en de prestaties van Exponentiële Backoff in een herhaalmechanisme:
- Initiële Vertraging
-
Doel: Stelt de wachttijd in vóór de eerste herhaling. Het moet lang genoeg zijn om onmiddellijke herhalingen te voorkomen, maar kort genoeg om merkbare vertragingen te vermijden.
-
Aanbevolen Instelling: Begin met een vertraging tussen 500 ms en 1000 ms. Voor kritieke systemen, gebruik een kortere vertraging, terwijl minder dringende operaties een langere vertraging kunnen hebben.
- Vertraging Vermenigvuldiger
-
Doel: Beheert hoe snel de vertraging toeneemt na elke poging. Een vermenigvuldiger van 2 verdubbelt de vertraging (bijv. 1s, 2s, 4s).
-
Aangeraden Instelling: Gewoonlijk balanceert een vermenigvuldiger tussen 1.5 en 2 responsiviteit en stabiliteit. Hogere vermenigvuldigers (bijv. 3) kunnen geschikt zijn als het systeem langere vertragingen tussen pogingen kan verwerken.
- Maximale Pogingen
-
Doel: Beperkt het aantal pogingen om overmatige herhalingen te voorkomen die middelen kunnen uitputten of de systeembelasting kunnen verhogen.
-
Aangeraden Instelling: Een bereik van 3 tot 5 pogingen is meestal voldoende voor de meeste toepassingen. Daarboven kan de operatie als mislukt moeten worden gelogd of anders beheerd, bijvoorbeeld door de gebruiker te waarschuwen of een melding te activeren.
- Jitter (Randomisatie)
-
Doel: Voegt willekeurigheid toe aan elke vertraging om te voorkomen dat pogingen zich clusteren en een “thundering herd” effect veroorzaken.
-
Aanbevolen Instelling: Voeg een willekeurige vertraging tussen 0 en 500 ms toe aan elk herhalingsinterval. Deze jitter helpt om de pogingen gelijkmatiger over de tijd te spreiden.
Conclusie
Door Exponential Backoff te gebruiken, voeg je veerkracht toe aan je applicatie, waardoor deze voorbereid is om onverwachte problemen aan te pakken. Het is een kleine verandering met een grote impact, vooral naarmate je applicatie groeit.
En dat is het voor nu, jongens. Voel je vrij om een opmerking achter te laten en vragen te stellen als je die hebt. Proost op het bouwen van betrouwbaardere en veerkrachtigere apps.
Vrolijk coderen! 👨💻❤️
Source:
https://timothy.hashnode.dev/implementing-exponential-backoff-for-reliable-systems