1

I'm running a licensed version of ServiceStack and trying to get a sentinel cluster setup on Google Cloud Compute.

The cluster is basically GCE's click-to-deploy redis solution - 3 servers. Here is the code i'm using to initialize...

var hosts = Settings.Redis.Host.Split(';');
var sentinel = new ServiceStack.Redis.RedisSentinel(hosts, "master");
redis = sentinel.Setup();

container.Register<IRedisClientsManager>(redis);
container.Register<ICacheClient>(redis.GetCacheClient());

The client works fine - but once i shut down one of the redis instances everything craps the bed. The client complains about not being able to connect to the missing instance. Additionally, even when i bring the instance back up - it is in READ ONLY mode, so everything still fails. There doesn't seem to be a way to recover once you are in this state...

Am i doing something wrong? Is there some reason that RedisSentinal client doesn't figure out who the new master is? I feed it all 3 host IP addresses...

josh-sachs
  • 1,749
  • 2
  • 15
  • 19

1 Answers1

2

You should only be supplying the host of the Redis Sentinel Server to RedisSentinel as it gets the active list of other master/slave redis servers from the Sentinel host.

Some changes to RedisSentinel were recently added in the latest v4.0.37 that's now available on MyGet which includes extra logging and callbacks of Redis Sentinel events. The new v4.0.37 API looks like:

var sentinel = new RedisSentinel(sentinelHost, masterName);

Starting the RedisSentinel will connect to the Sentinel Host and return a pre-configured RedisClientManager (i.e. redis connection pool) with the active

var redisManager = sentinel.Start();

Which you can then register in the IOC with:

container.Register<IRedisClientsManager>(redisManager);

The RedisSentinel should then listen to master/slave changes from the Sentinel hosts and failover the redisManager accordingly. The existing connections in the pool are then disposed and replaced with a new pool for the newly configured hosts. Any active connections outside of the pool they'll throw connection exceptions if used again, the next time the RedisClient is retrieved from the pool it will be configured with the new hosts.

Callbacks and Logging

Here's an example of how you can use the new callbacks to introspect the RedisServer events:

var sentinel = new RedisSentinel(sentinelHost, masterName)
{
    OnFailover = manager => 
    {
        "Redis Managers were Failed Over to new hosts".Print();
    },
    OnWorkerError = ex =>
    {
        "Worker error: {0}".Print(ex);
    },
    OnSentinelMessageReceived = (channel, msg) =>
    {
        "Received '{0}' on channel '{1}' from Sentinel".Print(channel, msg);
    },                
};

Logging of these events can also be enabled by configuring Logging in ServiceStack:

LogManager.LogFactory = new ConsoleLogFactory(debugEnabled:false);

There's also an additional explicit FailoverToSentinelHosts() that can be used to force RedisSentinel to re-lookup and failover to the latest master/slave hosts, e.g:

var sentinelInfo = sentinel.FailoverToSentinelHosts();

The new hosts are available in the returned sentinelInfo:

"Failed over to read/write: {0}, read-only: {1}".Print(
    sentinelInfo.RedisMasters, sentinelInfo.RedisSlaves);
mythz
  • 141,670
  • 29
  • 246
  • 390
  • @user2069563 What exactly do you mean "does not seem to provide any resiliency"? Redis's Sentinel maintains the active Master/Slave hosts and if the master fails automatically selects a slave to promote to master. The `RedisSentinel` class listens for these events and fails over to use the slave/master configuration when this occurs. – mythz Jan 25 '15 at 17:47
  • There may be a fundamental misunderstanding on my part regarding Sentinel - but implementing what you've provided here against 4.0.37 does not seem to provide any resiliency with the redis cluster. I thought the whole point is that the client can connect to any machine in the cluster - and the first machine to respond will tell the client which is currently the elected master R/W node. Even with the setup mentioned in your reply, i still can't recover from a machine going down even by simply bringing it back up. I get "failed to connect to sentinel" error on setup(). – josh-sachs Jan 25 '15 at 17:49
  • sorry i dont post to SE much so my comment got submitted before i was done when i pressed enter. basically the issue remains that if the machine at the IP i provide to RedisSentinel() goes offline - the application fails to connect to the cluster. Bringing that machine back online does not seem to resolve the issue. I have to alter my web.config to specify the IP of the newly elected host. – josh-sachs Jan 25 '15 at 17:51
  • @user2069563 [Redis Cluster](http://redis.io/topics/cluster-spec) (which is still unreleased) is not to be confused with [Redis Sentienl](http://redis.io/topics/sentinel) which just monitors existing master/slave instances and automatically fails over the master when it detects it's down. If Sentinel Host itself is down then it wont be able to get the active redis masters/slaves, but when Sentinel returns it should recover, this is the behavior I see in [RedisSentinelTests](https://github.com/ServiceStack/ServiceStack.Redis/blob/master/tests/ServiceStack.Redis.Tests/RedisSentinelTests.cs#L122) – mythz Jan 25 '15 at 17:59
  • 1
    Thank you mythz - i think what you've provided is functional then, and what i'm looking to achieve in GCE is beyond the scope of Sentinel alone. For anyone googling, see this as a potential way to leverage Sentinel as a component to achieving High Availability. I believe the SS wireup mythz provided will work with this setup. https://robertianhawdon.me.uk/2014/02/11/sysops-installing-a-high-availability-redis-service-on-centos-6-x-in-windows-azure/ – josh-sachs Jan 25 '15 at 18:44
  • Sorry to beat what may be a dead horse, but a couple more things 1. RedisSentinel doesn't appear to accept the host format password@host:port the same way the RedisManagerPool does. Please advise on how insure the underlying redis clients are supplying proper AUTH strings. 2. If there are 3 sentinel hosts provided to RedisManager, it seems intuitive that if one sentinel is down, the client should just try another as it attempts MASTER resolution. The client should never interpret one host being inaccessible as an exception - only all. This is in effect clustering no? – josh-sachs Jan 26 '15 at 17:20
  • @user2069563 You can customize the connection string that's used for the [master and slaves using a HostFilter](https://github.com/ServiceStack/Issues/issues/216#issuecomment-69873701). For the behavior, if you're seeing a specific issue, [please open a support ticket](https://github.com/ServiceStack/Issues). – mythz Jan 28 '15 at 18:09