html
In Memcached, both ADD
and SET
commands store data, but their behavior differs in one crucial aspect:
// SET will always store the value, overwriting if key exists
memcached.set("user:1001", "{name:'John', email:'john@example.com'}", expirationTime);
// ADD will only store if the key doesn't exist
memcached.add("user:1001", "{name:'John', email:'john@example.com'}", expirationTime);
When to use SET:
- When you need to unconditionally update a cached value
- For cache warming or forced refreshes
- When implementing cache-aside pattern
When to use ADD:
- Implementing distributed locks
- Preventing cache stampedes (thundering herd problem)
- Maintaining atomic counters
Here's how ADD helps prevent multiple concurrent cache misses:
function getExpensiveData(key) {
// Try to get cached data first
let data = memcached.get(key);
if (!data) {
// Only one process will succeed in adding the lock
if (memcached.add(key + "_lock", "1", 5)) {
// Generate expensive data
data = expensiveDatabaseQuery();
// Cache the data
memcached.set(key, data, 3600);
// Release the lock
memcached.delete(key + "_lock");
} else {
// Other processes wait and retry
sleep(100);
return getExpensiveData(key);
}
}
return data;
}
While both commands have similar performance characteristics:
SET
typically has slightly lower overhead as it doesn't need to check existenceADD
requires an existence check but prevents unnecessary overwrites- Network latency dominates both operations
Watch out for these scenarios:
// Problematic race condition:
if (!memcached.get("counter")) {
// Multiple processes might pass this check
memcached.set("counter", 1);
}
// Correct implementation using ADD:
memcached.add("counter", 1); // Only one will succeed
In Memcached, both ADD
and SET
are fundamental operations for storing data, but they behave differently in critical ways:
// SET will always write the value, regardless of existing key
memcached.set("user:1001", "{name:'John', role:'admin'}");
// ADD will only succeed if the key doesn't exist
memcached.add("config:latest_version", "v2.4.1");
Use ADD
when you need to ensure initialization of a value exactly once:
- Creating unique locks or flags
- Initializing configuration values
- Implementing "first-write-wins" scenarios
// Only set default config if it doesn't exist
if (!memcached.add("system:timezone", "UTC")) {
console.log("Timezone already configured");
}
SET
is your go-to for unconditional writes:
- Updating existing values
- Forcing value overwrites
- General caching scenarios
// Update user session unconditionally
memcached.set("session:" + userId, sessionData, 3600);
While both operations have similar O(1) time complexity, ADD
performs an extra existence check internally. In high-throughput systems:
- Prefer
SET
when you expect frequent updates - Use
ADD
only when the uniqueness guarantee is required - Benchmark both operations with your specific workload
ADD
provides atomic "check-and-set" behavior:
// Thread-safe initialization example
function initCounter() {
if (memcached.add("global:counter", 0)) {
return 0;
}
return memcached.get("global:counter");
}
Cache Stampede Prevention:
// Using ADD as a lock
function getExpensiveData(key) {
let data = memcached.get(key);
if (!data) {
if (memcached.add(key + ":lock", "1", 5)) {
data = fetchFromDatabase(key);
memcached.set(key, data, 300);
memcached.delete(key + ":lock");
} else {
// Another process is generating the data
return null;
}
}
return data;
}
Configuration Management:
// Using SET for config updates
function updateConfig(key, value) {
memcached.set("config:" + key, value);
logConfigChange(key, value);
}