Example #1
0
            public SentinelAdapter(RedisClient topOwner, ConnectionStringBuilder sentinelConnectionString, string[] sentinels, bool rw_splitting)
            {
                UseType           = UseType.Sentinel;
                TopOwner          = topOwner;
                _connectionString = sentinelConnectionString;
                _sentinels        = new LinkedList <ConnectionStringBuilder>(sentinels?.Select(a =>
                {
                    var csb  = ConnectionStringBuilder.Parse(a);
                    csb.Host = csb.Host.ToLower();
                    return(csb);
                }).GroupBy(a => a.Host, a => a).Select(a => a.First()) ?? new ConnectionStringBuilder[0]);
                _rw_splitting = rw_splitting;

                _is_single = !_rw_splitting && sentinelConnectionString.MaxPoolSize == 1;
                if (_sentinels.Any() == false)
                {
                    throw new ArgumentNullException(nameof(sentinels));
                }

                _ib = new IdleBus <RedisClientPool>(TimeSpan.FromMinutes(10));
                ResetSentinel();
            }
        public static ConnectionStringBuilder Parse(string connectionString)
        {
            var ret = new ConnectionStringBuilder();

            if (string.IsNullOrEmpty(connectionString))
            {
                return(ret);
            }

            //支持密码中带有逗号,将原有 split(',') 改成以下处理方式
            var vs = Regex.Split(connectionString, @"\,([\w \t\r\n]+)=", RegexOptions.Multiline);

            ret.Host = vs[0].Trim();

            for (var a = 1; a < vs.Length; a += 2)
            {
                var kv = new[] { Regex.Replace(vs[a].ToLower().Trim(), @"[ \t\r\n]", ""), vs[a + 1] };
                switch (kv[0])
                {
                case "ssl": if (kv.Length > 1 && kv[1].ToLower().Trim() == "true")
                    {
                        ret.Ssl = true;
                    }
                    break;

                case "protocol": if (kv.Length > 1 && kv[1].ToUpper().Trim() == "RESP3")
                    {
                        ret.Protocol = RedisProtocol.RESP3;
                    }
                    break;

                case "userid":
                case "user": if (kv.Length > 1)
                    {
                        ret.User = kv[1].Trim();
                    }
                    break;

                case "password": if (kv.Length > 1)
                    {
                        ret.Password = kv[1];
                    }
                    break;

                case "database":
                case "defaultdatabase": if (kv.Length > 1 && int.TryParse(kv[1].Trim(), out var database) && database > 0)
                    {
                        ret.Database = database;
                    }
                    break;

                case "prefix": if (kv.Length > 1)
                    {
                        ret.Prefix = kv[1].Trim();
                    }
                    break;

                case "name":
                case "clientname": if (kv.Length > 1)
                    {
                        ret.ClientName = kv[1].Trim();
                    }
                    break;

                case "encoding": if (kv.Length > 1)
                    {
                        ret.Encoding = Encoding.GetEncoding(kv[1].Trim());
                    }
                    break;

                case "idletimeout": if (kv.Length > 1 && long.TryParse(kv[1].Trim(), out var idleTimeout) && idleTimeout > 0)
                    {
                        ret.IdleTimeout = TimeSpan.FromMilliseconds(idleTimeout);
                    }
                    break;

                case "connecttimeout": if (kv.Length > 1 && long.TryParse(kv[1].Trim(), out var connectTimeout) && connectTimeout > 0)
                    {
                        ret.ConnectTimeout = TimeSpan.FromMilliseconds(connectTimeout);
                    }
                    break;

                case "receivetimeout": if (kv.Length > 1 && long.TryParse(kv[1].Trim(), out var receiveTimeout) && receiveTimeout > 0)
                    {
                        ret.ReceiveTimeout = TimeSpan.FromMilliseconds(receiveTimeout);
                    }
                    break;

                case "sendtimeout": if (kv.Length > 1 && long.TryParse(kv[1].Trim(), out var sendTimeout) && sendTimeout > 0)
                    {
                        ret.SendTimeout = TimeSpan.FromMilliseconds(sendTimeout);
                    }
                    break;

                case "poolsize":
                case "maxpoolsize": if (kv.Length > 1 && int.TryParse(kv[1].Trim(), out var maxPoolSize) && maxPoolSize > 0)
                    {
                        ret.MaxPoolSize = maxPoolSize;
                    }
                    break;

                case "minpoolsize": if (kv.Length > 1 && int.TryParse(kv[1].Trim(), out var minPoolSize) && minPoolSize > 0)
                    {
                        ret.MinPoolSize = minPoolSize;
                    }
                    break;
                }
            }
            return(ret);
        }
Example #3
0
            internal void ResetSentinel()
            {
                if (ResetSentinelFlag != 0)
                {
                    return;
                }
                if (Interlocked.Increment(ref ResetSentinelFlag) != 1)
                {
                    Interlocked.Decrement(ref ResetSentinelFlag);
                    return;
                }
                string masterhostEnd = _masterHost;
                var    allkeys       = _ib.GetKeys().ToList();

                for (int i = 0; i < _sentinels.Count; i++)
                {
                    if (i > 0)
                    {
                        var first = _sentinels.First;
                        _sentinels.RemoveFirst();
                        _sentinels.AddLast(first.Value);
                    }

                    try
                    {
                        using (var sentinelcli = new RedisSentinelClient(_sentinels.First.Value))
                        {
                            var masterhost             = sentinelcli.GetMasterAddrByName(_connectionString.Host);
                            var masterConnectionString = localTestHost(masterhost, RoleType.Master);
                            if (masterConnectionString == null)
                            {
                                continue;
                            }
                            masterhostEnd = masterhost;

                            if (_rw_splitting)
                            {
                                foreach (var slave in sentinelcli.Salves(_connectionString.Host))
                                {
                                    ConnectionStringBuilder slaveConnectionString = localTestHost($"{slave.ip}:{slave.port}", RoleType.Slave);
                                    if (slaveConnectionString == null)
                                    {
                                        continue;
                                    }
                                }
                            }

                            foreach (var sentinel in sentinelcli.Sentinels(_connectionString.Host))
                            {
                                var remoteSentinelHost = $"{sentinel.ip}:{sentinel.port}";
                                if (_sentinels.Contains(remoteSentinelHost))
                                {
                                    continue;
                                }
                                _sentinels.AddLast(remoteSentinelHost);
                            }
                        }
                        break;
                    }
                    catch { }
                }

                foreach (var spkey in allkeys)
                {
                    _ib.TryRemove(spkey, true);
                }
                Interlocked.Exchange(ref _masterHost, masterhostEnd);
                Interlocked.Decrement(ref ResetSentinelFlag);

                ConnectionStringBuilder localTestHost(string host, RoleType role)
                {
                    ConnectionStringBuilder connectionString = _connectionString.ToString();

                    connectionString.Host        = host;
                    connectionString.MinPoolSize = 1;
                    connectionString.MaxPoolSize = 1;
                    using (var cli = new RedisClient(connectionString))
                    {
                        if (cli.Role().role != role)
                        {
                            return(null);
                        }

                        if (role == RoleType.Master)
                        {
                            //test set/get
                        }
                    }
                    connectionString.MinPoolSize = connectionString.MinPoolSize;
                    connectionString.MaxPoolSize = connectionString.MaxPoolSize;

                    _ib.TryRegister(host, () => new RedisClientPool(connectionString, null, TopOwner));
                    allkeys.Remove(host);

                    return(connectionString);
                }
            }
            public override TValue AdapterCall <TValue>(CommandPacket cmd, Func <RedisResult, TValue> parse)
            {
                return(TopOwner.LogCall(cmd, () =>
                {
                    RedisResult rt = null;
                    RedisClientPool pool = null;
                    using (var rds = GetRedisSocket(cmd))
                    {
                        pool = (rds as DefaultRedisSocket.TempProxyRedisSocket)._pool;
                        try
                        {
                            if (cmd._clusterMovedAsking)
                            {
                                cmd._clusterMovedAsking = false;
                                rds.Write("ASKING");
                                rds.Read(false);
                            }
                            rds.Write(cmd);
                            rt = rds.Read(cmd._flagReadbytes);
                        }
                        catch (Exception ex)
                        {
                            if (pool?.SetUnavailable(ex) == true)
                            {
                            }
                            throw ex;
                        }
                    }
                    if (rt.IsError && pool != null)
                    {
                        var moved = ClusterMoved.ParseSimpleError(rt.SimpleError);
                        if (moved != null && cmd._clusterMovedTryCount < 3)
                        {
                            cmd._clusterMovedTryCount++;

                            if (moved.endpoint.StartsWith("127.0.0.1"))
                            {
                                moved.endpoint = $"{DefaultRedisSocket.SplitHost(pool._policy._connectionStringBuilder.Host).Key}:{moved.endpoint.Substring(10)}";
                            }
                            else if (moved.endpoint.StartsWith("localhost", StringComparison.CurrentCultureIgnoreCase))
                            {
                                moved.endpoint = $"{DefaultRedisSocket.SplitHost(pool._policy._connectionStringBuilder.Host).Key}:{moved.endpoint.Substring(10)}";
                            }

                            ConnectionStringBuilder connectionString = pool._policy._connectionStringBuilder.ToString();
                            connectionString.Host = moved.endpoint;
                            RegisterClusterNode(connectionString);

                            if (moved.ismoved)
                            {
                                _slotCache.AddOrUpdate(moved.slot, connectionString.Host, (k1, v1) => connectionString.Host);
                            }

                            if (moved.isask)
                            {
                                cmd._clusterMovedAsking = true;
                            }

                            TopOwner.OnNotice(new NoticeEventArgs(NoticeType.Info, null, $"{(cmd.WriteHost ?? "Not connected")} > {cmd}\r\n{rt.SimpleError} ", null));
                            return AdapterCall(cmd, parse);
                        }
                    }
                    rt.IsErrorThrow = TopOwner._isThrowRedisSimpleError;
                    return parse(rt);
                }));
            }
 //closure connectionString
 void RegisterClusterNode(ConnectionStringBuilder connectionString)
 {
     _ib.TryRegister(connectionString.Host, () => new RedisClientPool(connectionString, null, TopOwner));
 }
            void RefershClusterNodes()
            {
                foreach (var testConnection in _clusterConnectionStrings)
                {
                    RegisterClusterNode(testConnection);
                    //尝试求出其他节点,并缓存slot
                    try
                    {
                        var cnodes = AdapterCall <string>("CLUSTER".SubCommand("NODES"), rt => rt.ThrowOrValue <string>()).Split('\n');
                        foreach (var cnode in cnodes)
                        {
                            if (string.IsNullOrEmpty(cnode))
                            {
                                continue;
                            }
                            var dt = cnode.Trim().Split(' ');
                            if (dt.Length < 9)
                            {
                                continue;
                            }
                            if (!dt[2].StartsWith("master") && !dt[2].EndsWith("master"))
                            {
                                continue;
                            }
                            if (dt[7] != "connected")
                            {
                                continue;
                            }

                            var endpoint = dt[1];
                            var at40     = endpoint.IndexOf('@');
                            if (at40 != -1)
                            {
                                endpoint = endpoint.Remove(at40);
                            }

                            if (endpoint.StartsWith("127.0.0.1"))
                            {
                                endpoint = $"{DefaultRedisSocket.SplitHost(testConnection.Host).Key}:{endpoint.Substring(10)}";
                            }
                            else if (endpoint.StartsWith("localhost", StringComparison.CurrentCultureIgnoreCase))
                            {
                                endpoint = $"{DefaultRedisSocket.SplitHost(testConnection.Host).Key}:{endpoint.Substring(10)}";
                            }
                            ConnectionStringBuilder connectionString = testConnection.ToString();
                            connectionString.Host = endpoint;
                            RegisterClusterNode(connectionString);

                            for (var slotIndex = 8; slotIndex < dt.Length; slotIndex++)
                            {
                                var slots = dt[slotIndex].Split('-');
                                if (ushort.TryParse(slots[0], out var tryslotStart) &&
                                    ushort.TryParse(slots[1], out var tryslotEnd))
                                {
                                    for (var slot = tryslotStart; slot <= tryslotEnd; slot++)
                                    {
                                        _slotCache.AddOrUpdate(slot, connectionString.Host, (k1, v1) => connectionString.Host);
                                    }
                                }
                            }
                        }
                        break;
                    }
                    catch
                    {
                        _ib.TryRemove(testConnection.Host, true);
                    }
                }

                if (_ib.GetKeys().Length == 0)
                {
                    throw new RedisClientException($"All \"clusterConnectionStrings\" failed to connect");
                }
            }
Example #7
0
 /// <summary>
 /// Sentinel RedisClient
 /// </summary>
 public RedisClient(ConnectionStringBuilder sentinelConnectionString, string[] sentinels, bool rw_splitting)
 {
     Adapter = new SentinelAdapter(this, sentinelConnectionString, sentinels, rw_splitting);
 }
Example #8
0
 /// <summary>
 /// Pooling RedisClient
 /// </summary>
 public RedisClient(ConnectionStringBuilder connectionString, params ConnectionStringBuilder[] slaveConnectionStrings)
 {
     Adapter = new PoolingAdapter(this, connectionString, slaveConnectionStrings);
 }