====== Redis-Server ======
Mit einem Redis-Cluster steht ein über mehrere Gateways verteilte ausfallsicherer Datenspeicher zur Verfügung.
Ein Wert kann dann z.B. wie folgt geschrieben werden:
redis-cli -c -p 7000 set gate01-exit-provider earthvpn
Der Speicher ist den Gateways (bzw. zukünftig auch Servern) vorbehalten.
Ein Zugriff von den Knoten oder gar den Clients ist nicht vorgesehen.
Aktuell eingesetzte Version: **3.2.11**
:!: Die Version 4 werden wir erst einsetzen, wenn die Server auf Debian Buster (10) gewechselt sind.
Der Download der Quellen befindet sich unter: http://redis.io/download/,
die jeweils aktuelle Version unter http://download.redis.io/.
===== Installation =====
Benötigte Pakete:
aptitude install ruby libjemalloc1 php-redis python-redis
Wir wollen die aktuelle, clusterfähige Version haben, also übersetzen wir uns das Ding einfach selber:
cd /usr/local/src
wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make
make install
gem install redis
Überprüfen, ob alles geklappt hat
redis-server --version
Benutzer anlegen:
adduser --system --group --disabled-password --home /var/lib/redis --gecos 'Redis Server' redis
vm.overcommit_memory=1
# redis-server configure options
# ULIMIT: Call ulimit -n with this argument prior to invoking Redis itself.
# This may be required for high-concurrency environments. Redis itself cannot
# alter its limits as it is not being run as root. (default: do not call
# ulimit)
#
# ULIMIT=65536
# Options for Freifunk Community Pinneberg
# RUN_DAEMON=yes|no
RUN_DAEMON="yes"
Das für den Redis-Server vorhandene Init-Script bzw. deren Varianten die im Netz zu finden sind, sind irgendwie alle nicht überzeugend und können auch keine Cluster mit mehreren Instanzen je Server verwalten. Aus diesem Grund gibt es hier eine neu entwickelte Variante. Da sie sowohl mit Standalone-Servern als auch mit Clustern umgehen kann, nennen wir sie redis-cluster:
TODO Init-Script, zu finden in den [[ffpi-tools]]
Zusätzlich: redistats: https://github.com/jimeh/redistat
===== Cluster-Konfiguration =====
TODO
Achtung, die folgenden Einträge sind nur als eine Art Notizzettel gedacht und stellen keine freigegebene Anleitung dar.
Anlegen der benötigten Verzeichnisse
mkdir /etc/redis
chgrp redis /etc/redis
chmod g+w /etc/redis
mkdir /var/run/redis
chown redis. /var/run/redis
mkdir /var/lib/redis
mkdir /var/lib/redis/7000
mkdir /var/lib/redis/7001
chown -R redis. /var/lib/redis
mkdir /var/log/redis
chown redis. /var/log/redis
Wir setzen einen Cluster mit 4 Servern auf: ''gate01'', ''gate03'', ''gate04'' und ''gate05''. Auf jedem der Server läuft ein Master (Port 7000) und ein Slave (Port 7001).
Die folgenden Konfiguratonsbeispiele beziehen sich auf ''gate01'', Bei den anderen Servern ist einfach eine andere IP-Adresse zu verwenden.
Wichtig:
* Bei dem bind Befehl muß die localhost-Adresse an zweiter Stelle stehen. Anderenfalls funktioniert der Cluster nicht.
* ''logfile'' ist bewußt leer. Falls es einmal Probleme gibt, kann dort z.B. ''/var/log/redis/master.log'' eingetragen werden um Debuginformationen zu erhalten.
Konfigurationsdatei für den Master
# Redis cluster configuration file (Master)
#
port 7000
bind 10.137.10.1 127.0.0.1
daemonize yes
timeout 0
tcp-keepalive 0
tcp-backlog 96
loglevel notice
logfile ""
dir /var/lib/redis/7000
pidfile /var/run/redis/master-7000.pid
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename freifunk.rdb
databases 16
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
Konfigurationsdatei für den Slave
# Redis cluster configuration file (Slave)
#
port 7001
bind 10.137.10.1 127.0.0.1
daemonize yes
timeout 0
tcp-keepalive 0
tcp-backlog 96
loglevel notice
logfile ""
dir /var/lib/redis/7001
pidfile /var/run/redis/slave-7001.pid
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename freifunk.rdb
databases 16
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
Der Redis-Cluster läuft im Mesh-VPN. Damit wäre theoretisch Zugriff von jedem Gerät im Freifunk-Netz möglich. Da Redis selber keine Konfigurationsmöglichkeit für die Zugriffssteuerung auf IP-Adreßebene vorsieht, regeln wir das über IP-Tables:
iptables -A INPUT -p tcp --dport 7000 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7000 -s 10.137.10.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7000 -s 10.137.12.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7000 -s 10.137.13.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7000 -s 10.137.14.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7000 -j DROP
iptables -A INPUT -p tcp --dport 7001 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7001 -s 10.137.10.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7001 -s 10.137.12.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7001 -s 10.137.13.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7001 -s 10.137.14.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 7001 -j DROP
iptables -A INPUT -p tcp --dport 17000 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17000 -s 10.137.10.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17000 -s 10.137.12.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17000 -s 10.137.13.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17000 -s 10.137.14.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17000 -j DROP
iptables -A INPUT -p tcp --dport 17001 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17001 -s 10.137.10.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17001 -s 10.137.12.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17001 -s 10.137.13.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17001 -s 10.137.14.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 17001 -j DROP
iptables-save > /etc/iptables/rules.v4
Damit die Anzeige von iptables besser lesbar ist, kann die Datei ''/etc/services''
angepaßt werden:
redis 7000/tcp # Redis server
redis 7001/tcp
redis-cluster 17000/tcp # Redis cluster bus
redis-cluster 17001/tcp
==== Cluster initialisieren ====
* Auf allen beteiligten Servern:
/etc/init.d/redis-cluster start
* Erstellung anstoßen
cd /usr/src/redis-stable
./src/redis-trib.rb create --replicas 1 \
10.137.10.1:7000 10.137.10.1:7001 \
10.137.12.1:7000 10.137.12.1:7001 \
10.137.13.1:7000 10.137.13.1:7001 \
10.137.14.1:7000 10.137.14.1:7001
* Tests
redis-cli -p 7000 ping
redis-cli -p 7000
> set mykey somevalue
> get mykey
./src/redis-trib.rb info 10.137.10.1:7000
==== Knoten zum Cluster hinzufügen ====
Achtung: Das ist nur ein Merker für das grobe Vorgehen und ist
ggf. fehlerhaft.
Beim Slave ist die erste Adresse/Port die lokale Instanz und die
Zweite der zu verwendende Master
- Knoten aufsetzen
./src/redis-trib.rb add-node 10.137.12.1:7000
./src/redis-trib.rb add-node --slave 10.137.12.1:7001 10.137.10.1:7000
- Slot neu aufteilen
./src/redis-trib.rb reshard ...
==== Knoten vom Cluster entfernen ====
* Prozesse sollten nicht laufen: ''/etc/init.d/redis-cluster stop''
* Verzeichnisse leeren
rm /var/lib/redis/7000/*
rm /var/lib/redis/7001/*
* Auf allen übrigen Serverinstanzen die verwaisten Knoten-IDs entfernen
cluster forget 11de37b1018dbd8a83fa6000af6381630468e01e
==== Weitere Cluster-Befehle ====
* ''cluster nodes''
* ''cluster info''
* ''cluster failover'' -- Master/Slave tauschen, Befehl auf einem Slave eingeben
* ''info server'' -- allg Info zum aktuellen Server
* ''info replication''
* ''info cluster''
===== Update =====
cd /usr/local/src
rm redis-stable.tar.gz
rm -R redis-stable
wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make
make install
gem install redis
/etc/init.d/redis-cluster restart
===== Ruby Gems =====
Wenn man ''gem install redis'' mehrfach durchgeführt hat, sind nach einiger Zeit unterschiedliche Versionen installiert. Man kann sich das anzeigen lassen:
gem list redis
Eine alte Version kann gezielt entfernt werden
gem uninstall redis --version 3.2.2
Ebenso kann man sich eine spezielle Version installieren:
gem install redis --version 3.3.5
Eine Übersicht über die verfügbaren Versionen kann man erhalten mit:
gem list ^redis$ --remote --all
====== Cluster Client ======
Wenn die Client-Software //nicht// auf einem der Clusterknoten läuft, ist diesem
Server die Zugriffsberechtigung mittels Firewallregeln auf allen(!) Clusterknoten
zu erteilen.
Beispiel für manuelles, nachträgliches EInfügen:
iptables -I INPUT -s /32 -p tcp -m tcp --dport 7000 -j ACCEPT
iptables -I INPUT -s /32 -p tcp -m tcp --dport 7001 -j ACCEPT
===== Python Cluster Client =====
Basisvoraussetzung:
apt-get install python-hiredis
Um mit dem Cluster zu sprechen, kann man beispielsweise redis-py-cluster verwenden: https://pypi.python.org/pypi/redis-py-cluster/1.3.3
bzw. unter https://github.com/Grokzen/redis-py-cluster
Voraussetzung dafür ist redis-py, unter Debian heißt das Paket ''python-redis''.
Wenn die Geo-Funktionen genutzt werden sollen, muß die neueste Version von Github
verwendet werden. Aus diesem Grund ist in den folgenen Anweisungen auch kein
Checkout für einen Tag angegeben, es wird der Master verwendet (auf eigene Gefahr).
cd /usr/local/src
git clone https://github.com/andymccurdy/redis-py.git
cd redis-py
cp -a redis /usr/local/lib/python2.7/dist-packages/
bzw. für Python 3
cp -a redis /usr/local/lib/python3.4/dist-packages/
cd /usr/local/src
git clone https://github.com/Grokzen/redis-py-cluster.git
cd redis-py-cluster
git checkout 1.3.3
cp -a rediscluster/ /usr/local/lib/python2.7/dist-packages/
bzw. für Python 3
cp -a rediscluster/ /usr/local/lib/python3.4/dist-packages/
Auf dem Server A:
from rediscluster import StrictRedisCluster
startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)
rc.set("freifunk", "pinneberg")
Auf dem Server B:
from rediscluster import StrictRedisCluster
startup_nodes = [{"host": "127.0.0.1", "port": "7000"}]
rc = StrictRedisCluster(startup_nodes=startup_nodes, decode_responses=True)
print(rc.get("freifunk"))
===== PHP Cluster Client =====
Es gibt verschiedene Clients, jedoch funktionieren nicht alle mit dem
Cluster. Unter Debian Jessie funktioniert ''libphp-predis''.
Um Zugriff auf die Geo-Funktionen zu erhalten, sollte eine aktuelle
Version, wie z.B. 1.1.1 installiert werden. Dieses kann z.B. über PEAR
(siehe http://pear.nrk.io/) erfolgen.
Beispiel
require 'Predis/Autoloader.php';
Predis\Autoloader::register();
$parameters = ['tcp://127.0.0.1:7000'];
$options = ['cluster' => 'redis', 'profile' => '3.2'];
$client = new Predis\Client($parameters, $options);
echo "Statistiken\n";
echo "Knotenanzahl=". $client->get("nodes:counter:total") . "\n";
echo "davon online=".$client->get("nodes:counter:online"). "\n";
echo "davon Gates=".$client->get("nodes:counter:gates"). "\n";
echo "Geo-Funktionen\n";
print_r($client->geopos("nodes:geo", "6466b3c3ac82"));