memcached persistence in PHP does not work as expected
Asked Answered
G

2

6

i have played a bit around with different memcached library and plugin version to enable real persistence between PHP memcache client and memcached server.

The problem is that still connections are opened and closed so that the connection counter goes up instead of the reusage of a existing persistent connection.

I have compiled the memcached daemon on from newest source on a redhat machine. I use the version memcached-1.4.14 and started with "#/opt/memcached/bin/memcached -vvvv"

The php plugin i have also compiled from newest source version memcached-2.0.1, i have compiled it against libmemcached-1.0.9 to have it up to date. Currently it does not compile against libmemcached-1.0.10.

My PHP script looks like this:

<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");

$key = "key_" . uniqid();
$memcached = new Memcached( 'persistent' );
$memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
$memcached->setOption(Memcached::OPT_RECV_TIMEOUT, 1000);
$memcached->setOption(Memcached::OPT_SEND_TIMEOUT, 3000);
$memcached->setOption(Memcached::OPT_TCP_NODELAY, true);
$memcached->setOption(Memcached::OPT_PREFIX_KEY, 'persistent');

if( !count($memcached->getServerList() ) )
{
    $memcached->addServer( 'localhost', 11211 );
}
$memcached->set($key, 'value');
$value = $memcached->get($key);

print_r( $memcached->getStats() );
?>

On firing the script i see in the output that servers are not added, only after timeout period.

Array ( [@�qVG:11211] => Array ( [pid] => 3728 [uptime] => 73 [threads] => 4 [time] => 1343813688 [pointer_size] => 64 [rusage_user_seconds] => 0 [rusage_user_microseconds] => 6998 [rusage_system_seconds] => 0 [rusage_system_microseconds] => 31995 [curr_items] => 37 [total_items] => 37 [limit_maxbytes] => 67108864 [curr_connections] => 38 [total_connections] => 47 [connection_structures] => 39 [bytes] => 3589 [cmd_get] => 37 [cmd_set] => 37 [get_hits] => 37 [get_misses] => 0 [evictions] => 0 [bytes_read] => 3267 [bytes_written] => 39458 [version] => 1.4.14 ) )

But the connection counter still goes up and i suppose that the client creates a connection and on server side the persistent connection is re-used.

#netstat -an | grep 11211 | wc -l

tcp        0      0 ::1:11211                   ::1:55941                   VERBUNDEN   
tcp        0      0 ::1:55961                   ::1:11211                   VERBUNDEN   
tcp        0      0 ::1:55959                   ::1:11211                   VERBUNDEN   
tcp        0      0 ::1:11211                   ::1:56005                   VERBUNDEN   
...and so on

On server side i get verbous output that tells me that persistence is used:

...
<43 get persistentkey_5018f83903ded
> FOUND KEY persistentkey_5018f83903ded
>43 sending key persistentkey_5018f83903ded
>43 END
...

We want to use memcache on a high performance environment with a lot of incomming connections, and the connection amout does kill the apache childs currently. Any ideas how to enable real persistence?

Used software:

  • Red Hat Enterprise Linux Server release 6.2 (Santiago)
  • PHP Version 5.3.3
  • Apache/2.2.15 in Prefork
  • Memcache server 1.4.14
  • libmemcached 1.0.9
  • PHP memcached plugin 2.0.1
Grundyism answered 1/8, 2012 at 9:51 Comment(2)
This is interesting. I believe I am using some kind of old version of memcache php plugin, but I generally use only 4 functions. connect, get, set and flush. usually a script on my server creates a memcache server if it's not running.Kalfas
How many prefork servers do you have running at any given time? You could have as many persistent connections as you have parent servers running. Say you have 20 StartServers and 50 threads per server, each of those 20 servers could have their own persistent connection to memcached, and the 50 child threads for each server would use their parent's persistent connection. Do the PID's of those connections match up with the PIDs from each of your child processes?Visa
A
2

That's because you are setting the Memcached::OPT_TCP_NODELAY at every requests. Some options like this one causes the libmemcached library to perform a re-connection at the moment you are setting it.

Since the connection options persist, there is just no reason to set them at every requests. You should therefore use:

<?php
header("Cache-Control: no-cache, must-revalidate");
header("Expires: Sat, 26 Jul 1997 05:00:00 GMT");

$key = "key_" . uniqid();
$memcached = new Memcached( 'persistent' );

if( !count($memcached->getServerList() ) )
{
    $memcached->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, true);
    $memcached->setOption(Memcached::OPT_RECV_TIMEOUT, 1000);
    $memcached->setOption(Memcached::OPT_SEND_TIMEOUT, 3000);
    $memcached->setOption(Memcached::OPT_TCP_NODELAY, true);
    $memcached->setOption(Memcached::OPT_PREFIX_KEY, 'persistent');
    $memcached->addServer( 'localhost', 11211 );
}
$memcached->set($key, 'value');
$value = $memcached->get($key);

print_r( $memcached->getStats() );
?>
Autoicous answered 18/12, 2012 at 17:3 Comment(2)
That works fine for me, thank you for resolving the issue. I realize that in apache prefork mode two connections are opened for each apache child process, which seems to be a normal behavior. I see in the connections log: #netstat -n|grep 11211|grep "::"|wc -l 60 and this matches the apache processes #ps uax|grep httpd|wc -l 31 (master prozess and 30 childs)Grundyism
Was running out of local ports. Your answer saved my day. Thanks a lot!Parachronism
D
-1

I don't believe a real persistent can be achieved with Memcached extension. From PHP's persistent documentation:

If your using PHP-CGI

A persistent connection can be shared throughout the application process, but will be closed on script completion (page load);

If your using Apache's multiprocess module

A request will spin-off a child process with a persistent connection. Provided a new request comes in, and the previous one has yet to complete, the existing persistent connection will be used. However, if no additional request are made, the persistent connection will be closed when the child process completes.

The script you provided might be effective in testing memcached, but running it manually may not. Take a look at jMeter. You can quickly create a thread group, and throw a 100+ user at your application.

Done answered 7/8, 2012 at 20:34 Comment(1)
Yes, real persistent connections are supported by the Memcached extension.Autoicous

© 2022 - 2024 — McMap. All rights reserved.