Configure Memcached for Django in Production
Configure Memcached as Django’s cache in production: choose PyMemcacheCache, size memory and item limits, run several nodes with consistent hashing, secure the port, handle failures gracefully, and know what not to store there.
Problem statement
Memcached is a fast, simple, memory-only key-value cache, and Django has supported it from the start. It is a good fit when you need a shared cache across Gunicorn workers and servers and nothing more: no persistence, no queues, no data structures. Getting it right in production means picking the maintained client backend, giving it enough memory, understanding its 1 MB item limit and eviction, keeping it off the public internet, and making sure a cache outage slows the site down instead of breaking it.
pip install pymemcacheand setBACKEND: django.core.cache.backends.memcached.PyMemcacheCache.- Start Memcached with an explicit memory limit (
-m 1024), connection limit (-c 2048), and bind to a private address. - List several nodes in
LOCATIONfor capacity; the client spreads keys across them. - Keep values well under the 1 MB item limit, or raise
-Ideliberately. - Set
KEY_PREFIXper environment and reasonableTIMEOUTs. - Do not store sessions only in Memcached; use
cached_dbso evictions do not log users out.
Step-by-step solution
1. Install and configure Memcached
sudo apt install -y memcached
# /etc/memcached.conf
-m 1024 # MB of RAM for items
-c 2048 # max simultaneous connections
-l 10.0.0.21 # private interface only
-U 0 # disable UDP (amplification risk)
-I 2m # max item size, default 1m
sudo systemctl restart memcached
Memcached has no authentication in its default text protocol, so network isolation is the security model: bind to a private address and firewall the port (11211) to app servers only. Disabling UDP closes the reflection-attack vector that made exposed Memcached servers infamous.
2. Configure Django
CACHES = {
"default": {
"BACKEND": "django.core.cache.backends.memcached.PyMemcacheCache",
"LOCATION": ["10.0.0.21:11211", "10.0.0.22:11211"],
"TIMEOUT": 300,
"KEY_PREFIX": "myapp-prod",
"OPTIONS": {
"no_delay": True,
"ignore_exc": True, # treat errors as misses
"max_pool_size": 8,
"use_pooling": True,
"connect_timeout": 0.5,
"timeout": 0.5,
},
}
}
PyMemcacheCache (Django 3.2+) uses the maintained pymemcache client; the older MemcachedCache backend (python-memcached) was removed. ignore_exc makes a dead node behave like a cache miss instead of raising, and short timeouts keep requests from hanging on an unreachable node.
3. Mind the item size
A value over the item limit (1 MB by default) is silently not stored with some clients, or raises. Large querysets, rendered pages, or JSON blobs can exceed it. Cache smaller pieces, compress (pymemcache supports serde with compression), or raise -I with awareness that larger items use memory less efficiently.
4. Use keys and timeouts deliberately
- Prefix keys per environment so staging and production never share entries if they ever share a server.
- Use
cache.get_or_set(key, func, timeout)for read-through caching. - Version keys when the format changes (
cache.set(key, value, version=2)). - Remember
TIMEOUT: Nonemeans "never expire", and0means "do not cache".
5. Sessions and Memcached
SESSION_ENGINE = "django.contrib.sessions.backends.cache" stores sessions only in Memcached, so a restart or eviction logs users out. Use the write-through cached_db engine to read from cache and fall back to the database:
SESSION_ENGINE = "django.contrib.sessions.backends.cached_db"
Verification check:
echo stats | nc 10.0.0.21 11211 | grep -E "get_hits|get_misses|evictions|curr_connections"
python manage.py shell -c "from django.core.cache import cache; cache.set('probe', 1, 30); print(cache.get('probe'))"
A healthy cache shows rising hits, few evictions, and the probe value returned.
Explanation
Memcached is a distributed hash table where the client decides which server holds each key, using consistent hashing so adding or removing a server remaps only a fraction of keys. Servers do not talk to each other, do not persist anything, and evict least-recently-used items when memory is full. That simplicity makes it extremely fast and easy to operate, and also defines how to use it: only for data that can be recomputed, with the database ready to answer every miss.
Edge cases / notes
- Managed options include Amazon ElastiCache for Memcached and Google Cloud Memorystore for Memcached.
- SASL authentication is possible with the binary protocol but rarely used; rely on network isolation.
- Cache stampede. Many workers recomputing one expired hot key at once can overload the database; use short random jitter or a lock for expensive keys.
- Redis instead when you also need Celery, rate limiting, persistence, or data structures.
Next steps
- Decide what to cache with Django Caching Strategy for Production.
- Compare with the Redis setup in Set Up a Redis Cache for Django in Production.
FAQ
Which Memcached backend should Django use?
PyMemcacheCache, based on the maintained pymemcache client.
Is Memcached secure to expose?
No. It has no authentication by default. Bind it to private addresses and firewall the port.
Can I store sessions in Memcached?
Use the cached_db engine so sessions survive evictions and restarts.
What is the maximum item size?
1 MB by default, adjustable with Memcached's -I option.