Caching with Memcached: Configuration

Introduction

Memcached is a high-performance, distributed memory object caching system designed to speed up dynamic web applications by alleviating database load. Originally developed by Brad Fitzpatrick for LiveJournal in 2003, Memcached has become one of the most widely used caching solutions, powering some of the world's largest websites including Facebook, Twitter, YouTube, and Wikipedia.

Unlike Redis, Memcached is purpose-built exclusively for caching with a simpler architecture focused on speed and efficiency. It provides sub-millisecond response times and can handle millions of requests per second with minimal CPU overhead. Memcached's simplicity makes it extremely reliable and easy to scale horizontally by adding more servers to the cluster.

This comprehensive guide covers Memcached installation, configuration optimization, caching strategies, performance tuning, and real-world implementation examples. You'll learn how to leverage Memcached to dramatically reduce database load and improve application response times by 70-95%.

Understanding Memcached

What is Memcached?

Memcached is an in-memory key-value store for small chunks of arbitrary data from results of database calls, API calls, or page rendering. It uses a simple but powerful design:

  • In-Memory Storage: All data stored in RAM for ultra-fast access
  • Distributed System: Multiple servers form a cluster
  • LRU Eviction: Least Recently Used items removed when memory full
  • Simple Protocol: Text-based protocol, easy to implement clients
  • No Persistence: Data lost on restart (by design)

Memcached vs Redis

FeatureMemcachedRedis
Primary UsePure cachingCache + data store
Data StructuresSimple key-valueRich (strings, hashes, lists, sets, etc.)
PersistenceNoneOptional (RDB/AOF)
Multi-threadingYesNo (single-threaded)
Max Key Size250 bytes512 MB
Max Value Size1 MB (default)512 MB
ReplicationNo (client-side)Yes (built-in)
ClusteringClient-side consistent hashingNative support
Memory EfficiencyBetter for simple dataBetter for complex data

When to Choose Memcached

Best For:

  • Pure caching scenarios where data can be regenerated
  • Simple key-value data storage
  • Applications requiring multi-threaded performance
  • Scenarios where data persistence is not needed
  • Memory-constrained environments with simple data

Not Ideal For:

  • Complex data structures
  • Persistent data storage requirements
  • Pub/sub messaging
  • Sorted sets or lists
  • Atomic operations on complex data

Common Use Cases

  1. Database Query Caching: Store frequent query results
  2. Session Storage: User session data (with session replication)
  3. Page Fragment Caching: HTML fragments
  4. Object Caching: Serialized application objects
  5. API Response Caching: External API call results
  6. Computed Data: Expensive calculations

Installation and Setup

Installing Memcached

# Ubuntu/Debian
apt-get update
apt-get install memcached libmemcached-tools -y

# CentOS/RHEL/Rocky Linux
dnf install memcached libmemcached -y

# Verify installation
memcached -h
memcached -V

Installing Client Libraries

# Python
pip install python-memcached
# or pymemcache (faster)
pip install pymemcache

# PHP
apt-get install php-memcached

# Node.js
npm install memcached

# Ruby
gem install dalli

Basic Configuration

# Edit configuration file
vim /etc/memcached.conf

# Essential settings:
-d                      # Run as daemon
-m 64                   # Memory limit (MB)
-p 11211                # Port
-u memcache             # Run as user
-l 127.0.0.1            # Listen address (localhost)
-c 1024                 # Max simultaneous connections
-t 4                    # Threads (number of CPU cores)
-v                      # Verbose mode (for debugging)

# For production (4GB RAM, 4 cores):
-d
-m 4096
-p 11211
-u memcache
-l 127.0.0.1
-c 10240
-t 4

Starting Memcached

# Start with systemd
systemctl start memcached
systemctl enable memcached
systemctl status memcached

# Verify Memcached is running
echo "stats" | nc localhost 11211

# Or with telnet
telnet localhost 11211
stats
quit

# Test connection with memcached-tool
memcached-tool localhost:11211 stats

Benchmarking Memcached Performance

Baseline Performance Test

# Install benchmarking tool
git clone https://github.com/RedisLabs/memtier_benchmark.git
cd memtier_benchmark
autoreconf -ivf
./configure
make
make install

# Run benchmark
memtier_benchmark -s localhost -p 11211 --protocol=memcache_text \
  -t 4 -c 50 -n 10000 --ratio=1:10 --data-size=1024

# Typical results (modern hardware, 1KB values):
# Throughput: 150,000-300,000 ops/sec
# Latency: 0.5-2ms average
# GET operations: 95%+ at sub-millisecond
# SET operations: 90%+ at sub-millisecond

Application Response Time Baseline

Without Caching:

# Measure database query time
time curl http://localhost/api/products

# Results:
# Response time: 380ms
# Database queries: 12
# Database load: 85% CPU

With Memcached (after implementation):

time curl http://localhost/api/products

# Results:
# Response time: 22ms (94% improvement)
# Database queries: 0.6 average (95% cache hit rate)
# Database load: 12% CPU (86% reduction)

Memory Configuration and Optimization

Memory Allocation

# Set memory limit in /etc/memcached.conf
-m 4096  # 4GB

# Or start with command line
memcached -m 4096 -d

# Calculate recommended memory:
# Total RAM: 16GB
# System/OS: -2GB (reserve)
# Applications: -4GB
# Other services: -2GB
# Available for Memcached: 8GB
-m 8192

Memory Usage Monitoring

# Connect and check stats
echo "stats" | nc localhost 11211 | grep -E "bytes|limit_maxbytes|evictions"

# Key metrics:
# bytes: Current memory usage
# limit_maxbytes: Maximum allowed memory
# evictions: Number of items evicted due to memory pressure

# Example output:
# STAT bytes 1073741824               # 1GB used
# STAT limit_maxbytes 4294967296      # 4GB limit
# STAT evictions 12543                # Items evicted

Monitoring Script

#!/bin/bash
# /usr/local/bin/memcached-monitor.sh

HOST="localhost"
PORT="11211"

echo "=== Memcached Monitor - $(date) ==="

# Get stats
STATS=$(echo "stats" | nc $HOST $PORT)

# Parse key metrics
BYTES=$(echo "$STATS" | grep "^STAT bytes" | awk '{print $3}')
LIMIT=$(echo "$STATS" | grep "^STAT limit_maxbytes" | awk '{print $3}')
CURR_ITEMS=$(echo "$STATS" | grep "^STAT curr_items" | awk '{print $3}')
EVICTIONS=$(echo "$STATS" | grep "^STAT evictions" | awk '{print $3}')
GET_HITS=$(echo "$STATS" | grep "^STAT get_hits" | awk '{print $3}')
GET_MISSES=$(echo "$STATS" | grep "^STAT get_misses" | awk '{print $3}')

# Calculate metrics
MEMORY_PCT=$(awk "BEGIN {printf \"%.2f\", ($BYTES/$LIMIT)*100}")
TOTAL_GETS=$((GET_HITS + GET_MISSES))
if [ $TOTAL_GETS -gt 0 ]; then
    HIT_RATE=$(awk "BEGIN {printf \"%.2f\", ($GET_HITS/$TOTAL_GETS)*100}")
else
    HIT_RATE="0"
fi

# Display
echo "Memory Usage: $MEMORY_PCT%"
echo "Items Cached: $CURR_ITEMS"
echo "Evictions: $EVICTIONS"
echo "Cache Hit Rate: $HIT_RATE%"

# Alert if high evictions
if [ $EVICTIONS -gt 10000 ]; then
    echo "WARNING: High eviction count - consider increasing memory" | \
        mail -s "Memcached Alert" [email protected]
fi
chmod +x /usr/local/bin/memcached-monitor.sh
# Schedule monitoring
*/5 * * * * /usr/local/bin/memcached-monitor.sh >> /var/log/memcached-monitor.log

Slab Allocator Configuration

Memcached uses slab allocation for memory management:

# View slab statistics
echo "stats slabs" | nc localhost 11211

# Understanding slab allocation:
# Memcached divides memory into 1MB pages
# Pages grouped into slabs based on item size
# Default growth factor: 1.25

# Customize growth factor (closer to 1 = more slab classes, less wasted memory)
memcached -f 1.10 -m 4096 -d

# For varied object sizes, use smaller factor (1.10-1.15)
# For uniform object sizes, use larger factor (1.25-1.50)

# Example with optimized configuration:
-d
-m 4096
-f 1.10        # 10% growth factor
-n 512         # Minimum allocation size
-t 4
-c 10240

Connection and Thread Configuration

Connection Limits

# Set max connections in /etc/memcached.conf
-c 10240  # Default: 1024

# Calculate required connections:
# Connections = (Application servers × Connections per server × Safety margin)
# Example: 5 app servers × 200 connections × 1.5 = 1500 connections
-c 2048

# Monitor current connections
echo "stats" | nc localhost 11211 | grep curr_connections

# Check max connections reached
echo "stats" | nc localhost 11211 | grep listen_disabled_num
# If > 0, increase connection limit

Thread Configuration

# Set threads based on CPU cores
-t 4  # For 4-core CPU
-t 8  # For 8-core CPU

# Do NOT over-thread:
# General rule: threads = CPU cores
# Setting too many threads hurts performance

# Test thread scaling
# 1 thread
memcached -m 1024 -t 1 -p 11211 -d
memtier_benchmark -s localhost -p 11211 --protocol=memcache_text -t 4 -c 50

# 4 threads
memcached -m 1024 -t 4 -p 11211 -d
memtier_benchmark -s localhost -p 11211 --protocol=memcache_text -t 4 -c 50

# Typical results:
# 1 thread: 80,000 ops/sec
# 4 threads: 280,000 ops/sec (3.5x improvement)

TCP Configuration

# Tune kernel TCP parameters for Memcached
cat >> /etc/sysctl.d/99-memcached.conf << 'EOF'
# TCP buffer sizes
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# Connection handling
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65536
net.ipv4.tcp_max_syn_backlog = 8192

# TIME_WAIT optimization
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_tw_reuse = 1

# Connection queue
net.ipv4.ip_local_port_range = 10000 65535
EOF

sysctl -p /etc/sysctl.d/99-memcached.conf

Security Configuration

Network Security

# Bind to specific interface (default: all interfaces - INSECURE)
-l 127.0.0.1          # Localhost only (recommended)
-l 192.168.1.100      # Specific IP
-l 127.0.0.1,192.168.1.100  # Multiple IPs

# Disable UDP (unless needed)
-U 0                  # Disable UDP completely

# Example production config:
-d
-m 4096
-l 127.0.0.1          # Localhost only
-p 11211
-U 0                  # No UDP
-c 10240
-t 4
-u memcache

Firewall Configuration

# Only if remote access needed

# UFW (Ubuntu)
ufw allow from 192.168.1.0/24 to any port 11211 proto tcp
ufw enable

# Firewalld (CentOS/Rocky)
firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.1.0/24" port protocol="tcp" port="11211" accept'
firewall-cmd --reload

# Iptables
iptables -A INPUT -p tcp -s 192.168.1.0/24 --dport 11211 -j ACCEPT
iptables -A INPUT -p tcp --dport 11211 -j DROP
iptables-save > /etc/iptables/rules.v4

SASL Authentication

Enable SASL for authentication:

# Install SASL
apt-get install sasl2-bin libsasl2-modules -y

# Create SASL config directory
mkdir -p /etc/sasl2
cat > /etc/sasl2/memcached.conf << 'EOF'
mech_list: plain
sasldb_path: /etc/sasl2/memcached-sasldb2
EOF

# Create user
echo "password" | saslpasswd2 -a memcached -c username -p

# Set permissions
chown memcache:memcache /etc/sasl2/memcached-sasldb2
chmod 640 /etc/sasl2/memcached-sasldb2

# Enable SASL in Memcached
# Add to /etc/memcached.conf:
-S  # Enable SASL

# Restart
systemctl restart memcached

# Test with authentication
memcached-tool localhost:11211 --user=username --password=password stats

Distributed Memcached Setup

Client-Side Consistent Hashing

Memcached uses client-side distribution:

Python Example:

from pymemcache.client.hash import HashClient

# Define server pool
servers = [
    ('10.0.1.10', 11211),
    ('10.0.1.11', 11211),
    ('10.0.1.12', 11211),
]

# Create client with consistent hashing
client = HashClient(servers, use_pooling=True)

# Operations automatically distributed
client.set('key1', 'value1')  # Stored on server based on key hash
client.set('key2', 'value2')  # May be on different server

value1 = client.get('key1')    # Retrieved from correct server
value2 = client.get('key2')

PHP Example:

<?php
$memcached = new Memcached();

// Add servers
$memcached->addServers([
    ['10.0.1.10', 11211],
    ['10.0.1.11', 11211],
    ['10.0.1.12', 11211],
]);

// Enable consistent hashing
$memcached->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);

// Operations
$memcached->set('key1', 'value1');
$value1 = $memcached->get('key1');
?>

Scaling Strategy

# Start with single server
Server 1: 8GB RAM, handles 100% traffic

# Add servers as needed (client handles distribution)
Server 1: 8GB RAM, handles ~33% traffic
Server 2: 8GB RAM, handles ~33% traffic
Server 3: 8GB RAM, handles ~33% traffic

# Total capacity: 24GB distributed cache
# Throughput: 3x (if evenly distributed)

# Best practices:
# 1. Add servers in pairs or multiples
# 2. Monitor distribution across servers
# 3. Use consistent hashing to minimize rehashing
# 4. Plan for server failures (cache misses are acceptable)

Caching Strategies

Cache-Aside Pattern

Most common implementation:

import pymemcache.client.base as memcache

# Create client
mc = memcache.Client(('localhost', 11211))

def get_user(user_id):
    # Generate cache key
    cache_key = f'user:{user_id}'

    # Try to get from cache
    cached_user = mc.get(cache_key)

    if cached_user:
        # Cache hit
        return json.loads(cached_user)

    # Cache miss - query database
    user = database.query(f"SELECT * FROM users WHERE id = {user_id}")

    # Store in cache (1 hour TTL)
    mc.set(cache_key, json.dumps(user), expire=3600)

    return user

# Performance:
# Cache hit: 1ms
# Cache miss: 95ms (database query)
# With 95% hit rate: average 5.75ms (vs 95ms without cache)

Cache Invalidation

def update_user(user_id, user_data):
    # Update database
    database.update(f"UPDATE users SET ... WHERE id = {user_id}", user_data)

    # Invalidate cache
    mc.delete(f'user:{user_id}')

    # Or update cache immediately (write-through)
    # mc.set(f'user:{user_id}', json.dumps(user_data), expire=3600)

    return user_data

Multi-Get Operations

Batch operations for efficiency:

def get_multiple_users(user_ids):
    # Generate cache keys
    cache_keys = {f'user:{uid}': uid for uid in user_ids}

    # Fetch from cache (single network call)
    cached_users = mc.get_many(cache_keys.keys())

    # Identify misses
    cached_ids = {cache_keys[k] for k in cached_users.keys()}
    missing_ids = set(user_ids) - cached_ids

    # Fetch missing from database
    if missing_ids:
        db_users = database.query(
            f"SELECT * FROM users WHERE id IN ({','.join(map(str, missing_ids))})"
        )

        # Cache missing users
        cache_data = {f'user:{u["id"]}': json.dumps(u) for u in db_users}
        mc.set_many(cache_data, expire=3600)

        # Combine results
        all_users = list(cached_users.values()) + db_users
    else:
        all_users = list(cached_users.values())

    return [json.loads(u) if isinstance(u, str) else u for u in all_users]

# Performance:
# 100 users without batch: 100 cache requests = ~100ms
# 100 users with batch: 1 cache request = ~2ms (50x faster)

Key Naming Conventions

# Use structured key names

# User data
user:{user_id}                    # User object
user:{user_id}:profile            # User profile
user:{user_id}:preferences        # User preferences

# Session data
session:{session_id}

# Query results
query:{hash}                      # Hashed query string
api:products:category:{cat_id}    # API response

# Computed data
stats:daily:{date}                # Daily statistics
leaderboard:weekly                # Weekly leaderboard

# Time-based keys
temp:{timestamp}:{id}             # Temporary data

# Use prefixes for easy invalidation
cache_v2:user:{user_id}          # Version prefix (change to invalidate all)

Real-World Implementation Examples

Example 1: WordPress Object Cache

<?php
// wp-content/object-cache.php

class WP_Object_Cache {
    private $memcache;

    public function __construct() {
        $this->memcache = new Memcached();
        $this->memcache->addServer('localhost', 11211);
        $this->memcache->setOption(Memcached::OPT_COMPRESSION, true);
        $this->memcache->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
    }

    public function get($key, $group = 'default') {
        $cache_key = $this->buildKey($key, $group);
        return $this->memcache->get($cache_key);
    }

    public function set($key, $data, $group = 'default', $expire = 0) {
        $cache_key = $this->buildKey($key, $group);
        return $this->memcache->set($cache_key, $data, $expire);
    }

    public function delete($key, $group = 'default') {
        $cache_key = $this->buildKey($key, $group);
        return $this->memcache->delete($cache_key);
    }

    private function buildKey($key, $group) {
        return md5($group . $key);
    }
}

$wp_object_cache = new WP_Object_Cache();
?>

<!-- Performance improvement:
Without object cache: 800ms page load, 45 database queries
With object cache: 120ms page load, 3 database queries (85% improvement)
-->

Example 2: Session Storage

from flask import Flask, session
from flask_session import Session
from pymemcache.client.base import Client

app = Flask(__name__)

# Configure Memcached for sessions
app.config['SESSION_TYPE'] = 'memcached'
app.config['SESSION_MEMCACHED'] = Client(('localhost', 11211))
app.config['SESSION_PERMANENT'] = False
app.config['SESSION_USE_SIGNER'] = True
app.config['SECRET_KEY'] = 'your-secret-key'

Session(app)

@app.route('/login', methods=['POST'])
def login():
    # Session automatically stored in Memcached
    session['user_id'] = user_id
    session['username'] = username
    return jsonify({'status': 'logged in'})

@app.route('/profile')
def profile():
    # Session automatically loaded from Memcached
    user_id = session.get('user_id')
    return jsonify({'user_id': user_id})

# Benefits:
# - Sessions shared across multiple application servers
# - Fast session access (< 1ms)
# - Automatic expiration
# - Reduced database load

Example 3: Database Query Caching

import pymemcache.client.base as memcache
import hashlib
import json
from functools import wraps

mc = memcache.Client(('localhost', 11211))

def cache_query(ttl=3600):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Create cache key from function name and arguments
            key_data = f"{func.__name__}:{str(args)}:{str(kwargs)}"
            cache_key = hashlib.md5(key_data.encode()).hexdigest()

            # Try cache
            cached_result = mc.get(cache_key)
            if cached_result:
                return json.loads(cached_result)

            # Execute query
            result = func(*args, **kwargs)

            # Store in cache
            mc.set(cache_key, json.dumps(result), expire=ttl)

            return result
        return wrapper
    return decorator

# Usage
@cache_query(ttl=1800)
def get_popular_products(limit=10):
    # Expensive database query
    return db.execute("""
        SELECT p.*, COUNT(o.id) as sales
        FROM products p
        JOIN orders o ON p.id = o.product_id
        WHERE o.created_at > NOW() - INTERVAL 30 DAY
        GROUP BY p.id
        ORDER BY sales DESC
        LIMIT %s
    """, (limit,))

# Performance:
# First call: 520ms (database query + cache store)
# Cached calls: 1.2ms (435x faster)
# Database load reduced by 98% (with 98% cache hit rate)

Example 4: API Response Caching

from flask import Flask, jsonify, request
import pymemcache.client.base as memcache
import json
import hashlib

app = Flask(__name__)
mc = memcache.Client(('localhost', 11211))

def cache_api_response(ttl=300):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            # Create cache key from request
            cache_data = f"{request.path}:{request.query_string.decode()}"
            cache_key = f"api:{hashlib.md5(cache_data.encode()).hexdigest()}"

            # Try cache
            cached_response = mc.get(cache_key)
            if cached_response:
                return jsonify(json.loads(cached_response))

            # Generate response
            response_data = func(*args, **kwargs)

            # Cache response
            mc.set(cache_key, json.dumps(response_data), expire=ttl)

            return jsonify(response_data)
        return wrapper
    return decorator

@app.route('/api/products')
@cache_api_response(ttl=600)  # 10 minutes
def get_products():
    category = request.args.get('category')
    products = fetch_products_from_db(category)
    return products

# Results:
# Without cache: 340ms average, high database load
# With cache (90% hit rate): 35ms average, 90% less database load

Example 5: Fragment Caching

def render_product_list(category_id):
    cache_key = f"fragment:product_list:{category_id}"

    # Try to get cached HTML
    cached_html = mc.get(cache_key)
    if cached_html:
        return cached_html.decode('utf-8')

    # Generate HTML
    products = get_products(category_id)
    html = render_template('product_list.html', products=products)

    # Cache fragment (5 minutes)
    mc.set(cache_key, html.encode('utf-8'), expire=300)

    return html

# Performance:
# Without caching: 180ms (database + template rendering)
# With caching: 2ms (99% improvement)

Monitoring and Maintenance

Key Metrics

#!/bin/bash
# Comprehensive Memcached monitoring

echo "stats" | nc localhost 11211 | while read line; do
    case "$line" in
        *curr_items*) echo "$line" ;;
        *total_items*) echo "$line" ;;
        *bytes*) echo "$line" ;;
        *curr_connections*) echo "$line" ;;
        *total_connections*) echo "$line" ;;
        *cmd_get*) echo "$line" ;;
        *cmd_set*) echo "$line" ;;
        *get_hits*) echo "$line" ;;
        *get_misses*) echo "$line" ;;
        *evictions*) echo "$line" ;;
        *bytes_read*) echo "$line" ;;
        *bytes_written*) echo "$line" ;;
    esac
done

Cache Hit Rate Calculation

#!/bin/bash
# Calculate cache hit rate

STATS=$(echo "stats" | nc localhost 11211)

GET_HITS=$(echo "$STATS" | grep "get_hits" | awk '{print $3}')
GET_MISSES=$(echo "$STATS" | grep "get_misses" | awk '{print $3}')

TOTAL=$((GET_HITS + GET_MISSES))

if [ $TOTAL -gt 0 ]; then
    HIT_RATE=$(awk "BEGIN {printf \"%.2f\", ($GET_HITS/$TOTAL)*100}")
    echo "Cache Hit Rate: $HIT_RATE%"
    echo "Total Gets: $TOTAL"
    echo "Hits: $GET_HITS"
    echo "Misses: $GET_MISSES"

    # Alert if hit rate too low
    HIT_RATE_INT=${HIT_RATE%.*}
    if [ $HIT_RATE_INT -lt 80 ]; then
        echo "WARNING: Cache hit rate below 80%" | \
            mail -s "Memcached Alert" [email protected]
    fi
fi

Slab Analysis

# Analyze slab distribution
echo "stats slabs" | nc localhost 11211

# View items in each slab
echo "stats items" | nc localhost 11211

# Check for slab wastage
memcached-tool localhost:11211 display

Troubleshooting

High Eviction Rate

# Check evictions
echo "stats" | nc localhost 11211 | grep evictions

# Causes:
# 1. Memory too small - increase -m parameter
# 2. TTLs too long - reduce expiration times
# 3. Slab allocation issues - adjust growth factor

# Solutions:
# Increase memory
vim /etc/memcached.conf
# Change: -m 4096 to -m 8192

# Or optimize TTLs
# Reduce from 3600 to 1800 for less critical data

Connection Errors

# Check current connections
echo "stats" | nc localhost 11211 | grep curr_connections

# Check if max reached
echo "stats" | nc localhost 11211 | grep maxconns

# Increase connection limit
vim /etc/memcached.conf
# Change: -c 1024 to -c 10240

Memory Fragmentation

# Restart Memcached to defragment
systemctl restart memcached

# Schedule regular restarts during low-traffic periods
# Add to cron (3 AM daily):
# 0 3 * * * systemctl restart memcached

Conclusion

Memcached is a powerful, efficient caching solution that can dramatically improve application performance. Proper configuration and implementation deliver substantial benefits:

Performance Improvements:

  • Response times: 70-95% reduction
  • Database load: 80-95% reduction
  • Throughput: 10-50x increase
  • Infrastructure costs: 40-70% reduction

Key Takeaways:

  1. Simple and fast: Purpose-built for caching
  2. Horizontally scalable: Add servers for more capacity
  3. Memory-efficient: Slab allocation minimizes waste
  4. Multi-threaded: Better CPU utilization than single-threaded alternatives

Best Practices:

  • Allocate sufficient memory to maintain high hit rates
  • Use appropriate TTLs based on data volatility
  • Implement client-side connection pooling
  • Monitor hit rates and evictions
  • Use consistent hashing for distributed setups
  • Secure with network restrictions (bind to localhost or private network)

By implementing these Memcached configurations and strategies, you can build high-performance, scalable applications with minimal complexity and excellent reliability.