Inhaltsverzeichnis

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
/etc/sysctl.conf
vm.overcommit_memory=1
/etc/default/redis-server
# 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:

Konfigurationsdatei für den Master

/etc/redis/master-7000.conf
# 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

/etc/redis/slave-7001.conf
# 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:

/etc/services
redis           7000/tcp   # Redis server
redis           7001/tcp
redis-cluster   17000/tcp  # Redis cluster bus
redis-cluster   17001/tcp

Cluster initialisieren

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

  1. 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
  2. Slot neu aufteilen
    ./src/redis-trib.rb reshard ...

Knoten vom Cluster entfernen

Weitere Cluster-Befehle

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 <pos1> -s <serverip>/32 -p tcp -m tcp --dport 7000 -j ACCEPT
iptables -I INPUT <pos2> -s <serverip>/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"));