Naarmate je bot groeit, krijg je op een dag deze waarschuwing van Discord: de bot is bij te veel servers gevoegd en één enkele verbinding (shard) is niet meer genoeg. Precies hier komt Discord sharding in beeld. Discord laat een bot maximaal 2500 servers per gateway-verbinding aan; zodra je die grens passeert, wordt het opsplitsen van de bot in meerdere shards verplicht. In deze gids leg ik stap voor stap uit wat sharding is, hoe je je bot opschaalt met de ShardingManager-klasse van discord.js, en de fijne kneepjes van het verzamelen van data over shards heen.
Wat is sharding en wanneer heb je het nodig?
Een shard is één enkele WebSocket-verbinding die je bot opent naar de Discord-gateway. Elke shard is verantwoordelijk voor een deelverzameling van servers en ontvangt alleen events (berichten, lidwijzigingen, voice-status) voor zijn eigen servers. Discord verdeelt servers over shards met deze formule:
shard_id = (guild_id >> 22) % totaal_aantal_shards
Welke server op welke shard belandt, wordt dus bepaald door de ID van de server — het is niet willekeurig. Wanneer je sharding nodig hebt, is duidelijk:
- Harde limiet: zodra de bot 2500 servers passeert, laat Discord je niet meer met één shard verbinden.
- Prestaties: zelfs onder de 2500 kan één Node.js-proces moeite hebben om het event-verkeer en de cache van duizenden servers te dragen; sharding spreidt de last.
- Veerkracht: als één shard crasht, blijven de andere draaien.
Een belangrijk punt: voor kleine bots ruim onder de 2500 is sharding nodeloze complexiteit. Optimaliseer niet te vroeg; het toevoegen voordat de behoefte ontstaat maakt de ontwikkeling alleen lastiger.
Aan de slag met ShardingManager
discord.js levert een kant-en-klare ShardingManager-klasse die het sharden voor je regelt. Het idee is dit: in plaats van het hoofdbestand van je bot (bijvoorbeeld bot.js) rechtstreeks uit te voeren, schrijf je een managerscript (manager.js). Deze manager start je bot als meerdere aparte processen, elk een shard.
Eerst het managerbestand:
// 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} gestart`);
});
manager.spawn();
De instelling totalShards: 'auto' zorgt dat discord.js Discord om het aanbevolen aantal shards vraagt en het juiste aantal processen opstart. Je kunt het ook handmatig meegeven (totalShards: 4), maar 'auto' is in de meeste gevallen de veiligste keuze.
Je eigenlijke botbestand verandert nauwelijks:
// bot.js
const { Client, GatewayIntentBits } = require('discord.js');
const client = new Client({
intents: [GatewayIntentBits.Guilds],
});
client.once('ready', () => {
console.log(`Ingelogd: ${client.user.tag} | Shard: ${client.shard.ids}`);
});
client.login(process.env.DISCORD_TOKEN);
Let op: in bot.js geef je het token nog steeds aan client.login, maar je vertelt het nooit welke shard het is. De ShardingManager geeft de shard-ID's via omgevingsvariabelen door bij het starten van elk proces, en discord.js leest ze automatisch uit. Voortaan start je de bot met node manager.js, niet met node bot.js.
Data verzamelen over shards: broadcastEval
Het meest verwarrende aan sharding is dit: omdat elke shard een apart proces is, heeft het zijn eigen client.guilds.cache en kan het de servers op andere shards niet zien. Wil je het totale aantal servers van de bot weten, dan is naar één shard kijken misleidend. Je moet dezelfde code op elke shard uitvoeren en de resultaten combineren. discord.js doet dit met broadcastEval:
// Binnen een command-handler
const resultaten = await client.shard.broadcastEval(c => c.guilds.cache.size);
const totaalServers = resultaten.reduce((som, waarde) => som + waarde, 0);
console.log(`Totaal servers: ${totaalServers}`);
broadcastEval voert de functie die je meegeeft uit in het proces van elke shard en geeft een array met resultaten terug, één element per shard. Vervolgens voeg je ze samen met reduce. Hetzelfde patroon geldt voor het totale aantal gebruikers:
const ledenResultaten = await client.shard.broadcastEval(
c => c.guilds.cache.reduce((acc, g) => acc + g.memberCount, 0)
);
const totaalLeden = ledenResultaten.reduce((a, b) => a + b, 0);
Er is hier een cruciale regel: de functie die je aan broadcastEval meegeeft, heeft geen directe toegang tot variabelen daarbuiten, want hij draait in een ander proces. Om externe waarden door te geven gebruik je context:
const guildId = '123456789012345678';
const namen = await client.shard.broadcastEval(
(c, { doelId }) => {
const guild = c.guilds.cache.get(doelId);
return guild ? guild.name : null;
},
{ context: { doelId: guildId } }
);
const gevonden = namen.find(naam => naam !== null);
Omdat een bepaalde server maar op één shard leeft, geven de meeste resultaten null terug; de gevulde haal je eruit met find.
Geheugen, aantal processen en hybrid sharding
Omdat elke shard een apart Node.js-proces is, stijgt het RAM-gebruik recht evenredig met het aantal shards. 16 shards betekent grofweg 16 aparte botinstanties. Bij zeer grote bots (tienduizenden servers) kan dit het geheugen van de server uitputten.
De oplossing is hybrid sharding: meerdere shards groeperen in één proces (een cluster). De ingebouwde ShardingManager van discord.js biedt dit niet rechtstreeks; daarvoor wordt het community-pakket discord-hybrid-sharding gebruikt. De logica: splits je 32 shards in 4 clusters, dan worden er maar 4 processen gestart, elk met 8 shards. Dat verlaagt de geheugenvoetafdruk fors. Kleine en middelgrote bots hebben het niet nodig; de standaard ShardingManager is ruim voldoende.
Een paar praktische punten bij het plannen van je aantal processen:
- Beperk de cache: zet geen onnodige
intentsen caches aan; omdat elke shard zijn eigen cache bewaart, heeft verspilling een vermenigvuldigend effect. - Process- vs worker-modus:
ShardingManagerstart standaard aparte processen; metmode: 'worker'kun je worker_threads gebruiken, maar de isolatie is sterker in de process-modus. - Herstarten: met de optie
respawnaan komt een gecrashte shard automatisch weer omhoog.
Veelgestelde vragen
Moet ik sharden voordat mijn bot 2500 servers bereikt?
Nee, dat hoeft niet. Discord laat je met één shard verbinden tot 2500 servers. Tot je die grens nadert, voegt sharding alleen nodeloze complexiteit en geheugengebruik toe. Kom je in de buurt, dan is overstappen op ShardingManager een klus van slechts een paar bestanden — doe het niet te vroeg.
Moet ik het aantal shards handmatig instellen of 'auto' gebruiken?
In de meeste gevallen is totalShards: 'auto' het beste; discord.js vraagt het door Discord aanbevolen aantal op en start processen daarnaar. Overweeg een handmatig aantal alleen als je een eigen verdelingsstrategie hebt (bijvoorbeeld spreiden over meerdere machines).
Als één shard crasht, valt dan de hele bot uit?
Nee. Shards zijn onafhankelijke processen; crasht er één, dan blijven de andere draaien. Alleen de servers op die shard reageren tijdelijk niet. Met respawn aan herstart de ShardingManager de gecrashte shard automatisch, zodat de onderbreking kort is.
Is het tijd om je bot op te schalen? Heb je hulp nodig bij het bouwen van een sharding-architectuur, het verzamelen van data met broadcastEval of de overstap naar hybrid sharding, neem dan contact met me op — laten we je bot samen naar grote schaal brengen.