Wie Sie wiederholen, ohne einen Sturm auszulösen
Ein Limit ist eine Regel: Ein Dienst nimmt in kurzer Zeit nur so viele Aufrufe an. Eine Wiederholung ist ein zweiter Versuch, nachdem ein Aufruf abgelehnt wurde. Eine unbedachte Wiederholung kann eine Überlastung verschlimmern.
Das Modul über Kosten, Tracing und Zuverlässigkeit wiederholt einmal und weicht dann aus. Diese Lektion geht weiter: wachsende Wartezeiten, eine Streuung, damit Aufrufer nicht im Gleichschritt kommen, begrenzte Versuche und eine Wiederholung, die sich gefahrlos wiederholen lässt.
Am Ende dieser Lektion
Notiz
Ich kann einen Aufruf wiederholen, ohne einen Sturm auszulösen.
Schlüsselwörter
| Begriff | Was er bedeutet | Beispiel |
|---|---|---|
| Limit | die meisten Aufrufe, die ein Dienst in einem Zeitfenster annimmt | |
| Backoff | eine Wartezeit, die nach jedem Fehlversuch wächst (so heißt das Verfahren auch auf Deutsch) | 400, 800, 1600 |
| Streuung | eine kleine, für jeden Aufrufer andere Wartezeit | |
| Sturm | viele Aufrufer, die im selben Moment wiederholen | |
| Idempotent | gefahrlos wiederholbar: zweimal tun wirkt wie einmal | |
| Simulierte Uhr | eine Zahl, die wir von Hand weiterschieben, statt zu warten |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Wie ein Limit zählt
Der Dienst teilt die Zeit in Fenster von 1000 Millisekunden. In jedem Fenster nimmt er eine feste Zahl Aufrufe an, hier 2. Den Rest lehnt er ab, bis das nächste Fenster beginnt.
Die Zeit ist hier eine Zahl, die wir von Hand weiterschieben. Nichts wartet, also gibt jeder Lauf dieselbe Antwort.
Durchgerechnetes Beispiel: 2 Aufrufe je Fenster
| Zeit (ms) | Fenster | Schon angenommene Aufrufe | Ergebnis |
|---|---|---|---|
| 0 | 0 | 0 | Angenommen |
| 0 | 0 | 1 | Angenommen |
| 0 | 0 | 2 | Abgelehnt, das Fenster ist voll |
| 400 | 0 | 2 | Wieder abgelehnt |
| 1200 | 1 | 0 | Angenommen, ein neues Fenster |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Ein häufiger Fehler
Warnung
Viele denken, sofort zu wiederholen sei der schnellste Weg zu einer Antwort. Ist der Dienst überlastet, erhöht jede sofortige Wiederholung die Last, und es wird für alle schlechter. Warten Sie zuerst, und jedes Mal länger.
Backoff und Streuung
Ein Backoff ist eine Wartezeit, die sich verdoppelt. Bei der Basis 400 sind die Zeiten 400, 800, 1600. Setzen Sie eine Obergrenze, hier 2000, sonst wachsen die Zeiten ohne Ende.
Scheitern sechs Aufrufer gemeinsam und warten alle 400, kommen sie auch gemeinsam zurück. Eine Streuung addiert für jeden eine kleine andere Zahl, sodass sie einzeln zurückkehren.
Durchgerechnetes Beispiel: Basis 400, Grenze 2000
| Fehlversuch | Backoff | Streuung für Anfrage 3 | Nächster Versuch bei (ab 0) |
|---|---|---|---|
| 1 | 400 | 34 | 434 |
| 2 | 800 | 47 | 1281 (ab 434) |
| 3 | 1600 | 10 | 2891 (ab 1281) |
| 4 | 2000, die Grenze | Nicht genutzt | Aufgeben, wenn die Versuche 4 sind |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.
Eine Wiederholung muss sich gefahrlos wiederholen lassen
Manchmal hat ein Aufruf funktioniert, aber die Antwort ging auf dem Rückweg verloren. Der Aufrufer glaubt an einen Fehler und versucht es erneut. Bucht oder sendet die Wiederholung wieder etwas, ist es zweimal geschehen.
Geben Sie jeder Handlung einen Schlüssel. Der Server merkt sich die Schlüssel, die er kennt. Eine Wiederholung mit bekanntem Schlüssel bewirkt nichts Neues.
Die Modellhilfe schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const basis = process.env.AI_URL || \"http://ai:4000\";' '// Die Token einer Antwort oder null, wenn sie keine nennt.' 'function zaehlen(daten, name) {' ' return daten.usage && typeof daten.usage[name] === \"number\" ? daten.usage[name] : null;' '}' > model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Modellhilfe schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function fragen(nachrichten, probe, max) {' ' try {' ' const res = await fetch(basis + \"/v1/chat/completions\", {' ' method: \"POST\",' ' headers: { \"content-type\": \"application/json\", authorization: \"Bearer lab\" },' ' body: JSON.stringify({ model: \"lab\", messages: nachrichten, max_tokens: max || 100 }),' ' signal: AbortSignal.timeout(30000),' ' });' ' if (res.ok === false) throw new Error(\"Status \" + res.status);' ' const d = await res.json();' ' return { text: d.choices[0].message.content, eingabe: zaehlen(d, \"prompt_tokens\"), ausgabe: zaehlen(d, \"completion_tokens\"), aufgezeichnet: false };' ' } catch (fehler) {' ' console.log(\"Aufgezeichnete Probe: Kein Modell hat geantwortet (\" + fehler.message + \").\");' ' return { text: probe, eingabe: null, ausgabe: null, aufgezeichnet: true };' ' }' '}' 'module.exports = { fragen };' >> model.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Wiederholungs-Skript schreiben, Teil 1
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'const { fragen } = require(\"./model\");' 'function wartezeit(versuch, basis, grenze) { return Math.min(basis * Math.pow(2, versuch - 1), grenze); }' 'function streuung(nummer, versuch) { return (nummer * 7 + versuch * 13) % 50; }' 'function durchlauf(anzahl, limit, fenster, basis, grenze, versuche, streuenAn) {' ' const offen = [];' ' const verlauf = {};' ' const zaehler = {};' ' for (let n = 1; n <= anzahl; n++) { offen.push([0, n, 1]); verlauf[n] = []; }' > wiederholen.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Wiederholungs-Skript schreiben, Teil 2
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' while (offen.length > 0) {' ' offen.sort(function (a, b) { return a[0] - b[0] || a[1] - b[1] || a[2] - b[2]; });' ' const eintrag = offen.shift();' ' const platz = Math.floor(eintrag[0] / fenster);' ' verlauf[eintrag[1]].push(eintrag[0]);' >> wiederholen.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Wiederholungs-Skript schreiben, Teil 3
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' zaehler[platz] = zaehler[platz] || 0;' ' if (zaehler[platz] < limit) { zaehler[platz] = zaehler[platz] + 1; continue; }' ' if (eintrag[2] < versuche) {' ' const extra = streuenAn ? streuung(eintrag[1], eintrag[2]) : 0;' ' offen.push([eintrag[0] + wartezeit(eintrag[2], basis, grenze) + extra, eintrag[1], eintrag[2] + 1]);' ' }' ' }' ' return verlauf;' '}' >> wiederholen.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Wiederholungs-Skript schreiben, Teil 4
docker exec -w /home/node/project agent sh -c "printf '%s\n' 'async function main() {' ' for (const an of [false, true]) {' ' const v = durchlauf(6, 2, 1000, 400, 2000, 4, an);' ' const gesehen = {};' ' let schlimmste = 0;' ' for (const n in v) v[n].slice(1).forEach(function (t) { gesehen[t] = (gesehen[t] || 0) + 1; schlimmste = Math.max(schlimmste, gesehen[t]); });' ' console.log((an ? \"mit Streuung\" : \"ohne Streuung\") + \": meiste Wiederholungen in einer Millisekunde \" + schlimmste);' ' console.log(\" Anfrage 3 versuchte bei \" + v[3].join(\" \") + \", Anfrage 5 bei \" + v[5].join(\" \"));' ' }' >> wiederholen.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Das Wiederholungs-Skript schreiben, Teil 5
docker exec -w /home/node/project agent sh -c "printf '%s\n' ' const probe = \"Damit nicht alle Aufrufer im selben Moment wiederholen und den Dienst erneut überlasten.\";' ' const antwort = await fragen([{ role: \"user\", content: \"Warum fügt man einer Wiederholung eine zufällige Wartezeit hinzu? Antworten Sie in einem kurzen Satz.\" }], probe, 60);' ' console.log(\"Das Modell sagte: \" + antwort.text);' '}' 'main();' >> wiederholen.js"Hier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Die Wiederholungen ausführen
docker exec -w /home/node/project agent node wiederholen.jsHier angezeigt, nicht ausgeführt. Erstellen Sie ein kostenloses Konto, um „Ausführen“ zu drücken und ihn im Terminal Ihres eigenen Labs einzugeben.
Was der Run ausgibt
| Zeile | Was sie zeigt |
|---|---|
| ohne Streuung: meiste Wiederholungen in einer Millisekunde 4 | Vier Aufrufer kamen im selben Moment zurück |
| Anfrage 3 versuchte bei 0 400 1200, Anfrage 5 bei 0 400 1200 2800 | Ohne Streuung sind die Zeiten glatt und gleich |
| mit Streuung: meiste Wiederholungen in einer Millisekunde 1 | Keine zwei Wiederholungen teilen sich einen Moment |
| Anfrage 3 versuchte bei 0 434 1281 2891, Anfrage 5 bei 0 448 1259 2883 | Jeder Aufrufer wartet etwas anders |
| Das Modell sagte: ... | Ein Satz aus dem Labor. Eine Aufgezeichnete Probe, wenn kein Modell antwortet |
Die Zellen, die Lernende ausfüllen, bleiben in dieser Vorschau leer.