A l'heure où tout devient "connecté", "disponible en ligne", les échanges par l'internet se multiplient. Pour accompagner la démocratisation des liens rapides mais également pour améliorer l'expérience cliente, il est nécessaire que les fournisseurs de service en ligne optimisent leurs applications et la manière dont ils les livrent. Bien sûr, on peut toujours augmenter les ressources matériels, mais le coût n'est pas négligeable. Parfois, les développeurs peuvent travailler main dans la main avec les administrateurs. C'est le cas de l'utilisation des caches applicatifs (Memcached,Couchbase, Redis...).
Redis, dans la version stable actuelle (2.6) n'offre aucune fonctionnalité de mise en cluster comme Couchbase. Je ne parle pas non plus de l'absence totale d'organes de sécurité. Le but est clairement énoncé : la PER-FOR-MANCE.
Du coup, peu de solution pour la haute disponibilité si ce n'est mettre en place une architecture type maître/esclave avec une promotion automatique de l'esclave en tant que maître en cas de défaillance du premier. Nous allons voir cette mise en place puis tant qu'à faire, sa supervision.
On suppose pré-installés deux serveurs Debian Squeeze 64 bit. Notez que la version disponible de Redis dans les repositories officiels est une vieille 1.2.6 et que seule la branche 2.4 est disponible dans les backports. Traduction : nous allons être obligés de tout compiler à la main.
Pour cela, quelques pré-requis à installer :
aptitude install build-essential tcl8.5 pwgen
Le package tcl8.5 est là pour vous permettre d'effectuer quelques tests au besoin lors de la séance de compilation. Nous pouvons alors nous attaquer à Redis :
cd /usr/src wget http://redis.googlecode.com/files/redis-2.6.7.tar.gz tar -xzf redis-2.6.7.tar.gz rm redis-2.6.7.tar.gz cd redis-2.6.7 make make install useradd redis mkdir /opt/redis chown redis:redis /opt/redis chmod 770 /opt/redis
Je vous met à disposition un fichier un peu préparer, ici. Cependant, quelques modifications sont à prévoir.
wget http://cdn.aichelbaum.com/files/r/redis.conf -O /etc/redis.conf
Dans le cas que je présente ici, je bind l'application sur toutes les interfaces car les serveurs Redis sont sur un VLAN précis et isolé. Au besoin, on peut simplement l'isoler sur une IP en rajoutant dans la configuration un :
bind X.X.X.X
Il s'agit également de traitement en temps réel mais donc j'ai besoin d'avoir un maximum de garanties sur la pérennité des informations stockées, je sauvegarde toutes les 60 secondes s'il y a eu au moins une modification en base.
Redis a (trop) peu de sécurité. Cependant, autant mettre au moins un mot de passe pour la réplication. Pour se faire, on va en générer un propre avec pwgen :
pwgen -s -y 16
Il est à renseigner à la ligne commençant par masterauth. On réutilise le même mot dfe passe pour le champ requirepass.
Autre point important à modifier dans la configuration : la taille de la mémoire allouée à Redis. Dans mon exemple :
maxmemory 512mb
On peut aussi la passer à 8 Go par exemple :
maxmemory 8gb
Penser également à rajouter la ligne suivante dans votre /etc/security/limits.conf :
redis - nofile 20000
Redis nécessite un rajout à sysctl :
cat < EOF >> /etc/sysctl.conf vm.overcommit_memory=1 net.ipv4.conf.eth0.arp_ignore = 1 net.ipv4.conf.eth1.arp_ignore = 1 net.ipv4.conf.eth0.arp_announce = 2 net.ipv4.conf.eth1.arp_announce = 2 EOF sysctl -p
On a donc installé deux serveurs. On suppose leurs noms et IP :
- redis01 - 192.168.1.1
- redis02 - 192.168.1.2
On veut que redis02 soit esclave de redis01 :
sed -i "s/# slaveof <masterip> <masterport>/# slaveof <masterip> <masterport>\n#slaveof 192.168.1.1 6379/" /etc/redis.conf
Mais aussi l'inverse pour que redis01 devienne automatiquement esclave de redis01 en cas de failover :
sed -i "s/# slaveof <masterip> <masterport>/# slaveof <masterip> <masterport>\n#slaveof 192.168.1.2 6379/" /etc/redis.conf
On va entre s'appuyer sur redis-sentinel qui est une solution permettant de gérer facilement le failover entre les serveurs.
cp /usr/src/redis-2.6.7/src/redis-sentinel /usr/local/bin/redis-sentinel
Plus qu'à importer la configuration (et l'adapter avec vos IP et mots de passe) :
wget http://cdn.aichelbaum.com/files/s/sentinel.conf -O /etc/sentinel.conf
Petite précision : sentinel gère le failover, pas le fallback automatique. Il faut donc que l'ancien maître ( redis01) devienne un esclave du nouvellement promu ( redis02).
Pensez à installer un 3e sentinel sur le serveur de supervision avec les mêmes informations. Il vous permettra d'avoir un quorum de 2 sur les 3 sentinels possibles, très utile en cas de split-brain (chaque serveur est UP & Running mais ne voit plus son voisin).
On n'avait pas encore les fichiers d'init donc on va les mettre en place avec l'intelligence. J'ai préparé deux scripts d'init pour le coup
wget http://cdn.aichelbaum.com/files/r/redis-server.init -O /etc/init.d/redis-server wget http://cdn.aichelbaum.com/files/r/redis-sentinel.init -O /etc/init.d/redis-sentinel chmod +x /etc/init.d/redis-se* update-rc.d redis-sentinel defaults update-rc.d redis-server defaults insserv redis-sentinel insserv redis-server
On va gérer l'IP flottante permettant de n'accéder qu'au maître (pour fonctionner en actif/passif) avec un bête script. Pourquoi bête ? parce que le mode de fonctionnement ne requière pas l'installation d'une usine à gaz et qu'on a un simple cron qui peut faire le boulot. Pensez juste à éditer l'IP mise pour la VIP.
wget http://cdn.aichelbaum.com/files/r/redis-vip.sh -O /usr/local/bin/redis-vip.sh chmod +x /usr/local/bin/redis-vip.sh echo "* * * * * /usr/local/bin/redis-vip.sh &> /dev/null" > /etc/cron.d/redis-vip
On va s'appuyer sur un plugin existant : check_redis. Il permet aussi bien de superviser l'instance Redis en elle-même, que la réplication. Pour cela, il demande au serveur son rôle dans la réplication et dans le cas d'un esclave ( slave) son status.
Rien de particulier pour l'installation en soit. Le plugin est vraiment standard :
Usage: check_redis -H HOSTNAME -p PORT -c CRITICAL -w WARNING -t TIMEOUT (-P PASSWORD)
Par contre, il faut également superviser les sentinels. Au choix : un check_tcp sur le port 26379 ou vérifier en NRPE ou SNMP le status du service redis-sentinel.