aslain.dev
0%
01 Hizmetler 02 Hakkımda 03 Projeler 04 Stack 05 Blog 06 İletişim
← Tüm makaleler Discord-Bots

Discord Sharding: Große Bots skalieren

Wenn dein Bot wächst, bekommst du eines Tages diese Warnung von Discord: Der Bot ist zu vielen Servern beigetreten und eine einzige Verbindung (Shard) reicht nicht mehr. Genau hier kommt Discord Sharding ins Spiel. Discord erlaubt einem Bot maximal 2500 Server pro Gateway-Verbindung; sobald du diese Grenze überschreitest, wird das Aufteilen des Bots in mehrere Shards verpflichtend. In dieser Anleitung erkläre ich Schritt für Schritt, was Sharding ist, wie du deinen Bot mit der ShardingManager-Klasse von discord.js skalierst und worauf es beim Zusammenführen von Daten über Shards hinweg ankommt.

Was ist Sharding und wann braucht man es?

Ein Shard ist eine einzelne WebSocket-Verbindung, die dein Bot zum Discord-Gateway öffnet. Jeder Shard ist für eine Teilmenge der Server zuständig und empfängt Events (Nachrichten, Mitgliederänderungen, Voice-Status) nur für seine eigenen Server. Discord verteilt Server mit dieser Formel auf die Shards:

shard_id = (guild_id >> 22) % gesamtzahl_der_shards

Welcher Server auf welchem Shard landet, hängt also von der Server-ID ab — es ist nicht zufällig. Wann du Sharding brauchst, ist eindeutig:

  • Harte Grenze: Sobald der Bot 2500 Server überschreitet, lässt Discord keine Verbindung mit einem einzigen Shard mehr zu.
  • Leistung: Selbst unter 2500 kann ein einzelner Node.js-Prozess mit dem Event-Verkehr und Cache von Tausenden Servern überfordert sein; Sharding verteilt die Last.
  • Ausfallsicherheit: Stürzt ein Shard ab, laufen die anderen weiter.

Ein wichtiger Punkt: Für kleine Bots weit unter 2500 ist Sharding unnötige Komplexität. Optimiere nicht zu früh; es vor dem tatsächlichen Bedarf hinzuzufügen erschwert nur die Entwicklung.

Erste Schritte mit dem ShardingManager

discord.js bringt eine fertige ShardingManager-Klasse mit, die das Sharding für dich übernimmt. Die Idee ist diese: Statt die Hauptdatei deines Bots (etwa bot.js) direkt auszuführen, schreibst du ein Manager-Skript (manager.js). Dieser Manager startet deinen Bot als mehrere separate Prozesse, jeder davon ein Shard.

Zuerst die Manager-Datei:

// manager.js
const { ShardingManager } = require('discord.js');
require('dotenv').config();

const manager = new ShardingManager('./bot.js', {
  token: process.env.DISCORD_TOKEN,
  totalShards: 'auto',
});

manager.on('shardCreate', shard => {
  console.log(`Shard ${shard.id} gestartet`);
});

manager.spawn();

Die Einstellung totalShards: 'auto' sorgt dafür, dass discord.js bei Discord die empfohlene Shard-Anzahl abfragt und die passende Zahl an Prozessen startet. Du kannst sie auch manuell angeben (totalShards: 4), aber 'auto' ist in den meisten Fällen die sicherste Wahl.

Deine eigentliche Bot-Datei ändert sich kaum:

// bot.js
const { Client, GatewayIntentBits } = require('discord.js');

const client = new Client({
  intents: [GatewayIntentBits.Guilds],
});

client.once('ready', () => {
  console.log(`Angemeldet: ${client.user.tag} | Shard: ${client.shard.ids}`);
});

client.login(process.env.DISCORD_TOKEN);

Beachte: In bot.js übergibst du das Token weiterhin an client.login, aber du sagst ihm nie, welcher Shard er ist. Der ShardingManager übergibt die Shard-IDs beim Start jedes Prozesses über Umgebungsvariablen, und discord.js liest sie automatisch aus. Ab jetzt startest du den Bot mit node manager.js, nicht mit node bot.js.

Daten über Shards zusammenführen: broadcastEval

Der verwirrendste Teil am Sharding ist dieser: Da jeder Shard ein eigener Prozess ist, hat er seinen eigenen client.guilds.cache und kann die Server auf anderen Shards nicht sehen. Wenn du die Gesamtzahl der Server des Bots wissen willst, ist ein Blick auf einen einzelnen Shard irreführend. Du musst denselben Code auf jedem Shard ausführen und die Ergebnisse zusammenführen. discord.js macht das mit broadcastEval:

// Innerhalb eines Command-Handlers
const ergebnisse = await client.shard.broadcastEval(c => c.guilds.cache.size);
const gesamtServer = ergebnisse.reduce((summe, wert) => summe + wert, 0);

console.log(`Server insgesamt: ${gesamtServer}`);

broadcastEval führt die übergebene Funktion im Prozess jedes Shards aus und gibt ein Array von Ergebnissen zurück, ein Element pro Shard. Anschließend führst du sie mit reduce zusammen. Dasselbe Muster gilt für die Gesamtzahl der Nutzer:

const mitgliederErgebnisse = await client.shard.broadcastEval(
  c => c.guilds.cache.reduce((acc, g) => acc + g.memberCount, 0)
);
const gesamtMitglieder = mitgliederErgebnisse.reduce((a, b) => a + b, 0);

Hier gibt es eine entscheidende Regel: Die an broadcastEval übergebene Funktion kann nicht direkt auf Variablen außerhalb zugreifen, weil sie in einem anderen Prozess läuft. Um externe Werte zu übergeben, nutzt du context:

const guildId = '123456789012345678';

const namen = await client.shard.broadcastEval(
  (c, { zielId }) => {
    const guild = c.guilds.cache.get(zielId);
    return guild ? guild.name : null;
  },
  { context: { zielId: guildId } }
);

const gefunden = namen.find(name => name !== null);

Da ein bestimmter Server nur auf einem Shard existiert, geben die meisten Ergebnisse null zurück; den befüllten holst du dir mit find.

Speicher, Prozessanzahl und Hybrid Sharding

Da jeder Shard ein eigener Node.js-Prozess ist, steigt der RAM-Verbrauch direkt proportional zur Shard-Anzahl. 16 Shards bedeuten grob 16 separate Bot-Instanzen. Bei sehr großen Bots (Zehntausende Server) kann das den Speicher des Servers erschöpfen.

Die Lösung ist Hybrid Sharding: mehrere Shards in einem einzigen Prozess (einem Cluster) zu bündeln. Der eingebaute ShardingManager von discord.js bietet das nicht direkt an; dafür wird das Community-Paket discord-hybrid-sharding verwendet. Die Logik: Teilst du 32 Shards in 4 Cluster, werden nur 4 Prozesse gestartet, jeder mit 8 Shards. Das senkt den Speicherbedarf deutlich. Kleine und mittlere Bots brauchen das nicht; der Standard-ShardingManager reicht völlig aus.

Ein paar praktische Punkte bei der Planung deiner Prozessanzahl:

  • Cache kürzen: Aktiviere keine unnötigen intents und Caches; da jeder Shard seinen eigenen Cache hält, hat Verschwendung einen Multiplikatoreffekt.
  • Process- vs. Worker-Modus: ShardingManager startet standardmäßig separate Prozesse; mit mode: 'worker' kannst du worker_threads nutzen, aber die Isolation ist im Process-Modus stärker.
  • Neustart: Mit aktivierter respawn-Option fährt ein abgestürzter Shard automatisch wieder hoch.

Häufige Fragen

Sollte ich sharden, bevor mein Bot 2500 Server erreicht?

Nein, das ist nicht nötig. Discord lässt dich mit einem einzigen Shard bis zu 2500 Server verbinden. Bis du dieser Grenze nahekommst, bringt Sharding nur unnötige Komplexität und Speicherverbrauch. Wenn es eng wird, ist der Umstieg auf den ShardingManager eine Sache von nur wenigen Dateien — bemühe dich nicht zu früh darum.

Sollte ich die Shard-Anzahl manuell setzen oder 'auto' verwenden?

In den meisten Fällen ist totalShards: 'auto' am besten; discord.js fragt die von Discord empfohlene Anzahl ab und startet die Prozesse entsprechend. Eine manuelle Anzahl solltest du nur erwägen, wenn du eine eigene Verteilungsstrategie hast (zum Beispiel die Verteilung auf mehrere Maschinen).

Wenn ein Shard abstürzt, fällt dann der ganze Bot aus?

Nein. Shards sind unabhängige Prozesse; stürzt einer ab, laufen die anderen weiter. Nur die Server auf diesem Shard antworten vorübergehend nicht. Mit aktiviertem respawn startet der ShardingManager den abgestürzten Shard automatisch neu, sodass die Unterbrechung kurz bleibt.

Ist es Zeit, deinen Bot zu skalieren? Wenn du Hilfe beim Aufbau einer Sharding-Architektur, beim Zusammenführen von Daten mit broadcastEval oder beim Umstieg auf Hybrid Sharding brauchst, melde dich bei mir — bringen wir deinen Bot gemeinsam auf große Skala.

Bu kategorideki tüm yazılar →

Devamı için