Multiple memcached instances on one server

I had to run multiple WordPress sites on one server and for fast loading I’m using memcached plugin and the solution was multiple memcached instances.

Install Memcached  and changes

First install memcached and PHP5 extension

apt-get install memcached php5-memcached

Change the startup script

vi /etc/init.d/memcached
#! /bin/sh
### BEGIN INIT INFO
# Provides:		memcached
# Required-Start:	$syslog
# Required-Stop:	$syslog
# Should-Start:		$local_fs
# Should-Stop:		$local_fs
# Default-Start:	2 3 4 5
# Default-Stop:		0 1 6
# Short-Description:	memcached - Memory caching daemon
# Description:		memcached - Memory caching daemon 
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/memcached
DAEMONNAME=memcached
DAEMONBOOTSTRAP=/usr/share/memcached/scripts/start-memcached
DESC=memcached

test -x $DAEMON || exit 0
test -x $DAEMONBOOTSTRAP || exit 0

set -e

FILES=(/etc/memcached_*.conf);
# check for alternative config schema
if [ -r "${FILES[0]}" ]; then
  CONFIGS=();
  for FILE in "${FILES[@]}";
  do
    # remove prefix
    NAME=${FILE#/etc/};
    # remove suffix
    NAME=${NAME%.conf};

    # check optional second param
    if [ $# -ne 2 ];
    then
      # add to config array
      CONFIGS+=($NAME);
    elif [ "memcached_$2" == "$NAME" ];
    then
      # use only one memcached
      CONFIGS=($NAME);
      break;
    fi;
  done;

  if [ ${#CONFIGS[@]} == 0 ];
  then
    echo "Config not exist for: $2" >&2;
    exit 1;
  fi;
else
  CONFIGS=(memcached);
fi;

CONFIG_NUM=${#CONFIGS[@]};
for ((i=0; i < $CONFIG_NUM; i++)); do
  NAME=${CONFIGS[${i}]};
  PIDFILE="/var/run/${NAME}.pid";

case "$1" in
  start)
	echo -n "Starting $DESC: "
        start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE
	echo "$NAME."
	;;
  stop)
	echo -n "Stopping $DESC: "
	start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON 
	echo "$NAME."
	rm -f $PIDFILE
	;;

  restart|force-reload)
	#
	#	If the "reload" option is implemented, move the "force-reload"
	#	option to the "reload" entry above. If not, "force-reload" is
	#	just the same as "restart".
	#
	echo -n "Restarting $DESC: "
	start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE
	rm -f $PIDFILE
	sleep 1
        start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE
	echo "$NAME."
	;;
  *)
	N=/etc/init.d/$NAME
	# echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2
	echo "Usage: $N {start|stop|restart|force-reload}" >&2
	exit 1
	;;
esac
done;

exit 0

Change the start file

vi /usr/share/memcached/scripts/start-memcached
#!/usr/bin/perl -w

# start-memcached
# 2003/2004 - Jay Bonci 
# This script handles the parsing of the /etc/memcached.conf file
# and was originally created for the Debian distribution.
# Anyone may use this little script under the same terms as
# memcached itself.

use strict;

if($> != 0 and $< != 0)
{
	print STDERR "Only root wants to run start-memcached.\n";
	exit;
}

my $params; my $etchandle; my $etcfile = "/etc/memcached.conf";

# This script assumes that memcached is located at /usr/bin/memcached, and
# that the pidfile is writable at /var/run/memcached.pid

my $memcached = "/usr/bin/memcached";
my $pidfile = "/var/run/memcached.pid";

if (scalar(@ARGV) == 2) {
	$etcfile = shift(@ARGV);
	$pidfile = shift(@ARGV);
}

# If we don't get a valid logfile parameter in the /etc/memcached.conf file,
# we'll just throw away all of our in-daemon output. We need to re-tie it so
# that non-bash shells will not hang on logout. Thanks to Michael Renner for 
# the tip
my $fd_reopened = "/dev/null";

	sub handle_logfile
	{
		my ($logfile) = @_;
		$fd_reopened = $logfile;
	}

	sub reopen_logfile
	{
		my ($logfile) = @_;

		open *STDERR, ">>$logfile";
		open *STDOUT, ">>$logfile";
		open *STDIN, ">>/dev/null";
		$fd_reopened = $logfile;
	}

# This is set up in place here to support other non -[a-z] directives

my $conf_directives = {
	"logfile" => \&handle_logfile,
};

if(open $etchandle, $etcfile)
{
	foreach my $line (< $etchandle>)
	{
		$line ||= "";
		$line =~ s/\#.*//g;
		$line =~ s/\s+$//g;
		$line =~ s/^\s+//g;
		next unless $line;
		next if $line =~ /^\-[dh]/;

		if($line =~ /^[^\-]/)
		{
			my ($directive, $arg) = $line =~ /^(.*?)\s+(.*)/; 
			$conf_directives->{$directive}->($arg);
			next;
		}

		push @$params, $line;		
	}

}else{
	$params = [];
}

	push @$params, "-u root" unless(grep "-u", @$params);
	$params = join " ", @$params;

if(-e $pidfile)
{
	open PIDHANDLE, "$pidfile";
	my $localpid = <PIDHANDLE>;
	close PIDHANDLE;

	chomp $localpid;
	if(-d "/proc/$localpid")
	{
		print STDERR "memcached is already running.\n"; 
		exit;		
	}else{
		`rm -f $localpid`;
	}

}

my $pid = fork();

if($pid == 0)
{
		reopen_logfile($fd_reopened);
		exec "$memcached $params";
		exit(0);

}else{
	if(open PIDHANDLE,">$pidfile")
	{
		print PIDHANDLE $pid;
		close PIDHANDLE;
	}else{

		print STDERR "Can't write pidfile to $pidfile.\n";
	}
}

Setup multiple config files

The following modifications will search for config files with the following pattern /etc/memcached_*.conf, so if you have 2 websites you can copy memcached.conf file and change the instance port.

cp /etc/memcached.conf /etc/memcached_website1.conf
cp /etc/memcached.conf /etc/memcached_website2.conf

Now you can start all servers at once with:

/etc/init.d/memcached start

Or add website1 or website2 at the end to start/stop/restart specific memcached instance

/etc/init.d/memcached restart website2

Original patches: https://gist.github.com/jonhiggs/516746