En 2012, el servidor principal de la red IRC que administraba empezo a usar 2 GB de RAM. Teniamos 3.000 usuarios. Eso era 10 veces mas de lo esperado. El problema: un modulo de logging que guardaba el buffer completo de cada canal en memoria sin limite. Cada canal activo acumulaba megabytes de historial que nunca se liberaban. Cuando identifique y limite el buffer, el consumo bajo a 200 MB. La leccion: la memoria de un IRCd no se ajusta a posteriori — se planifica antes de abrir el servidor.
Cuanta memoria usa un IRCd
Un IRCd bien configurado consume sorprendentemente poca memoria. Las cifras de referencia para 2025:
- Sin usuarios: 10-30 MB (binario + modulos cargados)
- 100 usuarios, 50 canales: 30-50 MB
- 1.000 usuarios, 200 canales: 80-150 MB
- 5.000 usuarios, 500 canales: 200-400 MB
- 10.000 usuarios, 1.000 canales: 400-800 MB
Estos numeros varian segun el IRCd, los modulos cargados, el tamano de los send queues, y la actividad de los canales. Un servidor con 5.000 usuarios en canales tranquilos usa menos memoria que uno con 1.000 usuarios en canales extremadamente activos, porque los buffers de envio se llenan mas.
Si tu IRCd usa significativamente mas que estos rangos, algo esta mal. Probablemente un modulo con un buffer sin limite, un leak de memoria en una version vieja del IRCd, o una configuracion con send queues excesivamente grandes.
Que consume memoria
El consumo de memoria de un IRCd se divide en:
- Estructura de usuario (~2-5 KB por usuario): Nick, user, host, IP, modos, canales en los que esta, timestamps, y metadatos varios. En UnrealIRCd, la estructura base de un usuario son ~3 KB.
- Estructura de canal (~1-3 KB por canal + listas): Nombre, modos, topic, timestamp. Las listas de bans (+b), invites (+I), y excepciones (+e) se suman. Un canal con 200 bans activos usa significativamente mas memoria que uno con 5.
- Send queues (~8-64 KB por usuario activo): El buffer de datos pendientes de enviar a cada usuario. Es el mayor consumidor variable de memoria. Si un usuario tiene una conexion lenta y el canal es activo, su send queue se llena.
- Modulos: Cada modulo cargado anade su propio consumo. Modulos de logging, estadisticas, o que cachen datos pueden consumir cantidades variables.
- TLS: Cada conexion TLS tiene un contexto SSL que consume ~30-50 KB. Con 5.000 usuarios TLS, esto son 150-250 MB solo para TLS.
Send queues y receive queues
Los send queues son la valvula de presion del IRCd. Cuando un usuario recibe mas datos de los que su conexion puede enviar (canal muy activo + conexion lenta), los datos se acumulan en la send queue. Cuando la queue se llena, el IRCd desconecta al usuario con \"SendQ exceeded\".
# UnrealIRCd — configurar send queues por clase:
class clients {
pingfreq 120;
maxclients 1000;
sendq 1M; /* 1 MB maximo por usuario */
recvq 8192; /* 8 KB de buffer de recepcion */
};
class opers {
pingfreq 120;
maxclients 20;
sendq 5M; /* Los opers necesitan mas sendq */
recvq 8192;
};
# InspIRCd — en el bloque connect:
# Calculo de memoria:
# 1.000 usuarios x 1 MB sendq maximo = 1 GB en el peor caso
# En la practica, la mayoria de send queues estan vacias
# Solo se llenan cuando hay lag o flood
El truco esta en el balance. Un sendq demasiado pequeno desconecta usuarios legitimos en canales activos (\"SendQ exceeded\" frecuente). Un sendq demasiado grande permite que un solo usuario con conexion lenta consuma cientos de MB de memoria del servidor.
Mi recomendacion: 1 MB para usuarios normales, 5 MB para operadores. Si ves muchos \"SendQ exceeded\", el problema no es el sendq — es que los canales son demasiado activos para las conexiones de esos usuarios, o hay flood.
Limites de canales y modos
# Limitar canales por usuario:
# UnrealIRCd:
set { max-channels-per-user 20; };
# InspIRCd (en connect block):
maxchans="20"
# Limitar bans por canal:
# UnrealIRCd:
set { maxbans 60; }; /* 60 bans max por canal */
# InspIRCd:
# Limitar longitud de topic:
# UnrealIRCd:
set { topic-length 360; };
# InspIRCd:
# Limitar WHOWAS entries (historial de nicks):
# UnrealIRCd:
set { whowas-maxentries 1024; };
# InspIRCd:
Cada ban en un canal es una cadena de texto almacenada en memoria. Un canal con 500 bans acumulados consume kilobytes innecesariamente. Limita los bans por canal y configura un mecanismo de limpieza (manual o automatico via bot) para eliminar bans viejos.
WHOWAS es otro consumidor silencioso. Por defecto, algunos IRCds guardan miles de entradas de nicks anteriores. Si tienes 10.000 usuarios que cambian de nick frecuentemente, el historial WHOWAS puede crecer sin control. Limita las entradas y el tiempo de retencion.
Impacto de modulos
Los modulos que mas memoria consumen son los que cachean datos:
- Modulos de historial/playback: Guardan N lineas por canal en memoria. Un canal activo con 1.000 lineas de historial x 200 bytes/linea = 200 KB por canal. Con 500 canales = 100 MB.
- Modulos de estadisticas: Contadores por usuario, por canal, por hora. Se acumulan sin limite si no se configuran.
- Modulos DNSBL: Cachean resultados de consultas DNS. El cache reduce consultas repetidas pero consume memoria. Limita el tamano del cache.
- Modulos de filtro: Listas de palabras prohibidas, patrones regex compilados. El impacto depende del tamano de la lista.
La regla: carga solo los modulos que necesitas. Cada modulo que no usas pero tienes cargado consume memoria base y puede tener overhead por usuario. Revisa periodicamente que modulos tienes activos y descarga los innecesarios.
Diagnostico de consumo
# Ver memoria del proceso IRCd:
ps aux | grep unrealircd
# O mas detallado:
cat /proc/$(pidof unrealircd)/status | grep -i mem
# VmRSS: memoria residente real
# VmSize: memoria virtual total (incluye mapeada no usada)
# Dentro del IRCd (como oper):
/STATS z # Estadisticas de memoria (UnrealIRCd)
/STATS T # Contadores de estructuras
/STATS u # Uptime y uso general
# Monitorizar en el tiempo:
while true; do
echo "$(date) $(ps -o rss= -p $(pidof unrealircd)) KB"
sleep 60
done >> /var/log/ircd_memory.log
# Graficar con gnuplot o importar a Prometheus
# (ver articulo de monitoring)
# Detectar leaks:
# Si la memoria crece monotonamente sin correlacion con usuarios,
# probablemente hay un leak.
# Herramientas: valgrind (en entorno de test, no produccion)
# valgrind --tool=massif /path/to/unrealircd -F
El indicador mas fiable de un memory leak es la memoria residente (RSS) creciendo continuamente sin que el numero de usuarios crezca. Si tienes 1.000 usuarios estables y la RSS sube 10 MB por dia, hay un leak. Reporta al proyecto del IRCd con la version exacta, los modulos cargados, y el grafico de memoria.
Tunning del sistema operativo
# Linux — sysctl relevantes para IRCd:
# File descriptors (uno por conexion):
fs.file-max = 65536
# Y en limits.conf para el usuario del IRCd:
# ircd soft nofile 65536
# ircd hard nofile 65536
# TCP buffers:
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216
# TCP backlog (conexiones pendientes):
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
# Reutilizar TIME_WAIT sockets:
net.ipv4.tcp_tw_reuse = 1
# Overcommit memory (para evitar OOM killer):
vm.overcommit_memory = 0
# 0 = heuristic (default, razonable)
# 1 = siempre overcommit (peligroso)
# 2 = nunca overcommit (conservador)
# Aplicar:
sysctl -p /etc/sysctl.d/ircd.conf
# FreeBSD equivalentes:
kern.maxfiles=65536
kern.ipc.maxsockbuf=16777216
kern.ipc.somaxconn=4096
El ajuste mas critico es fs.file-max y los limites de file descriptors del usuario. Un IRCd con 5.000 usuarios necesita al menos 5.000 file descriptors (uno por conexion TCP) mas los que usa para logs, sockets de servidor, y comunicacion interna. El default de 1.024 es insuficiente para cualquier servidor serio.
Preguntas frecuentes
Cuanta RAM necesito para 10.000 usuarios?
Entre 1 y 2 GB es suficiente para la mayoria de configuraciones. El mayor consumidor sera TLS (30-50 KB por conexion x 10.000 = 300-500 MB) y los send queues bajo carga. Asegurate de tener al menos 4 GB totales en el servidor para dejar margen al sistema operativo.
El OOM killer puede matar mi IRCd?
Si. En Linux, si el sistema se queda sin memoria, el OOM killer selecciona y mata procesos. Un IRCd que consume mucha RAM es un candidato. Solucion: configura el oom_score_adj del proceso IRCd a un valor negativo para reducir la probabilidad de ser elegido: echo -500 > /proc/$(pidof unrealircd)/oom_score_adj.
Debo usar swap?
Para un IRCd, la swap es peor que no tener memoria. Si el IRCd empieza a swappear, la latencia se dispara y los usuarios experimentan lag insoportable. Es mejor que el IRCd se quede sin memoria y se caiga (reinicio rapido) que lentamente agonizar en swap. Configura suficiente RAM para que nunca necesite swap.