Unverified Commit b2db13fc authored by Shadi Massalha's avatar Shadi Massalha Committed by GitHub

Sentinel Support Derived from pr-692 (#1067)

This PR is derived from PR-692 and have been merged with the latest master commit.
Things that have been done:
1. review code for PR-692
2. fixed potential infinite loop in the code
3. Adapt code to success build with the latest master commit
4. Manual testing on 3 Sentinel nodes and 3 Redis nodes (connection and failover)

Usage:
```C#
                ConfigurationOptions sentinelConfig = new ConfigurationOptions();
                sentinelConfig.ServiceName = "mymaster";
                sentinelConfig.EndPoints.Add("192.168.99.102", 26379);
                sentinelConfig.EndPoints.Add("192.168.99.102", 26380);
                sentinelConfig.EndPoints.Add("192.168.99.102", 26381);
                sentinelConfig.TieBreaker = "";
                sentinelConfig.DefaultVersion = new Version(4, 0, 11);                 
                // its important to set the Sentinel commands supported
                sentinelConfig.CommandMap = CommandMap.Sentinel;

                // Get sentinel connection
                ConnectionMultiplexer sentinelConnection = ConnectionMultiplexer.Connect(sentinelConfig, Console.Out);
                // Create master service configuration
                ConfigurationOptions masterConfig = new ConfigurationOptions { ServiceName = "mymaster" };
                // Get master Redis connection
                var redisMasterConnection = sentinelConnection.GetSentinelMasterConnection(masterConfig);

                ...
               IDatabase db = redisMasterConnection.GetDatabase();                
               db.StringSet(key, value);
               ...
               string value1 = db.StringGet(key);

```
parent 748f1fa7
......@@ -38,6 +38,8 @@ install:
redis-server.exe --service-install --service-name "redis-26379" "..\Sentinel\sentinel-26379.conf" --sentinel
redis-server.exe --service-install --service-name "redis-26380" "..\Sentinel\sentinel-26380.conf" --sentinel
redis-server.exe --service-install --service-name "redis-26381" "..\Sentinel\sentinel-26381.conf" --sentinel
cd ..\..\..
- sh: >-
......
......@@ -752,6 +752,15 @@ public partial interface IServer : IRedis
/// <remarks>https://redis.io/topics/sentinel</remarks>
Task<EndPoint> SentinelGetMasterAddressByNameAsync(string serviceName, CommandFlags flags = CommandFlags.None);
/// <summary>
/// Returns the ip and port numbers of all known Sentinels
/// for the given service name.
/// </summary>
/// <param name="serviveName">the sentinel service name</param>
/// <param name="flags"></param>
/// <returns>a list of the sentinel ips and ports</returns>
Task<EndPoint[]> SentinelGetSentinelAddresses(string serviveName, CommandFlags flags = CommandFlags.None);
/// <summary>
/// Show the state and info of the specified master.
/// </summary>
......
......@@ -807,6 +807,12 @@ public Task<EndPoint> SentinelGetMasterAddressByNameAsync(string serviceName, Co
return ExecuteAsync(msg, ResultProcessor.SentinelMasterEndpoint);
}
public Task<EndPoint[]> SentinelGetSentinelAddresses(string serviceName, CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.SENTINELS, (RedisValue)serviceName);
return ExecuteAsync(msg, ResultProcessor.SentinelAddressesEndPoints);
}
public KeyValuePair<string, string>[] SentinelMaster(string serviceName, CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.MASTER, (RedisValue)serviceName);
......
......@@ -125,6 +125,9 @@ public static readonly StreamPendingMessagesProcessor
public static readonly ResultProcessor<EndPoint>
SentinelMasterEndpoint = new SentinelGetMasterAddressByNameProcessor();
public static readonly ResultProcessor<EndPoint[]>
SentinelAddressesEndPoints = new SentinelGetSentinelAddresses();
public static readonly ResultProcessor<KeyValuePair<string, string>[][]>
SentinelArrayOfArrays = new SentinelArrayOfArraysProcessor();
......@@ -714,6 +717,11 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
}
}
}
else if (message?.Command == RedisCommand.SENTINEL)
{
server.ServerType = ServerType.Sentinel;
server.Multiplexer.Trace("Auto-configured server-type: sentinel");
}
SetResult(message, true);
return true;
case ResultType.MultiBulk:
......@@ -765,6 +773,11 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
}
}
}
else if (message?.Command == RedisCommand.SENTINEL)
{
server.ServerType = ServerType.Sentinel;
server.Multiplexer.Trace("Auto-configured server-type: sentinel");
}
SetResult(message, true);
return true;
}
......@@ -1970,12 +1983,62 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
return true;
}
break;
}
return false;
}
}
private sealed class SentinelGetSentinelAddresses : ResultProcessor<EndPoint[]>
{
protected override bool SetResultCore(PhysicalConnection connection, Message message, in RawResult result)
{
List<EndPoint> endPoints = new List<EndPoint>();
switch (result.Type)
{
case ResultType.MultiBulk:
foreach (RawResult item in result.GetItems())
{
var arr = item.GetItemsAsValues();
string ip = null;
string portStr = null;
for (int i = 0; i < arr.Length && (ip == null || portStr == null); i += 2)
{
string name = arr[i];
string value = arr[i + 1];
switch (name)
{
case "ip":
ip = value;
break;
case "port":
portStr = value;
break;
}
}
if (ip != null && portStr != null && int.TryParse(portStr, out int port))
{
endPoints.Add(Format.ParseEndPoint(ip, port));
}
}
break;
case ResultType.SimpleString:
//We don't want to blow up if the master is not found
if (result.IsNull)
return true;
break;
}
if (endPoints.Count > 0)
{
SetResult(message, endPoints.ToArray());
return true;
}
return false;
}
}
......
......@@ -284,6 +284,12 @@ internal void AutoConfigure(PhysicalConnection connection)
msg.SetInternalCall();
WriteDirectOrQueueFireAndForgetSync(connection, msg, ResultProcessor.AutoConfigure);
}
if (commandMap.IsAvailable(RedisCommand.SENTINEL))
{
msg = Message.Create(-1, flags, RedisCommand.SENTINEL, RedisLiterals.MASTERS);
msg.SetInternalCall();
WriteDirectOrQueueFireAndForgetSync(connection, msg, ResultProcessor.AutoConfigure);
}
if (commandMap.IsAvailable(RedisCommand.INFO))
{
lastInfoReplicationCheckTicks = Environment.TickCount;
......
port 26381
sentinel monitor mymaster 127.0.0.1 7011 2
sentinel monitor mymaster 127.0.0.1 7010 1
sentinel down-after-milliseconds mymaster 1000
sentinel failover-timeout mymaster 1000
sentinel config-epoch mymaster 0
......
......@@ -33,7 +33,7 @@ redis-server cluster-7005.conf &>/dev/null &
popd > /dev/null
#Sentinel Servers
echo Starting Sentinel: 7010-7011,26379-26380
echo Starting Sentinel: 7010-7011,26379-26381
pushd Sentinel > /dev/null
echo "${INDENT}Targets: 7010-7011"
redis-server redis-7010.conf &>/dev/null &
......
......@@ -79,7 +79,9 @@ public class Config
public string RemoteServerAndPort => RemoteServer + ":" + RemotePort.ToString();
public string SentinelServer { get; set; } = "127.0.0.1";
public int SentinelPort { get; set; } = 26379;
public int SentinelPortA { get; set; } = 26379;
public int SentinelPortB { get; set; } = 26380;
public int SentinelPortC { get; set; } = 26381;
public string SentinelSeviceName { get; set; } = "mymaster";
public string ClusterServer { get; set; } = "127.0.0.1";
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment