09.01.2013

Repcache - кластеризация Memcache'а

Не понравился мне CouchBase. Причина - он написан на Java. А чтобы починить продукт на Java нужно быть Java-программистом и уметь читать эксепшены (а это подразумевает, что продукт писал ты сам, потому что эксепшен незнакомой программы понять физически невозможно). Еще сильнее убила нерабочая функция flush_all.
Ну пусть они сами своим барахлом и пользуются. А нам кто-то неизвестный великодушно дал еще один продукт, но на приличном языке Си: repcached.

Ну как водится, показываю как это сделать для Debian.

Сначала соберем пакет.
Нам понадобится одна зависимость и одна утилита:
apt-get install libevent-dev checkinstall

Создадим рабочую директорию:
mkdir /usr/src/repcached
cd /usr/src/repcached
Скачаем дистрибутив в эту директорию.

Распакуем его и перейдем внутрь:
tar xzf memcached-1.2.8-repcached-2.2.tar.gz
cd memcached-1.2.8-repcached-2.2
Далее есть баг, который заключается в том, что переменная IOV_MAX объявляется только для FreeBSD, а у нас Debian. Если этого не сделать, то ошибка при компиляции выскочит такая:
error: ‘IOV_MAX’ undeclared (first use in this function)



Поэтому уберем условие, что это только для FreeBSD:
vi +57 memcached.c
#ifndef IOV_MAX
#if defined(__FreeBSD__) || defined(__APPLE__)
# define IOV_MAX 1024
#endif
#endif

Теперь сконфигурируем и скомпилируем:
./configure --enable-replication --enable-64bit
make
Подготовим конфиги и init-скрипты.
Сначала список файлов, который пойдет в пакет:
cat > include-pak
etc/repcached.conf
etc/default/repcached
usr/share/memcached/scripts/start-repcached
etc/init.d/repcached
А теперь создадим эти директории и файлы:
mkdir -p etc/default usr/share/memcached/scripts etc/init.d
Ну и сами файлы:
cat > etc/repcached.conf
# repcached default config file
# 2003 - Jay Bonci <jaybonci@debian.org>
# This configuration file is read by the start-repcached script provided as
# part of the Debian GNU/Linux distribution.
# Run repcached as a daemon. This command is implied, and is not needed for the
# daemon to run. See the README.Debian that comes with this package for more
# information.
-d
# Log repcached's output to /var/log/repcached
logfile /var/log/repcached.log
# Be verbose
# -v
# Be even more verbose (print client commands as well)
# -vv
# Start with a cap of 64 megs of memory. It's reasonable, and the daemon default
# Note that the daemon will grow to this size, but does not start out holding this much
# memory
-m 64
# Default connection port is 11211
-p 11211
# Run the daemon as root. The start-memcached will default to running as root if no
# -u command is present in this config file
-u nobody
# Specify which IP address to listen on. The default is to listen on all IP addresses
# This parameter is one of the only security measures that memcached has, so make sure
# it's listening on a firewalled interface.
# -l 127.0.0.1
# Limit the number of simultaneous incoming connections. The daemon default is 1024
# -c 1024
# Lock down all paged memory. Consult with the README and homepage before you do this
# -k
# Return error when memory is exhausted (rather than removing items)
# -M
# Maximize core file limit
# -r
# Remote Repcache sync node's port
-X 11212
# Remote Repcache sync node's IP or hostname
-x IPorHOST.ofREMOTE.SYNC.NODE
cat > etc/default/repcached
# Set this to no to disable repcached.
ENABLE_REPCACHED=yes
cat > usr/share/memcached/scripts/start-repcached
#!/usr/bin/perl -w
# start-repcached
# 2003/2004 - Jay Bonci <jaybonci@debian.org>
# This script handles the parsing of the /etc/repcached.conf file
# and was originally created for the Debian distribution.
# Anyone may use this little script under the same terms as
# repcached itself.
use POSIX qw(setsid);
use strict;
if($> != 0 and $< != 0)
{
    print STDERR "Only root wants to run start-repcached.\n";
    exit;
}
my $params; my $etchandle; my $etcfile = "/etc/repcached.conf";
# This script assumes that repcached is located at /usr/local/bin/memcached, and
# that the pidfile is writable at /var/run/repcached.pid
my $memcached = "
/usr/local/bin/memcached";
my $pidfile = "/var/run/repcached.pid";
if (scalar(@ARGV) == 2) {
    $etcfile = shift(@ARGV);
    $pidfile = shift(@ARGV);
}
# If we don't get a valid logfile parameter in the /etc/repcached.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 "repcached is already running.\n";
        exit;
    }else{
        `rm -f $localpid`;
    }
}
my $pid = fork();
if($pid == 0)
{
    # setsid makes us the session leader
    setsid();
    reopen_logfile($fd_reopened);
    # must fork again now that tty is closed
    $pid = fork();
    if ($pid) {
      if(open PIDHANDLE,">$pidfile")
      {
          print PIDHANDLE $pid;
          close PIDHANDLE;
      }else{
          print STDERR "Can't write pidfile to $pidfile.\n";
      }
      exit(0);
    }
    exec "$memcached $params";
    exit(0);
}
cat > etc/init.d/repcached
#! /bin/bash
### BEGIN INIT INFO
# Provides:            repcached
# Required-Start:      $remote_fs $syslog
# Required-Stop:       $remote_fs $syslog
# Should-Start:                $local_fs
# Should-Stop:         $local_fs
# Default-Start:       2 3 4 5
# Default-Stop:                0 1 6
# Short-Description:   Start repcached daemon
# Description:         Start up repcached, a high-performance memory caching daemon cluster
### END INIT INFO
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=
/usr/local/bin/memcached
DAEMONNAME=repcached
DAEMONBOOTSTRAP=/usr/share/memcached/scripts/start-repcached
DESC=repcached
test -x $DAEMON || exit 0
test -x $DAEMONBOOTSTRAP || exit 0
set -e
. /lib/lsb/init-functions
# Edit /etc/default/repcached to change this.
ENABLE_REPCACHED=no
test -r /etc/default/repcached && . /etc/default/repcached

NAME=$DAEMONNAME
PIDFILE="/var/run/${NAME}.pid"
case "$1" in
  start)
       echo -n "Starting $DESC: "
       if [ $ENABLE_REPCACHED = yes ]; then
            start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE
            echo "$NAME."
       else
            echo "$NAME disabled in /etc/default/repcached."
       fi
       ;;
  stop)
       echo -n "Stopping $DESC: "
       start-stop-daemon --stop --quiet --oknodo --retry 5 --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 --retry 5 --pidfile $PIDFILE
       rm -f $PIDFILE
       if [ $ENABLE_REPCACHED = yes ]; then
                start-stop-daemon --start --quiet --exec "$DAEMONBOOTSTRAP" -- /etc/${NAME}.conf $PIDFILE
                echo "$NAME."
       else
            echo "$NAME disabled in /etc/default/repcached."
       fi
       ;;
  status)
       status_of_proc -p $PIDFILE $DAEMON $NAME  && exit 0 || exit $?
       ;;
  *)
        N=/etc/init.d/$NAME
        echo "Usage: $N {start|stop|restart|force-reload|status}" >&2
        exit 1
        ;;
esac
exit 0
chmod +x etc/init.d/repcached
chmod +x usr/share/memcached/scripts/start-repcached
Название для красоты:
cat > description-pak
Memcached fail-over daemon
И соберем пакет:
checkinstall -nodoc --install=no --include=include-pak --pkgname=repcached
Вот, что получилось:
ls -l repcached*deb
Пакет полностью собран. Теперь его надо раскидать по обоим серверам, которые будут участвовать в кластере.

Шаги по установке, которые надо повторить на каждом из двух серверов.

Repcached конфликтует с memcached (те же порты), поэтому либо его не надо было ставить либо надо выключить теперь:
sed -i 's/ENABLE_MEMCACHED=yes/ENABLE_MEMCACHED=no/g' /etc/default/memcached
service memcached stop
Теперь ставим сам пакет repcached:
dpkg -i repcached_2.2-1_amd64.deb
После установки и перед запуском, заполните последнюю строку в конфиге /etc/repcached.conf - туда надо вписать IP второго сервера (не того, на котором стоит этот пакет). А на втором сервере поставить этот пакет и вписать, соответственно, IP первого сервера.

Можно запускать и проверять:
service repcached start
netstat -plunt | grep cache





Комментариев нет:

Отправить комментарий