【问题标题】:StackExchange.Redis - Is it possible to prioritize Endpoints?StackExchange.Redis - 是否可以优先考虑端点?
【发布时间】:2017-11-01 06:52:07
【问题描述】:

我的设置:

  • 4 个 Windows 服务器
  • 每个服务器上都有一个 Redis 节点和一个 Sentinel 进程
  • 在每台服务器上部署相同的 Web 应用程序
  • Web 应用程序通过 StackExchange.Redis 驱动程序连接到 redis 服务器

一切都很好,但我想知道读取操作是否有可能总是尝试使用首先在本地可用的 redis 节点。这将大大提高性能,因为所有读取操作的跳数都会减少。

据我所知,可以通过 Command Flags 属性将特定命令的从属优先于主控。 但是有没有办法确定特定端点的优先级

PS:

使用的 DLL:StackExchange.Redis.StrongName@1.2.0.0

Redis 服务器版本:3.2.100

编辑:

这是我的连接代码。我没有使用推荐的 Lazy getter 的原因是我想在其中一个节点发生故障时连接/重新连接,这与我的解决方案非常有效。

internal class RedisConnector
{
    private readonly ConfigurationOptions _currentConfiguration;
    internal ConnectionMultiplexer Connection;

    internal RedisCacheStore Store;

    internal RedisConnector(ConfigurationOptions configuration)
    {
        _currentConfiguration = configuration;
        Connect();
    }

    internal IDatabase Database
        => Connection.GetDatabase(RedisCacheConfiguration.Instance.Connection.DatabaseId);

    internal IServer Server => Connection.GetServer(Database.IdentifyEndpoint());

    private void Connect()
    {
        Connection = ConnectionMultiplexer.Connect(_currentConfiguration);
        if (Connection == null || !Connection.IsConnected)
            throw new CacheNotAvailableException();
        Connection.ConnectionFailed += OnConnectionFailed;
        Connection.ConnectionRestored += OnConnectionRestored;
        Store = new RedisCacheStore(Database);
    }

    private void Reconnect()
    {
        if (Connection != null && !Connection.IsConnected)
            Connection.Dispose();
        Connect();
    }

    private void OnConnectionFailed(object sender, ConnectionFailedEventArgs args)
    {
        lock (_currentConfiguration)
        {
            if (_currentConfiguration.EndPoints.Contains(args.EndPoint))
            {
                _currentConfiguration.EndPoints.Remove(args.EndPoint);
                Reconnect();
            }
        }
    }

    private void OnConnectionRestored(object sender, ConnectionFailedEventArgs args)
    {
        lock (_currentConfiguration)
        {
            if (!_currentConfiguration.EndPoints.Contains(args.EndPoint))
            {
                _currentConfiguration.EndPoints.Add(args.EndPoint);
                Reconnect();
            }
        }
    }
}

【问题讨论】:

  • 你好,优先级是什么意思?
  • 它是否优先考虑具有诸如尝试调用本地redis而不是调用另一个redis之类的规则的redis节点?
  • ConnectionMultiplexer 管理我的四个端点。据我所知,ConnectionMultiplexer 会查看可用的端点,并在我发出特定命令(例如 SET 或 GET)时选择一个。现在我希望 ConnectionMultiplexer 使用一个特定的端点而不是其他端点(如果它可用)。我知道我可以自己迭代端点,但我认为这就是 ConnectionMultiplexer 的用途。所以我想知道是否有办法保持该抽象完整,但也许可以通过配置 ConnectionMultiplexer 端点来做我想做的事。
  • 现在明白了,这是我的答案。

标签: c# redis stackexchange.redis


【解决方案1】:

在这种情况下。

假设你有这种情况,3VM 有 3 个应用程序和 3 个 redis 实例。
APP在VM1中运行的最佳选择是在VM1中使用Redis。 APP在VM2中运行的最佳选择是在VM2中使用Redis。 APP在VM3中运行的最佳选择是在VM3中使用Redis。

你可以像这样实现一些规则:

private static Lazy<ConfigurationOptions> configOptions
    = new Lazy<ConfigurationOptions>(() => 
    {
        var configOptions = new ConfigurationOptions();
        configOptions.EndPoints.Add("x.x.x.1:6379");          
        configOptions.EndPoints.Add("x.x.x.2:6379");
        configOptions.EndPoints.Add("x.x.x.3:6379");

        configOptions.ClientName = "LeakyRedisConnection";
        configOptions.ConnectTimeout = 100000;
        configOptions.SyncTimeout = 100000;
        return configOptions;
    });



private static string getIP()
{
    var host = Dns.GetHostEntry(Dns.GetHostName());
    foreach (var ip in host.AddressList)
    {
        if (ip.AddressFamily == AddressFamily.InterNetwork)
        {
            return ip.ToString();
        }
    }
    throw new Exception("ip not found!");
}


private static Lazy<ConfigurationOptions> getOptionsForIp(string myip)
        {
            var configOptions = new ConfigurationOptions();
            configOptions.EndPoints.Add(myip);
            configOptions.ClientName = "LeakyRedisConnectionDirectVM";
            configOptions.ConnectTimeout = 100000;
            configOptions.SyncTimeout = 100000;
            return configOptions;
        });


private static ConnectionMultiplexer conn;

private static ConnectionMultiplexer LeakyConn
{
    get
    {
        if (conn == null || !conn.IsConnected){               
            string myIP = getIP();

            conn = ConnectionMultiplexer.Connect(getOptionsForIp(myIP).Value);
            if(conn == null || !conn.IsConnected){
                conn = ConnectionMultiplexer.Connect(configOptions.Value);
            }

        }
        return conn;
    }
}

如何使用此代码:

 var db = LeakyConn.GetDatabase();
 db.StringSet(key, i);
 db.StringGet(key);

【讨论】:

  • @ //conn = 代码在这里你的私人规则 这段代码看起来如何?我的意思是我明白我总是可以删除除 localhost+master 之外的所有端点。然后我可能会监听 Co​​nnectionFailed 事件,在这种情况下我可以尝试下一个端点。这是您的提议还是有更好的选择?
  • 一个好的做法是在区域/ping/webaccess 方面尝试“更接近”的服务器。这个可以自己配置。如果你的 redis 和你的应用在同一台服务器上运行,最好先使用 localhost rest。
  • 当然可以,但我怎样才能做到这一点。正如我所说:只给多路复用器两个端点(localhost + master)可能会起作用,但我觉得这有点危险。如果驱动程序按照我指定的顺序自动对端点进行优先级排序,那肯定会更好。我查看了 StackExchange.Redis 源代码,但找不到理由相信端点的顺序对 ServerSelectionStrategy 很重要
  • 因此,使用您的最新编辑:它将仅连接到本地端点。如果连接不起作用,它将继续到其他端点。不幸的是,这并没有为本地端点不是主节点的情况提供解决方案(在这种情况下,每个 WRITE 操作都会失败)。我当然可以手动寻找主人。如果它足够可靠,我将对其进行测试。
  • 是的,当然,如果你想写,你需要把写的东西传递给主人。出于阅读目的,您可以将您的工作卸载给奴隶。 Salvesa 仅用于读取目的(即使 redis 允许写入从属服务器,这也不安全/您将/可能丢失数据)。
猜你喜欢
  • 2017-01-08
  • 1970-01-01
  • 2010-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-07-02
  • 1970-01-01
  • 2022-11-28
相关资源
最近更新 更多