【问题标题】:MOVED exception with Redis Cluster - StackExchange.RedisRedis集群的MOVED异常 - StackExchange.Redis
【发布时间】:2024-01-08 17:10:01
【问题描述】:

使用@Marcgravell article 中提到的具有非环回IP 地址的redis 官方教程在Ubuntu 服务器14.0 LTS(AZURE VM)中配置了Redis 集群服务器,但是在某些键出现MOVED 异常时使用 Stackexchange.Redis 客户端。嗨@Marcgravell,你能对此有所了解吗?谢谢。

【问题讨论】:

  • MOVED 如果在集群模式下应该由客户端处理。也许您正在使用旨在连接单个主节点的方法连接到实例?
  • 嗨@antirez,感谢您的回复和出色的产品。我的客户是 Stackexchange.Redis。是的,你是对的,当连接没有'-c' 参数的 redis-cli 时,我得到了移动异常。不知道怎么提那个参数 StackExchange.redis 客户端连接字符串。
  • 听上去好像是什么破事了。我将不得不重新调查
  • 嗨@Marc Gravell,你有时间解决这个问题吗?提前致谢。

标签: azure redis cluster-computing stackexchange.redis


【解决方案1】:

终于让我的程序运行起来了。感谢@hrishi18pathak。 我已经从 https://github.com/hrishi18pathak/StackExchange.Redis/tree/SEClusteringBugFix 分支下载了代码,并在 2015 年 7 月 17 日进行了更改。主要变化在 ConnectionMultiplexer 和 ConfigurartionOptions 类中。


ConnectionMultiplexer.cs(修改UpdateClusterRange()方法,增加IsNodeCompatibleWithConfiguration()方法):

internal void UpdateClusterRange(ClusterConfiguration configuration)
    {
        if (configuration == null) return;
        foreach (var node in configuration.Nodes)
        {
            // do not update cluster range if the node configuration is incompatible with the multiplexer 

            // endpoints configuration. If a user has specified endpoints in the multiplexer configuration using

            // Dns endpoints, Stackexchange.redis returns the ConnectionMultiplexer object successfully 
            // after connecting to all the nodes in the connection string (using their host names). 
            // Also, before returning the multiplexer object it updates the mapping of nodes to their clusterslots 

            // and this mapping is of the format “DNS hostname:port” : “clusterSlotNumber”.

            // However at the same time, the client also issues “CLUSTER NODES” command to each of the nodes in the above list 

            // (to determine master and slave configuration) and re-updates the cluster mapping with the output of the clusternodes command 

            // which now is going to contain IP addresses (redis-server itself does not understand host names). 

            // So the cluster mapping is now updated to the format: “IP Address” : “clusterSlotNumber”

            // If the StackExchange.Redis has not been able to connect to all the nodes using their IP addresses by the time the first command (GET,SET) 
            // is issued to the cluster, it results in failure to connect to that particular node resulting in the “MOVED ERROR” 

            // (since it tries to hit a random node in the list subsequently)

            if (node.IsSlave || node.Slots.Count == 0 || !IsNodeCompatibleWithConfiguration(node)) continue;
            foreach (var slot in node.Slots)
            {
                var server = GetServerEndPoint(node.EndPoint);
                if (server != null) serverSelectionStrategy.UpdateClusterRange(slot.From, slot.To, server);
            }
        }
    }

/// <summary>
    /// Checks if the specified node has the same format as that of
    /// the endpoints specified in the multiplexer configuration i.e.
    /// if all nodes are dns endpoints then the specified node has to be a dns endpoint
    /// to be compatible.
    /// </summary>
    /// <param name="node"></param>
    /// <returns>True if node is compatible with multiplexer configuration</returns>
    private bool IsNodeCompatibleWithConfiguration(ClusterNode node)
    {
        return (this.configuration.HasAllDnsEndPoints() && (node.EndPoint is DnsEndPoint)) ||
            (!this.configuration.HasDnsEndPoints() && !(node.EndPoint is DnsEndPoint));
    }

ConfigurationOptions.cs(添加方法 HasAllDnsEndPoints())

internal bool HasAllDnsEndPoints()
    {
        return !endpoints.Any(ep => !(ep is DnsEndPoint));
    }

我仍然需要验证此修复是否有任何影响。

【讨论】:

  • 如果您验证并发布会很好。
  • 因为这不是解决此问题的有效方法。不应该这样处理。