Using php5-memcached to store sessions on distributed servers

This article is an extension of the previous article about storing sessions in Memcached with PHP. Using Memcached for sessions storage is generally a matter of speed (storing them in memory is faster than on disk) and of scalability (using a Memcached server allows you to have several web servers serving the same PHP application in a seamless way). In the previous article, we mentioned (3 years ago) that the php5-memcached extension did not seem to manage the storage of sessions quite well, or at least that the configuration of such setup was not well documented. This time, we've been able to do it with php5-memcached. This time also, we're talking about distributing Memcached on several servers. Typically, in a cloud environment with several web servers and no dedicated memcached server, or a need for some kind of fail-over solution for the memcached server. We're setting this up on 3 Ubuntu 14.04 servers in 64bit that act as load-balanced web servers behind a load balancer managed by Nginx. If you use another distribution or operating system, you might need to adapt the commands we're showing here.

Installing Memcached + PHP

So the few commands you need to launch first are to install the required software, on the 3 web servers (you can either do that on one of them then replicate the image if you are using Cloud instances, or you can install simultaneously on your 3 web servers using ClusterSSH, for example, with the cssh server1 server2 server3 command) :
sudo apt-get install memcached php5-memcached
sudo service apache2 restart
The second command is to make sure Apache understands the php5-memcached extension is there. In order to enable the connection to Memcached from the different load-balanced servers, we need to change the Memcached configuration to listen on the external IP address. Check the IP address with /sbin/ifconfig. The Memcached configuration file is located in /etc/memcached.conf. Locate the "-l" option and change "127.0.0.1" for your external IP, then save and close the file. Note that this might introduce a security flaw, where you are possibly opening the connection to your Memcached server to the outside world. You can prevent that using a firewall (iptables is a big classic, available on Ubuntu) Next, restart the Memcached daemon:
sudo service memcached restart
Now you have a Memcached server running on each of your web servers, accessible from the other web servers. To test this, connect to any of your web servers and try a telnet connection on the default Memcached port: 11211, like so:
user@server1$ telnet ip-server2 11211
To get out of there, just type "quit" and Enter. OK, so now we have 3 Memcached servers, we only need to wrap up configuring PHP to use these Memcached servers to store sessions.

Configuring PHP to use Memcached as session storage

This is done by editing your Apache VirtualHost files (on each web server) and adding (before the closing </VirtualHost> tag) the following PHP settings:
 php_admin_value session.save_handler memcached
 php_admin_value session.save_path "ip-server1:11211,ip-server2:11211,ip-server3:11211"
Now reload your web server:
 sudo service apache2 reload
You should now be able to connect to your web application using the distributed Memcached server as a session storage (you usually don't need to change anything in your application itself, but some might exceptionally define their own session storage policy).

The dangers of using a distributed Memcached server

Apart from the possible open access to your Memcached server previously mentioned, which is particularly security-related, you have to take another danger, mostly high-availability related, into account. When using a distributed Memcached server configuration, it is important to understand that it works as sharded spaces configuration. That is, it doesn't store the same sessions over on the various available Memcached server. It only stores each single session in one single server. The decision of where it will store the session is out of the context of this article, but it means that, if you have 300 users with active sessions on your system at any one time, and one of your web servers goes down, you still have 2 web servers and 2 Memcached servers, but ultimately around 100 users will loose their session (that was stored on the web server that went down). Worst: the PHP configuration will not understand this, and still try to send sessions to the server that was considered to hold these 100 sessions, making it impossible for the users to login again until the corresponding Memcached server is back up (unless you change the configuration in your PHP configuration). This is why you have to consider 2 things, and why this article is just one step in the right direction:
  • you should configure the Memcached servers from inside your application for the sessions management (as such, you should have a save_handler defined inside it and check for the availability of each server *before* you store the session in it)
  • if your sessions are critical, you should always have some kind of data persistence mechanism, whereby (for example), you store the session in the database once every ten times it is modified
We hope this was of some use to you in understanding how to use Memcached for sessions storage in PHP. Please don't hesitate to leave questions or comments below.

Comments

[&#8230;] as of July 2014, there is a recent article discussing the use of php5-memcache instead of php5-memcache to store sessions on this [&#8230;]

you specified that we should configure the Memcached servers from inside our application for the sessions management (as such, you should have a save_handler defined inside it and check for the availability of each server *before* you store the session in it).
Please explain how to do it.

En réponse à par YW

Permalien

We recently worked on that. You can find an example in the following pull requests (not yet entirely functional in the context of Chamilo, but you'll get an idea from the code, the foreach() statement, the array included, the elements checked, etc): https://github.com/chamilo/chamilo-lms/pull/344/files