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.


