Esempio n. 1
0
        /// <summary>
        /// 查找指定节点所有符合给定模式 pattern 的 key
        /// </summary>
        /// <param name="src">主设备节点</param>
        /// <param name="pattern">匹配模式</param>
        /// <returns></returns>
        public IList <string> Keys(ClusterNode src, string pattern)
        {
            InternalClusterNode node   = this.CheckMasterNode(src);
            IList <string>      result = null;
            var bytes = this.DoExecute(node.Slot.Start, c => c.Keys(pattern));

            if (bytes != null)
            {
                if (result == null)
                {
                    result = new List <string>();
                }
                for (var index = 0; index < bytes.Length; index++)
                {
                    result.Add(bytes[index].FromUtf8Bytes());
                }
            }

            return(result);
        }
Esempio n. 2
0
        /// <summary>
        /// 从 cluster nodes 的每一行命令里读取出集群节点的相关信息
        /// </summary>
        /// <param name="line">集群命令</param>
        /// <returns></returns>
        public static InternalClusterNode Parse(string line)
        {
            if (string.IsNullOrEmpty(line))
            {
                throw new ArgumentException("line");
            }

            InternalClusterNode node = new InternalClusterNode();

            node._nodeDescription = line;
            string[] segs = line.Split(' ');

            node.NodeId       = segs[0];
            node.Host         = segs[1].Split(':')[0];
            node.Port         = int.Parse(segs[1].Split(':')[1]);
            node.MasterNodeId = segs[3] == "-" ? null : segs[3];
            node.PingSent     = long.Parse(segs[4]);
            node.PongRecv     = long.Parse(segs[5]);
            node.ConfigEpoch  = int.Parse(segs[6]);
            node.LinkState    = segs[7];

            string[] flags = segs[2].Split(',');
            node.IsMater = flags[0] == MYSELF ? flags[1] == MASTER : flags[0] == MASTER;
            node.IsSlave = !node.IsMater;
            int start = 0;

            if (flags[start] == MYSELF)
            {
                start = 1;
            }
            if (flags[start] == SLAVE || flags[start] == MASTER)
            {
                start += 1;
            }
            node.NodeFlag = string.Join(",", flags.Skip(start));

            if (segs.Length > 8)
            {
                string[] slots = segs[8].Split('-');
                node.Slot.Start = int.Parse(slots[0]);
                if (slots.Length > 1)
                {
                    node.Slot.End = int.Parse(slots[1]);
                }

                for (int index = 9; index < segs.Length; index++)
                {
                    if (node.RestSlots == null)
                    {
                        node.RestSlots = new List <HashSlot>();
                    }

                    slots = segs[index].Split('-');

                    int  s1 = 0;
                    int  s2 = 0;
                    bool b1 = int.TryParse(slots[0], out s1);
                    bool b2 = int.TryParse(slots[1], out s2);
                    if (!b1 || !b2)
                    {
                        continue;
                    }
                    else
                    {
                        node.RestSlots.Add(new HashSlot(s1, slots.Length > 1 ? new Nullable <int>(s2) : null));
                    }
                }
            }

            return(node);



            //序列化格式
            //命令的输出只是一个空格分隔的 CSV 字符串,其中每行代表集群中的一个节点。以下是输出示例:

            //07c37dfeb235213a872192d90877d0cd55635b91 127.0.0.1:30004 slave e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 0 1426238317239 4 connected
            //67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 127.0.0.1:30002 master - 0 1426238316232 2 connected 5461-10922
            //292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 127.0.0.1:30003 master - 0 1426238318243 3 connected 10923-16383
            //6ec23923021cf3ffec47632106199cb7f496ce01 127.0.0.1:30005 slave 67ed2db8d677e59ec4a4cefb06858cf2a1a89fa1 0 1426238316232 5 connected
            //824fe116063bc5fcf9f4ffd895bc17aee7731ac3 127.0.0.1:30006 slave 292f8b365bb7edb5e285caf0b7e6ddc7265d2f4f 0 1426238317741 6 connected
            //e7d1eecce10fd6bb5eb35b9f99a514335d9ba9ca 127.0.0.1:30001 myself,master - 0 0 1 connected 0-5460
            //每行由以下字段组成:

            //<id> <ip:port> <flags> <master> <ping-sent> <pong-recv> <config-epoch> <link-state> <slot> <slot> ... <slot>
            //每个字段的含义如下:
            //1. id:节点 ID,一个40个字符的随机字符串,当一个节点被创建时不会再发生变化(除非CLUSTER RESET HARD被使用)。
            //2. ip:port:客户端应该联系节点以运行查询的节点地址。
            //3. flags:逗号列表分隔的标志:myself,master,slave,fail?,fail,handshake,noaddr,noflags
            //4. master:如果节点是从属节点,并且主节点已知,则节点ID为主节点,否则为“ - ”字符。
            //5. ping-sent:以毫秒为单位的当前激活的ping发送的unix时间,如果没有挂起的ping,则为零。
            //6. pong-recv:毫秒 unix 时间收到最后一个乒乓球。
            //7. config-epoch:当前节点(或当前主节点,如果该节点是从节点)的配置时期(或版本)。每次发生故障切换时,都会创建一个新的,唯一的,单调递增的配置时期。如果多个节点声称服务于相同的哈希槽,则具有较高配置时期的节点将获胜。
            //8. link-state:用于节点到节点集群总线的链路状态。我们使用此链接与节点进行通信。可以是connected或disconnected。
            //9. slot:散列槽号或范围。从参数9开始,但总共可能有16384个条目(限制从未达到)。这是此节点提供的散列槽列表。如果条目仅仅是一个数字,则被解析为这样。如果它是一个范围,它是在形式start-end,并且意味着节点负责所有散列时隙从start到end包括起始和结束值。
            //标志的含义(字段编号3):
            //myself:您正在联系的节点。
            //master:节点是主人。
            //slave:节点是从属的。
            //fail?:节点处于PFAIL状态。对于正在联系的节点无法访问,但仍然可以在逻辑上访问(不处于FAIL状态)。
            //fail:节点处于FAIL状态。对于将PFAIL状态提升为FAIL的多个节点而言,这是无法访问的。
            //handshake:不受信任的节点,我们握手。
            //noaddr:此节点没有已知的地址。
            //noflags:根本没有标志。
        }
Esempio n. 3
0
        /// <summary>
        /// 调整指定 Redis 服务器的配置(configuration)而无须重启
        /// </summary>
        /// <param name="src">主设备节点</param>
        /// <param name="parameter">配置名称</param>
        /// <param name="value">配置内容</param>
        /// <returns></returns>
        public void ConfigSet(ClusterNode src, string parameter, byte[] value)
        {
            InternalClusterNode node = this.CheckMasterNode(src);

            this.DoExecute(node.Slot.Start, c => c.ConfigSet(parameter, value));
        }
Esempio n. 4
0
        /// <summary>
        /// 在后台异步(Asynchronously)保存当前节点的数据到磁盘。
        /// BGSAVE 命令执行之后立即返回 OK ,然后 Redis fork 出一个新子进程,原来的 Redis 进程(父进程)继续处理客户端请求,而子进程则负责将数据保存到磁盘,然后退出
        /// </summary>
        /// <param name="src">主设备节点</param>
        /// <returns></returns>
        public void BgSave(ClusterNode src)
        {
            InternalClusterNode node = this.CheckMasterNode(src);

            this.DoExecute(node.Slot.Start, c => c.BgSave());
        }
Esempio n. 5
0
        /// <summary>
        /// 清空指定节点数据(删除所有数据库的所有 key )
        /// </summary>
        /// <param name="src">主设备节点</param>
        /// <returns></returns>
        public void FlushAll(ClusterNode src)
        {
            InternalClusterNode node = this.CheckMasterNode(src);

            this.DoExecute(node.Slot.Start, c => c.FlushAll());
        }
Esempio n. 6
0
        /// <summary>
        /// SCAN 命令是一个基于游标的迭代器(cursor based iterator): SCAN 命令每次被调用之后, 都会向用户返回一个新的游标。
        /// 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。
        /// 当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代, 而当服务器向用户返回值为 0 的游标时, 表示迭代已结束
        /// </summary>
        /// <param name="src">主设备节点</param>
        /// <param name="cursor">游标</param>
        /// <param name="count">每次返回的键数量</param>
        /// <param name="match">匹配模式</param>
        /// <returns></returns>
        public ScanResult Scan(ClusterNode src, ulong cursor, int count = 10, string match = null)
        {
            InternalClusterNode node = this.CheckMasterNode(src);

            return(this.DoExecute(node.Slot.Start, c => c.Scan(cursor, count, match)));
        }
Esempio n. 7
0
        /// <summary>
        /// 从指定节点随机返回(不删除)一个 key
        /// </summary>
        /// <returns></returns>
        public string RandomKey(ClusterNode src)
        {
            InternalClusterNode node = this.CheckMasterNode(src);

            return(this.DoExecute(node.Slot.Start, c => c.RandomKey()));
        }
Esempio n. 8
0
        // 读取集群上的节点信息
        static IList <InternalClusterNode> ReadClusterNodes(IEnumerable <ClusterNode> source)
        {
            RedisClient  c      = null;
            StringReader reader = null;
            IList <InternalClusterNode> result = null;

            int index    = 0;
            int rowCount = source.Count();

            foreach (var node in source)
            {
                try
                {
                    // 从当前节点读取REDIS集群节点信息
                    index += 1;
                    c      = new RedisClient(node.Host, node.Port, node.Password);
                    RedisData data = c.RawCommand("CLUSTER".ToUtf8Bytes(), "NODES".ToUtf8Bytes());
                    string    info = Encoding.UTF8.GetString(data.Data);

                    // 将读回的字符文本转成强类型节点实体
                    reader = new StringReader(info);
                    string line = reader.ReadLine();
                    while (line != null)
                    {
                        if (result == null)
                        {
                            result = new List <InternalClusterNode>();
                        }
                        InternalClusterNode n = InternalClusterNode.Parse(line);
                        n.Password = node.Password;
                        result.Add(n);

                        line = reader.ReadLine();
                    }

                    // 只要任意一个节点拿到集群信息,直接退出
                    if (result != null && result.Count > 0)
                    {
                        break;
                    }
                }
                catch (Exception ex)
                {
                    // 出现异常,如果还没到最后一个节点,则继续使用下一下节点读取集群信息
                    // 否则抛出异常
                    if (index < rowCount)
                    {
                        Thread.Sleep(100);
                    }
                    else
                    {
                        throw new RedisClusterException(ex.Message, c != null ? c.GetHostString() : string.Empty, ex);
                    }
                }
                finally
                {
                    if (reader != null)
                    {
                        reader.Dispose();
                    }
                    if (c != null)
                    {
                        c.Dispose();
                    }
                }
            }


            if (result == null)
            {
                result = new List <InternalClusterNode>(0);
            }
            return(result);
        }