2881099 / csredis

.NET Core or .NET Framework 4.0+ client for Redis and Redis Sentinel (2.8) and Cluster. Includes both synchronous and asynchronous clients.
MIT License
2k stars 414 forks source link

System.IO.IOException:“Could not connect to sentinel or master” #88

Open zhousichuan opened 5 years ago

zhousichuan commented 5 years ago

版本号3.0.35 RedisSentinelManager.Connect调用报错 跟进代码后发现了几个问题: 1.csredis/src/CSRedisCore/RedisSentinelManager.cs:38 这里应该是Add(hostname, port); 因为host已经带有端口号了,再加上一个端口,会出现两个端口号 2.csredis/src/CSRedisCore/Internal/Commands/RedisRoleCommand.cs:48 这边应该改成长整型更合适,这边有溢出的情况 3.csredis/src/CSRedisCore/Internal/Utilities/Serializer.cs:156 这边获取到的构造函数为空,应为第二个参数应该是IFormatterConverter类型的, 但是传入的LocalVariableInfo类并没有实现IFormatterConverter接口

2881099 commented 5 years ago

你要用哨兵吗

2881099 commented 5 years ago
using (var sentinel = new RedisSentinelManager("host1:123", "host2:456"))
{
    sentinel.Add(Host); // add host using default port 
    sentinel.Add(Host, 36379); // add host using specific port
    sentinel.Connected += (s, e) => sentinel.Call(x => x.Auth(Password)); // this will be called each time a master connects
    sentinel.Connect("mymaster"); // open connection
    var test2 = sentinel.Call(x => x.Time()); // use the Call() lambda to access the current master connection
}
2881099 commented 5 years ago

可以考虑上 cluster,直接用 CSRedisClient 会方便很多。

sentinel 在切换故障的时候会丢失数据,并且不支持横向扩展。

zhousichuan commented 5 years ago
using (var sentinel = new RedisSentinelManager("host1:123", "host2:456"))
{
    sentinel.Add(Host); // add host using default port 
    sentinel.Add(Host, 36379); // add host using specific port
    sentinel.Connected += (s, e) => sentinel.Call(x => x.Auth(Password)); // this will be called each time a master connects
    sentinel.Connect("mymaster"); // open connection
    var test2 = sentinel.Call(x => x.Time()); // use the Call() lambda to access the current master connection
}

我们公司目前是用的哨兵模式,还没上cluster,我执行了你的这段代码后,报错了: System.OverflowException:“Value was either too large or too small for an Int32.”

2881099 commented 5 years ago

贴出使用的代码,以及错误信息+堆栈信息

2881099 commented 5 years ago

这两天在 CSRedisClient 现实了哨兵访问方式,除了定义,使用习惯与普通方式一致。

image

zhousichuan commented 5 years ago

tim 20190214132545

2881099 commented 5 years ago

mymaster 名称是否正确。 主从配置是否正确。

这个错误说明没有找到 mymaster 的主节点。

2881099 commented 5 years ago

可以手工测试:

redis-cli -h 192.168.2.34 -p 26379 SENTINEL get-master-addr-by-name mymaster

拿到返回值,redis-cli 连接后,执行 role 查看角色是否为 master

这是我本地测试结果:

image

zhousichuan commented 5 years ago

找到问题了,新的这个方式,我如果Redis设置免密登录的话,就出问题了。 你会强制发送AUTH指令,Redis会提示异常,被你拦截掉了 image

2881099 commented 5 years ago

这个 try 原本是解决master断开后的错。。坑了

我修复一下

2881099 commented 5 years ago
SentinelManager.Connected += (s, e) => {
    if (!string.IsNullOrEmpty(tmppoolPolicy._password)) {
        try {
            SentinelManager.Call(c => c.Auth(tmppoolPolicy._password));
        } catch (Exception authEx) {
            if (authEx.Message != "ERR Client sent AUTH, but no password is set")
                throw authEx;
        }
    }
};

CSRedisClient.cs 233行,改成这样试试

2881099 commented 5 years ago

测试好了: 1、有密码的主从+哨兵,连接字符串需要提供password; 2、无密码的主从+哨兵,连接字符串不应提供password,即使提供了也会忽略 "ERR Client sent AUTH, but no password is set" 错误;