From 886aa622b0e402d3264bac6c77352312e65b1241 Mon Sep 17 00:00:00 2001 From: Chris Dent Date: Mon, 12 Jan 2015 13:32:35 +0000 Subject: [PATCH] Update sentinel support to allow multiple sentinel hosts Multiple sentinel hosts are now allowed by listing the additional hosts as multiple 'sentinel_fallback' parameters. These are combined with the first sentinel host to create a list that is provided to Sentinel class constructor. This provides safety in the case when the first (or any other) sentinel host goes down. Tests are run twice: once with fallbacks, once without. Change-Id: Ie0a134f02617e8552a87c8bcd49996daaba07f4e --- doc/source/drivers.rst | 2 +- setup-sentinel-env.sh | 37 +++++++++++++++++++++++++++---------- tooz/drivers/redis.py | 23 ++++++++++++++++++++++- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/doc/source/drivers.rst b/doc/source/drivers.rst index b12fa255..75a2524e 100644 --- a/doc/source/drivers.rst +++ b/doc/source/drivers.rst @@ -15,7 +15,7 @@ API, some of them have different properties: on timeout (heartbeats, locks, etc) so are less resilient than other backends. -* `redis`_ is a basic implementation and provides some resiliency +* `redis`_ is a basic implementation and provides reasonable resiliency when used with redis-sentinel. A lot of the features provided in tooz are based on timeout (heartbeats, locks, etc) so are less resilient than other backends. diff --git a/setup-sentinel-env.sh b/setup-sentinel-env.sh index 138e0e23..6c935a30 100755 --- a/setup-sentinel-env.sh +++ b/setup-sentinel-env.sh @@ -1,7 +1,8 @@ #!/bin/bash set -x -e -CONFFILE=$(mktemp -t tooz-sentinel-XXXXXX) +SENTINEL_PORTS="26381 26382 26383" +CONFFILES=() function clean_exit(){ local error_code="$?" @@ -10,29 +11,45 @@ function clean_exit(){ kill $(jobs -p) fi wait $spawned - rm $CONFFILE || true - rm /tmp/sentinel.26381.log || true + rm /tmp/sentinel.2638[123].log || true + rm ${CONFFILES[@]} || true return $error_code } -cat > $CONFFILE < $conffile <:?sentinel= + Additional sentinel hosts are listed with mutiple ``sentinel_fallback`` + parameters as follows: + + redis://:?sentinel=& + sentinel_fallback=:& + sentinel_fallback=:& + sentinel_fallback=: + Further resources/links: - http://redis.io/ @@ -202,6 +210,10 @@ class RedisDriver(coordination.CoordinationDriver): 'ssl_certfile', 'ssl_keyfile', 'sentinel', + 'sentinel_fallback', + ]) + _CLIENT_LIST_ARGS = frozenset([ + 'sentinel_fallback', ]) _CLIENT_BOOL_ARGS = frozenset([ 'retry_on_timeout', @@ -317,6 +329,8 @@ class RedisDriver(coordination.CoordinationDriver): # redis://localhost:6379?timeout=5&timeout=2 if a in cls._CLIENT_BOOL_ARGS: v = strutils.bool_from_string(options[a][-1]) + elif a in cls._CLIENT_LIST_ARGS: + v = options[a] elif a in cls._CLIENT_INT_ARGS: v = int(options[a][-1]) else: @@ -328,14 +342,21 @@ class RedisDriver(coordination.CoordinationDriver): # Ask the sentinel for the current master if there is a # sentinel arg. if 'sentinel' in kwargs: + sentinel_hosts = [ + tuple(fallback.split(':')) + for fallback in kwargs.get('sentinel_fallback', []) + ] + sentinel_hosts.insert(0, (kwargs['host'], kwargs['port'])) sentinel_server = sentinel.Sentinel( - [(kwargs['host'], kwargs['port'])], + sentinel_hosts, socket_timeout=kwargs['socket_timeout']) master_host, master_port = sentinel_server.discover_master( kwargs['sentinel']) kwargs['host'] = master_host kwargs['port'] = master_port del kwargs['sentinel'] + if 'sentinel_fallback' in kwargs: + del kwargs['sentinel_fallback'] return redis.StrictRedis(**kwargs) def _start(self):