All Products
Search
Document Center

ApsaraDB for Memcache:Use PHP persistent connections to improve performance

Last Updated:Jun 10, 2026

PHP applications that connect to ApsaraDB for Memcache through Apache use short-lived connections by default. Each short-lived connection incurs a socket handshake and a full Simple Authentication and Security Layer (SASL) re-authentication on every request — far more expensive than the cache lookup itself. Switching to persistent connections eliminates this per-request overhead and is the most effective way to improve throughput under load.

Prerequisites

Before you begin, make sure you have:

  • The PHP Memcached extension installed (not the memcache extension)

  • An ApsaraDB for Memcache instance endpoint and port

  • Valid SASL credentials (username and password)

How it works

The PHP Memcached extension achieves connection persistence through the persistent_id constructor parameter, not through a pconnect() method. All instances created with the same persistent_id string share a single connection pool.

From the PHP Memcached documentation:

Memcached::__construct([ string $persistent_id ])

Creates a Memcached instance. By default, the instance is destroyed after the request ends.
Specifying a persistent_id causes the instance — and its underlying connections — to persist
across requests. All instances sharing the same persistent_id share the same connection pool.

Call new Memcached('ocs') from any PHP request and you get a connection from the named pool rather than opening a new socket.

Enable persistent connections

The key pattern is to guard all initialization with a getServerList() check. If the pool already exists (non-empty server list), skip initialization entirely — including addServer() and all setOption() calls. Re-running those calls on an existing persistent pool can cause reconnections or silently convert a persistent connection into a short-lived one.

<?php
$memc = new Memcached('ocs'); // 'ocs' is the persistent_id — the name of the connection pool

if (count($memc->getServerList()) == 0) {
    // Pool does not exist yet — initialize it.
    // All setOption() calls must be inside this block.
    // Calling setOption() on an existing pool can trigger a reconnection
    // or silently downgrade the persistent connection to a short-lived one.
    echo "New connection" . "<br>";

    $memc->setOption(Memcached::OPT_COMPRESSION, false);
    $memc->setOption(Memcached::OPT_BINARY_PROTOCOL, true);
    // OPT_TCP_NODELAY eliminates a fixed 40 ms latency that occurs when a get
    // returns no value, caused by a known bug in the PHP Memcached extension.
    $memc->setOption(Memcached::OPT_TCP_NODELAY, true);

    // addServer() must also be inside this block.
    // Calling addServer() on an existing pool duplicates the server entry
    // and can cause client-side exceptions.
    $memc->addServer("your_ip", 11212);
    $memc->setSaslAuthData("user", "password");
} else {
    echo "Now connections is:" . count($memc->getServerList()) . "<br>";
}

$memc->set("key", "value");
echo "Get from OCS: " . $memc->get("key");

// Do not call $memc->quit() here.
// quit() closes the underlying socket and converts the persistent connection
// back into a short-lived one.
?>

Three rules to follow:

  • getServerList() guard: Wrap all initialization in a getServerList() == 0 conditional. Without this check, every request re-runs addServer(), duplicates the server entry in the 'ocs' pool, and causes client-side exceptions.

  • All options inside the guard: Any setOption() call outside the guard can trigger a reconnection or silently downgrade the persistent connection to a short-lived one. Keep every option call inside the if block.

  • No quit() at the end: Calling $memc->quit() closes the underlying socket and converts the persistent connection back into a short-lived one. Remove it.

Verify the result

Place the code at /var/www/html/test.php and open http://your_ip:80/test.php in a browser.

The first eight requests each print:

New connection
Get from OCS: value

Subsequent requests reuse the existing connections — no new socket handshake, no re-authentication. Packet capture confirms this.

The number of "new connection" messages matches Apache's StartServers setting:

# Number of server processes to start
StartServers 8

Apache starts eight subprocesses at startup. Each subprocess initializes one connection under the 'ocs' pool, giving you eight persistent connections total. All subsequent requests across those subprocesses reuse those eight connections.

Persistence across page navigations

To confirm persistence across page navigations, copy the PHP file and keep the same persistent_id ('ocs'). Navigating between pages may switch to a different Apache subprocess — and therefore a different connection — but no socket reconnection or re-authentication occurs. This confirms that PHP Memcached persistent connections are working correctly.

In PHP-FPM mode, the behavior is the same: each FPM worker process holds its own persistent connection to the Memcache server, and that connection lives for the lifetime of the worker process.