Memcached doesn’t actually have a "maximum item count" limit; it has a memory limit, and when that’s full, it starts evicting older items.
Let’s see this in action. Imagine we have a Memcached instance running, and we’re pushing data into it.
# Start a Memcached instance (for demonstration)
memcached -p 11211 -m 64
# Simulate adding items
for i in $(seq 1 10000); do
echo "set mykey_$i 0 60 10" | nc localhost 11211
echo "some_value_$i" | nc localhost 11211
done
As we add items, Memcached uses the allocated memory (64MB in this example). It keeps track of items and their associated memory. When the 64MB is full, it doesn’t refuse new items; it employs an LRU (Least Recently Used) eviction policy.
The core problem Memcached solves is fast, in-memory key-value storage, reducing database load and improving application response times. It’s a cache. Its internal mechanism is relatively simple: a hash table maps keys to item data, and a linked list manages eviction order. When you set an item, it’s added to the hash table and the front of the LRU list. When you get an item, it’s moved to the front of the LRU list. When memory is full, the item at the end of the LRU list is removed to make space.
The "limit" isn’t a hard count, but rather the total memory available. If you have 100 million tiny items or 100 large items, what matters is the sum of their sizes plus Memcached’s internal overhead.
The primary lever you control is the -m (memory allocation) flag when starting Memcached. A larger value allows more items to reside in memory simultaneously.
# Increasing memory allocation
memcached -p 11211 -m 128
Another factor is item size. Smaller items allow for a higher effective item count within the same memory limit. Conversely, a few very large items can quickly fill the cache.
Consider the cas (compare-and-swap) field in Memcached. When you get an item, Memcached returns a unique, monotonically increasing integer value for that key. If another client modifies the item and then you try to cas with the old cas value, your update will be rejected. This prevents race conditions where stale data is overwritten. This cas value is stored alongside the item’s data in memory and contributes to its overall memory footprint.
The eviction process is deterministic based on memory usage and access patterns, not a simple count. If you have 100 million items and only 64MB of memory, most items will be evicted almost immediately after being set, making Memcached effectively useless for those items. The key is to size Memcached’s memory appropriately for the working set of your application.
If you’re consistently hitting eviction and performance degrades, it means your cache is too small for your current data access patterns, or your items are too large. You’re not hitting an item count limit, but a memory capacity limit.
The next concept you’ll likely grapple with is cache invalidation strategies beyond simple LRU, especially when dealing with complex data relationships or eventual consistency requirements.