Using Memcached for PHP Sessions

In modern web architectures, storing PHP sessions on the local filesystem prevents horizontal scaling. If a user logs into Web Server A, and their next request is routed to Web Server B, they will be logged out because Server B lacks the session file.

The php-memcached extension includes a highly robust, drop-in replacement session handler. By storing sessions in a centralized Memcached cluster, your application becomes completely stateless, allowing you to add or remove web servers at will.

1. Basic Configuration

To configure PHP to use Memcached for sessions, you edit your php.ini file. Do not use the memcache handler, explicitly use memcached.

; Set the session handler to memcached
session.save_handler = memcached

; Define the server(s). Multiple servers are separated by commas.
; Format: hostname:port
session.save_path = "10.0.0.10:11211,10.0.0.11:11211"

2. Session Locking (Preventing Race Conditions)

One of the most critical features of the php-memcached session handler is Session Locking.

When an AJAX-heavy application makes multiple concurrent requests using the same session ID, PHP natively locks the session file so that request #2 waits for request #1 to finish writing session data. php-memcached replicates this behavior in the cache.

Without locking, concurrent requests would overwrite each other's session data (e.g., losing items added to a shopping cart).

Lock Configuration Directives

; Enable session locking (Default: On)
memcached.sess_locking = On

; Minimum time (ms) to wait before polling the lock again (Default: 150)
memcached.sess_lock_wait_min = 150

; Maximum time (ms) to wait before polling the lock again (Default: 150)
; (The wait time doubles on each retry until it hits this max)
memcached.sess_lock_wait_max = 150

; Maximum number of times to retry getting the lock before giving up (Default: 5)
memcached.sess_lock_retries = 5

; How long (in seconds) the lock lives before automatically expiring.
; 0 means it falls back to PHP's max_execution_time. (Default: 0)
memcached.sess_lock_expire = 0

Common Pitfall: If you see the warning Unable to clear session lock record or Failed to read session data in your PHP logs, it means memcached.sess_lock_retries was exhausted. The script waited too long for another script to release the lock. You may need to optimize your slow requests, call session_write_close() earlier in your code, or increase the retries.

3. High Availability (Redundancy)

Memcached is an in-memory cache, meaning if a server crashes or restarts, all data (and therefore all active sessions) are lost.

To mitigate this, libmemcached provides a "Poor Man's High Availability" feature. It can write your session data to the primary server and simultaneously replicate it to backup servers.

; Write session data to this many additional servers (Default: 0)
memcached.sess_number_of_replicas = 1

; Randomize which replica is read from (Default: Off)
memcached.sess_randomize_replica_read = Off

; Automatically remove servers that fail continuously (Default: Off)
memcached.sess_remove_failed_servers = On

; How many times a server must fail before removal (Default: 0)
memcached.sess_server_failure_limit = 3

Caveat: Because Memcached uses LRU (Least Recently Used) eviction, if a replica server is full, it might evict your backup session data. This feature provides redundancy against sudden node failure, but it is not guaranteed persistent storage.

4. Connection & Protocol Settings

These directives optimize how the session handler communicates with the daemon.

; Use the efficient Binary Protocol for sessions. 
; MUST be On if you are using sess_number_of_replicas or SASL. (Default: On)
memcached.sess_binary_protocol = On

; Keep connections open between requests, heavily reducing TCP overhead. (Default: Off)
memcached.sess_persistent = On

; Add a prefix to all session keys to separate them from general app cache. (Default: memc.sess.key.)
memcached.sess_prefix = "sess_"

; Ensure consistent hashing is used so removing a server doesn't destroy all sessions. (Default: On)
memcached.sess_consistent_hash = On

; The hashing algorithm. (Default: ketama)
memcached.sess_consistent_hash_type = "ketama"

5. SASL Authentication

If you are using a managed Memcached service (like AWS ElastiCache with authentication enabled, or Memcached Enterprise) that requires SASL authentication, configure the credentials directly in the .ini file:

memcached.sess_sasl_username = "your_app_user"
memcached.sess_sasl_password = "SuperSecretToken123"

(Note: SASL authentication requires memcached.sess_binary_protocol = On).