Garnet: Caché en Memoria de Microsoft Compatible con Redis
Garnet es un servidor de caché en memoria de código abierto desarrollado por Microsoft Research, diseñado como alternativa de alto rendimiento compatible con el protocolo RESP de Redis. Construido sobre .NET y aprovechando las APIs de .NET moderno para operaciones de red y almacenamiento, Garnet destaca por su latencia extremadamente baja en operaciones de cola y por su capacidad de escalado en hardware con muchos núcleos en servidores Linux.
Requisitos Previos
- Ubuntu 20.04/22.04 o CentOS/Rocky Linux 8+
- .NET 8.0 Runtime o superior
- Al menos 2 GB de RAM
- CPU moderna con múltiples núcleos
- Acceso root o usuario con privilegios sudo
Instalación de Garnet
Instalar el Runtime de .NET
# Ubuntu/Debian: instalar .NET 8.0 Runtime
# Añadir el repositorio oficial de Microsoft
wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb
sudo apt-get update
sudo apt-get install -y dotnet-runtime-8.0
# Verificar instalación
dotnet --version
# CentOS/Rocky Linux
sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm
sudo yum install -y dotnet-runtime-8.0
Instalar Garnet como herramienta .NET
# Instalar Garnet via dotnet tool
dotnet tool install --global Microsoft.Garnet
# Añadir el directorio de herramientas .NET al PATH
echo 'export PATH="$HOME/.dotnet/tools:$PATH"' >> ~/.bashrc
source ~/.bashrc
# Verificar instalación
garnet --version
Instalación desde código fuente
# Instalar .NET SDK para compilar
sudo apt-get install -y dotnet-sdk-8.0
# Clonar el repositorio de Garnet
git clone https://github.com/microsoft/garnet.git
cd garnet
# Compilar en modo Release
dotnet build --configuration Release
# Ejecutar desde el código compilado
cd main/GarnetServer
dotnet run --configuration Release -- --port 6379
Instalación con Docker
# Ejecutar Garnet con Docker
docker run -d \
--name garnet \
-p 6379:6379 \
--restart unless-stopped \
ghcr.io/microsoft/garnet:latest \
--bind 0.0.0.0 \
--port 6379
# Verificar funcionamiento
docker exec garnet redis-cli ping
Configuración Básica
Crear servicio systemd para Garnet:
# Crear directorio de datos y configuración
sudo mkdir -p /opt/garnet /var/lib/garnet /var/log/garnet
sudo useradd -r -s /bin/false garnet
sudo chown garnet:garnet /var/lib/garnet /var/log/garnet
# Crear script de inicio
sudo cat > /opt/garnet/start-garnet.sh << 'EOF'
#!/bin/bash
# Script de inicio de Garnet
exec garnet \
--bind 127.0.0.1 \
--port 6379 \
--password "contraseña_segura" \
--checkpointdir /var/lib/garnet/checkpoints \
--logdir /var/log/garnet \
--loglevel Information \
--index 128m \
--memory 2g \
--objectstorememory 512m
EOF
sudo chmod +x /opt/garnet/start-garnet.sh
# Crear servicio systemd
sudo cat > /etc/systemd/system/garnet.service << 'EOF'
[Unit]
Description=Garnet In-Memory Cache Server (Microsoft)
After=network.target
[Service]
Type=simple
User=garnet
Group=garnet
ExecStart=/opt/garnet/start-garnet.sh
Restart=always
RestartSec=5
# Variables de entorno para .NET
Environment=DOTNET_ROOT=/usr
Environment=DOTNET_CLI_TELEMETRY_OPTOUT=1
Environment=HOME=/var/lib/garnet
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable garnet
sudo systemctl start garnet
sudo systemctl status garnet
Parámetros principales de configuración:
# Ver todos los parámetros disponibles
garnet --help
# Parámetros más importantes:
# --bind IP de escucha (default: 127.0.0.1)
# --port Puerto (default: 6379)
# --password Contraseña de acceso
# --memory Tamaño del almacén de strings en memoria (ej: 2g)
# --objectstorememory Tamaño del almacén de objetos (listas, hashes, etc.)
# --index Tamaño del índice de claves en memoria
# --checkpointdir Directorio para checkpoints (persistencia)
# --aof Habilitar Append Only File para durabilidad
# --loglevel Nivel de log (Debug, Information, Warning, Error)
# --tls Habilitar TLS
# --cert-file-name Certificado TLS
# --key-file-name Clave privada TLS
# Iniciar con TLS habilitado
garnet \
--bind 0.0.0.0 \
--port 6380 \
--password "pass_segura" \
--tls \
--cert-file-name /etc/garnet/certs/server.crt \
--key-file-name /etc/garnet/certs/server.key
# Generar certificado autofirmado para pruebas
sudo mkdir -p /etc/garnet/certs
openssl req -x509 -newkey rsa:4096 -keyout /etc/garnet/certs/server.key \
-out /etc/garnet/certs/server.crt -days 365 -nodes \
-subj "/CN=garnet.mi-servidor.com"
Compatibilidad con Redis
Garnet implementa el protocolo RESP de Redis:
# Conectar con redis-cli
redis-cli -p 6379 -a "contraseña_segura"
# Comandos de strings (totalmente compatibles)
SET clave "valor"
GET clave
SETEX sesion:abc123 3600 "datos_de_sesion"
TTL sesion:abc123
MSET k1 v1 k2 v2 k3 v3
MGET k1 k2 k3
# Contadores
INCR contador:visitas
INCRBY contador:visitas 10
# Hashes
HSET usuario:1 nombre "Carlos López" email "[email protected]" rol "admin"
HGET usuario:1 nombre
HMGET usuario:1 nombre email
HGETALL usuario:1
HINCRBY usuario:1 intentos_login 1
# Listas (Garnet las soporta)
RPUSH cola:tareas "tarea-1" "tarea-2" "tarea-3"
LPOP cola:tareas
LLEN cola:tareas
LRANGE cola:tareas 0 -1
# Sets
SADD grupo:admins "usuario1" "usuario2" "usuario3"
SMEMBERS grupo:admins
SISMEMBER grupo:admins "usuario1"
# Sorted Sets
ZADD ranking:usuarios 1500 "alice" 2000 "bob" 1200 "charlie"
ZRANGE ranking:usuarios 0 -1 WITHSCORES
ZREVRANK ranking:usuarios "bob"
# Pub/Sub
# Terminal 1: Suscribirse
redis-cli -p 6379 -a "pass" SUBSCRIBE canal:alertas
# Terminal 2: Publicar
redis-cli -p 6379 -a "pass" PUBLISH canal:alertas "Servidor caído: web-01"
Modo Clúster
Configurar Garnet en modo clúster:
# Iniciar múltiples instancias de Garnet para el clúster
# Nodo 1
garnet --bind 192.168.1.10 --port 6379 \
--cluster \
--clusterip 192.168.1.10 \
--clusterport 6380 \
--checkpointdir /var/lib/garnet/node1 \
--memory 4g &
# Nodo 2
garnet --bind 192.168.1.11 --port 6379 \
--cluster \
--clusterip 192.168.1.11 \
--clusterport 6380 \
--checkpointdir /var/lib/garnet/node2 \
--memory 4g &
# Nodo 3
garnet --bind 192.168.1.12 --port 6379 \
--cluster \
--clusterip 192.168.1.12 \
--clusterport 6380 \
--checkpointdir /var/lib/garnet/node3 \
--memory 4g &
# Crear el clúster (similiar a Redis Cluster)
redis-cli --cluster create \
192.168.1.10:6379 \
192.168.1.11:6379 \
192.168.1.12:6379 \
--cluster-replicas 0 \
--cluster-yes
# Verificar el estado del clúster
redis-cli -h 192.168.1.10 cluster info
redis-cli -h 192.168.1.10 cluster nodes
Benchmark de Rendimiento
Comparar el rendimiento de Garnet:
# Benchmark básico con redis-benchmark
redis-benchmark \
-p 6379 \
-a "contraseña_segura" \
-t set,get,incr,lpush,sadd \
-n 1000000 \
-q
# Benchmark con alta concurrencia y pipeline
redis-benchmark \
-p 6379 \
-a "contraseña_segura" \
-t set,get \
-n 5000000 \
-c 200 \
-P 32 \
--threads 8
# Benchmark de latencia (percentiles)
redis-benchmark \
-p 6379 \
-a "contraseña_segura" \
-t get \
-n 1000000 \
--csv \
2>&1 | grep "p99"
# Herramienta de benchmark propia de Garnet
# Disponible en el repositorio: src/BDN.benchmark
# Ejecutar benchmark específico de Garnet:
dotnet run --project src/BDN.benchmark --configuration Release -- \
--filter "*Basic*" \
--exporters json \
--artifacts /tmp/garnet-bench-results
Monitorización
# Comandos de monitorización compatibles con Redis
redis-cli -p 6379 -a "pass" info all
# Secciones importantes de INFO:
redis-cli -p 6379 -a "pass" info server
redis-cli -p 6379 -a "pass" info memory
redis-cli -p 6379 -a "pass" info stats
redis-cli -p 6379 -a "pass" info clients
# Ver comandos en tiempo real
redis-cli -p 6379 -a "pass" monitor
# Script de monitorización de Garnet
cat > /usr/local/bin/garnet-monitor.sh << 'EOF'
#!/bin/bash
# Monitorización básica de Garnet
PASS="contraseña_segura"
PORT=6379
echo "=== Estado de Garnet ($(date)) ==="
echo ""
echo "--- Información del servidor ---"
redis-cli -p $PORT -a "$PASS" info server 2>/dev/null | \
grep -E "garnet_version|redis_version|uptime_in_seconds|tcp_port"
echo ""
echo "--- Memoria ---"
redis-cli -p $PORT -a "$PASS" info memory 2>/dev/null | \
grep -E "used_memory_human|maxmemory_human|mem_fragmentation"
echo ""
echo "--- Rendimiento ---"
redis-cli -p $PORT -a "$PASS" info stats 2>/dev/null | \
grep -E "total_commands|instantaneous_ops|keyspace_hits|keyspace_misses"
echo ""
echo "--- Clientes conectados ---"
redis-cli -p $PORT -a "$PASS" info clients 2>/dev/null | \
grep -E "connected_clients|blocked_clients"
EOF
chmod +x /usr/local/bin/garnet-monitor.sh
Casos de Uso
Garnet es especialmente adecuado para:
# CASO DE USO 1: Caché de sesiones de usuarios
# Alta velocidad de lectura/escritura con TTL automático
redis-cli -p 6379 -a "pass" << 'EOF'
# Almacenar sesión de usuario con TTL de 1 hora
SET "sesion:abc123def456" '{"userId":1,"email":"[email protected]","rol":"admin"}' EX 3600
GET "sesion:abc123def456"
# Renovar sesión
EXPIRE "sesion:abc123def456" 3600
EOF
# CASO DE USO 2: Rate limiting
cat > /tmp/rate-limit.sh << 'EOF'
#!/bin/bash
# Rate limiting con Garnet/Redis
IP=$1
LIMITE=100 # Máximo 100 peticiones
VENTANA=60 # Por minuto
CLAVE="rate:$IP:$(date +%s | awk '{print int($1/60)}')"
CONTADOR=$(redis-cli -p 6379 -a "pass" INCR "$CLAVE")
redis-cli -p 6379 -a "pass" EXPIRE "$CLAVE" "$VENTANA" > /dev/null
if [ "$CONTADOR" -gt "$LIMITE" ]; then
echo "BLOQUEADO: $IP ha superado el límite de $LIMITE peticiones/minuto"
exit 1
fi
echo "PERMITIDO: Petición $CONTADOR/$LIMITE para $IP"
EOF
chmod +x /tmp/rate-limit.sh
# CASO DE USO 3: Cola de mensajes (simple)
# Productor
redis-cli -p 6379 -a "pass" RPUSH "cola:emails" \
'{"para":"[email protected]","asunto":"Bienvenido","plantilla":"welcome"}'
# Consumidor (bloqueo con timeout)
redis-cli -p 6379 -a "pass" BLPOP "cola:emails" 30
Solución de Problemas
Garnet no arranca (error de .NET):
# Verificar que .NET 8 está instalado
dotnet --version # Debe ser 8.x.x
# Ver logs de error
sudo journalctl -u garnet -n 50
# Probar ejecutar manualmente para ver errores
garnet --bind 127.0.0.1 --port 6379 --memory 512m
Error de conexión desde aplicación:
# Verificar que Garnet escucha en el puerto correcto
ss -tlnp | grep 6379
# Probar conexión básica
redis-cli -p 6379 ping
# Verificar que el firewall no bloquea el puerto
sudo ufw status
sudo iptables -L | grep 6379
Alto uso de memoria:
# Ver el uso de memoria detallado
redis-cli -p 6379 -a "pass" info memory
# Garnet tiene dos almacenes de memoria:
# --memory: para strings simples (más eficiente)
# --objectstorememory: para colecciones (hashes, listas, sets)
# Ajustar los límites de memoria
# Reiniciar Garnet con valores ajustados
# garnet --memory 1g --objectstorememory 256m
Conclusión
Garnet demuestra que Microsoft Research puede producir herramientas de infraestructura de primer nivel para el ecosistema de código abierto, ofreciendo una alternativa compatible con Redis con particular fortaleza en latencias de cola y operaciones de alta frecuencia gracias a las optimizaciones de bajo nivel del runtime de .NET moderno. Para equipos que ya trabajan con .NET y buscan un almacén en memoria de alto rendimiento sin depender de la licencia SSPL de Redis, Garnet representa una opción técnicamente sólida y con el respaldo institucional de Microsoft como garantía de mantenimiento a largo plazo.


