Garnet In-Memory Cache from Microsoft

Garnet is an open-source remote cache-store from Microsoft Research, built on .NET and designed to be a high-performance, Redis-compatible in-memory data service. This guide covers installing Garnet on Linux, configuring the .NET runtime, using it as a Redis drop-in replacement, setting up cluster mode, and benchmarking performance.

Prerequisites

  • Ubuntu 20.04/22.04 or CentOS 8/Rocky Linux 8+
  • .NET 8.0 SDK or Runtime
  • At least 2 GB RAM
  • Root or sudo access
  • Port 6379 available (default Redis port)

Install .NET Runtime

Garnet requires .NET 8.0 or later:

# Ubuntu/Debian - Add Microsoft package repository
wget https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
rm packages-microsoft-prod.deb

# Install .NET 8 runtime
sudo apt update
sudo apt install -y dotnet-runtime-8.0

# Verify installation
dotnet --version

# CentOS/Rocky Linux
sudo dnf install -y dotnet-runtime-8.0
# Or use the Microsoft repo:
sudo rpm -Uvh https://packages.microsoft.com/config/centos/8/packages-microsoft-prod.rpm
sudo dnf install -y dotnet-runtime-8.0

Install Garnet

From NuGet (recommended for .NET users):

# Install .NET SDK (needed to run Garnet as a tool)
sudo apt install -y dotnet-sdk-8.0

# Install Garnet as a .NET global tool
dotnet tool install --global Microsoft.Garnet

# Add .NET tools to PATH
echo 'export PATH="$PATH:/root/.dotnet/tools"' >> ~/.bashrc
source ~/.bashrc

# Verify installation
GarnetServer --version

From binary release:

# Download the latest Garnet release
GARNET_VERSION="1.0.0"
wget "https://github.com/microsoft/garnet/releases/download/v${GARNET_VERSION}/GarnetServer-${GARNET_VERSION}-linux-x64.tar.gz"
tar -xzf "GarnetServer-${GARNET_VERSION}-linux-x64.tar.gz"
sudo mv GarnetServer /usr/local/bin/
sudo chmod +x /usr/local/bin/GarnetServer

Build from source:

# Install .NET SDK
sudo apt install -y dotnet-sdk-8.0 git

# Clone the repository
git clone https://github.com/microsoft/garnet.git
cd garnet

# Build the server
dotnet build -c Release

# Run from build output
cd main/GarnetServer/bin/Release/net8.0/
./GarnetServer --help

Basic Configuration

Garnet uses command-line arguments or a JSON configuration file:

# Start Garnet with basic settings
GarnetServer \
  --port 6379 \
  --bind 0.0.0.0 \
  --auth password \
  --memory 1g \
  --storage-memory 2g \
  --log-level Information

JSON configuration file:

mkdir -p /etc/garnet

cat > /etc/garnet/garnet.conf << 'EOF'
{
  "Port": 6379,
  "Address": "0.0.0.0",
  "Password": "your-strong-password",
  "Memory": "2g",
  "StorageMemory": "4g",
  "SegmentSize": "1g",
  "IndexSize": "128m",
  "LogLevel": "Information",
  "DisablePubSub": false,
  "QuietMode": false,
  "EnableStorageTier": false,
  "EnableAOF": false,
  "EnableCluster": false
}
EOF

# Start with config file
GarnetServer --config-import-path /etc/garnet/garnet.conf

Redis Protocol Compatibility

Garnet implements the Redis Serialization Protocol (RESP) and supports a wide range of Redis commands:

# Test with redis-cli
redis-cli -h localhost -p 6379 -a your-strong-password ping
# PONG

redis-cli -h localhost -p 6379 -a your-strong-password info server | head -20

# Test supported data types
redis-cli -a your-password << 'EOF'
SET mykey "hello from garnet"
GET mykey
EXPIRE mykey 300
TTL mykey
LPUSH mylist a b c
LRANGE mylist 0 -1
HSET myhash field1 value1 field2 value2
HGETALL myhash
ZADD leaderboard 100 player1 200 player2
ZREVRANGE leaderboard 0 -1 WITHSCORES
SADD myset member1 member2 member3
SMEMBERS myset
EOF

Python client:

# pip install redis
import redis

# Connect to Garnet using the standard Redis client
r = redis.Redis(
    host='localhost',
    port=6379,
    password='your-strong-password',
    decode_responses=True
)

print(r.ping())  # True

# String operations
r.set('name', 'Garnet Cache')
r.setex('session:abc123', 3600, 'user_data_json')
print(r.get('name'))

# Hash operations (useful for object storage)
r.hset('user:1', mapping={
    'name': 'Alice',
    'email': '[email protected]',
    'role': 'admin'
})
print(r.hgetall('user:1'))

# List operations (queue pattern)
r.rpush('task_queue', 'task1', 'task2', 'task3')
print(r.llen('task_queue'))
print(r.lpop('task_queue'))  # task1

# Pub/Sub
pubsub = r.pubsub()
pubsub.subscribe('alerts')
r.publish('alerts', 'High CPU on web01')

Cluster Mode Setup

Garnet supports Redis cluster mode for horizontal scaling:

# Start 6 Garnet instances for a 3-primary, 3-replica cluster
for port in 7000 7001 7002 7003 7004 7005; do
  mkdir -p /var/lib/garnet/${port}
  
  GarnetServer \
    --port ${port} \
    --bind 0.0.0.0 \
    --auth clusterpassword \
    --enable-cluster \
    --cluster-node-timeout 5000 \
    --checkpointdir /var/lib/garnet/${port} \
    --log-level Warning \
    --quiet &
  echo "Started Garnet on port ${port}"
done

# Create the cluster using redis-cli
# (Garnet cluster creation uses the same Redis cluster protocol)
redis-cli --cluster create \
  127.0.0.1:7000 \
  127.0.0.1:7001 \
  127.0.0.1:7002 \
  127.0.0.1:7003 \
  127.0.0.1:7004 \
  127.0.0.1:7005 \
  --cluster-replicas 1 \
  -a clusterpassword

# Verify cluster
redis-cli -p 7000 -a clusterpassword cluster info
redis-cli -p 7000 -a clusterpassword cluster nodes

TLS Configuration

# Generate self-signed certificate for testing
openssl req -x509 -newkey rsa:4096 -nodes \
  -keyout /etc/garnet/server.key \
  -out /etc/garnet/server.crt \
  -days 365 \
  -subj "/CN=localhost"

# Start Garnet with TLS
GarnetServer \
  --port 6380 \
  --tls \
  --cert-file-name /etc/garnet/server.crt \
  --cert-password "" \
  --auth your-password

# For production: use a proper certificate from Let's Encrypt
# sudo certbot certonly --standalone -d cache.example.com
# GarnetServer --tls --cert-file-name /etc/letsencrypt/live/cache.example.com/fullchain.pem ...

# Connect with TLS using redis-cli
redis-cli -h localhost -p 6380 -a your-password \
  --tls --cacert /etc/garnet/server.crt \
  ping

Performance Benchmarks

# Install redis-benchmark
sudo apt install -y redis-tools

# Benchmark Garnet
redis-benchmark \
  -h localhost \
  -p 6379 \
  -a your-password \
  -c 50 \
  -n 1000000 \
  --threads 4 \
  -q

# Typical benchmark output:
# SET: 800,000+ ops/sec
# GET: 900,000+ ops/sec

# Test with pipelining (more realistic for batch operations)
redis-benchmark -h localhost -p 6379 -a your-password \
  -c 50 -n 1000000 -P 16 -q

# Test specific data sizes
redis-benchmark -h localhost -p 6379 -a your-password \
  -c 100 -n 500000 -d 1024 -q  # 1KB values

# Compare with Redis or ValKey on the same machine
# Use a different port for the comparison
redis-benchmark -h localhost -p 6380 -c 50 -n 1000000 -q  # Redis port

Systemd Service Setup

# Create a dedicated user
sudo useradd -r -d /var/lib/garnet -s /bin/false garnet
sudo mkdir -p /var/lib/garnet
sudo chown garnet:garnet /var/lib/garnet

# Create systemd service
cat > /etc/systemd/system/garnet.service << 'EOF'
[Unit]
Description=Garnet In-Memory Cache (Microsoft)
After=network.target
Documentation=https://microsoft.github.io/garnet

[Service]
Type=simple
User=garnet
Group=garnet
WorkingDirectory=/var/lib/garnet
ExecStart=/usr/local/bin/GarnetServer \
  --config-import-path /etc/garnet/garnet.conf
Restart=on-failure
RestartSec=5

# .NET runtime optimizations
Environment="DOTNET_GCHeapHardLimit=2147483648"
Environment="DOTNET_GCConserveMemory=5"
Environment="DOTNET_TieredCompilation=1"

LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now garnet
sudo systemctl status garnet

Firewall configuration:

sudo ufw allow from 10.0.0.0/8 to any port 6379

# Or restrict to specific IPs
sudo ufw allow from 192.168.1.0/24 to any port 6379

Troubleshooting

Garnet fails to start - "Address already in use":

# Check what's on port 6379
ss -tlnp | grep 6379

# Stop conflicting Redis/ValKey instance
sudo systemctl stop redis-server
sudo systemctl stop valkey-server

# Change Garnet's port if needed
# In garnet.conf: "Port": 6380

.NET runtime not found:

# Verify .NET is installed
dotnet --version

# Check runtime versions
dotnet --list-runtimes

# Install missing runtime
sudo apt install -y dotnet-runtime-8.0

# For self-contained binary, no .NET runtime required:
# Download the self-contained build from GitHub releases

Memory usage too high:

# Reduce memory settings in garnet.conf
# "Memory": "512m"        - in-memory cache limit
# "StorageMemory": "1g"   - object store memory

# Configure .NET GC
# Environment="DOTNET_GCHeapHardLimit=1073741824"  # 1GB limit

# Check actual usage
ps aux | grep GarnetServer

Redis clients getting NOAUTH errors:

# Ensure password is set consistently
redis-cli -p 6379 AUTH your-password

# Check Garnet is started with --auth flag
ps aux | grep GarnetServer | grep auth

Conclusion

Garnet brings Microsoft Research's performance engineering to open-source in-memory caching, offering Redis protocol compatibility with a .NET foundation that integrates naturally into .NET-heavy environments. It delivers competitive throughput compared to Redis, supports cluster mode for horizontal scaling, and backs TLS encryption natively. It is a solid choice when you want a Redis-compatible cache with an open-source license and active development from Microsoft.