打开redis连接太慢了

Mih*_*Kuz 5 connection timeout redis booksleeve

打开与Redis的连接有时需要很长时间.看起来它取决于连接线程的数量,也许还有PC配置.我在两个带有4核CPU的工作站上运行50个线程的测试,打开连接需要70-100ms,在8核工作站和8核登台服务器上需要1000-1500ms,有时甚至更多.奇怪的依赖,但它'可再现.当IIS应用程序池重新启动,并且所有线程都尝试重新连接时,会导致缓存停机等.为了获得合理的连接时间,我需要改变什么?

我使用BookSleeve客户端,这里是代码示例:

static void Main(string[] args)
{
    for (var i = 0; i < threadCount; i++)
        threads.Add(new Thread(RunThread));

    foreach (var thread in threads)
        thread.Start();

    foreach (var thread in threads)
        thread.Join();
}

static void RunThread()
{
    var connection = TryGetConnection();
    while (connection == null)
    {
        connection = TryGetConnection();
    }
}

static RedisConnection TryGetConnection()
{
    var connection = currentConnection;
    if ((connection != null) && (connection.State == RedisConnectionBase.ConnectionState.Open))
        return connection;

    lock (syncRoot)
    {
        if ((currentConnection != null) && (currentConnection.State == RedisConnectionBase.ConnectionState.Open))
            return currentConnection;

        if ((connectionTask != null) && connectionTask.IsCompleted)
            connectionTask = null;

        if (connectionTask == null)
        {
            if ((currentConnection != null) && (currentConnection.State == RedisConnectionBase.ConnectionState.Closed))
            {
                currentConnection.Dispose();
                currentConnection = null;
            }

            if (currentConnection == null)
            {
                currentConnection = new RedisConnection(
                    serverAddress,
                    serverPort,
                    ioTimeout: (int) operationTimeout.TotalMilliseconds,
                    syncTimeout: (int) operationTimeout.TotalMilliseconds);
            }

            if (currentConnection.State == RedisConnectionBase.ConnectionState.New)
                currentConnection.Open();
        }
    }
    return null;
}
Run Code Online (Sandbox Code Playgroud)

Mar*_*ell 2

我们看看吧; 我们这里有一个循环:

var connection = TryGetConnection();
while (connection == null)
{
    connection = TryGetConnection();
}
Run Code Online (Sandbox Code Playgroud)

我不清楚是否正确处理所有场景(“打开”等),但坦率地说,这是一个有争议的点TryGetConnection如果您要进行紧密循环直到获得连接,那么您不妨显着简化。您可以做的第一件事是等待任务(显然有超时),而不是使用热循环。概括:

var task = connection.Open();
connection.Wait(task);
Run Code Online (Sandbox Code Playgroud)

上面Wait使用连接的指定超时,并做了一些工作来简化异常。

但是,在这种特定情况下,您可能可以使用类似以下内容的内容:

var connection = TryGetConnection();
// no loop here
Run Code Online (Sandbox Code Playgroud)

和:

static RedisConnection TryGetConnection()
{
    var connection = currentConnection;
    if ((connection != null) && (connection.State == RedisConnectionBase.ConnectionState.Open))
        return connection;

    lock (syncRoot)
    {   // double-checked
        if ((connection != null) && (connection.State == RedisConnectionBase.ConnectionState.Open))
            return connection;

        connection = ConnectionUtils.Connect(config);
        return connection;
    }
}
Run Code Online (Sandbox Code Playgroud)

其中config是值的组合;基本上是这样的:

myserver:6389,syncTimeout=1000
Run Code Online (Sandbox Code Playgroud)

这个配置字符串也可以更复杂,包括多个redis服务器(主/从等)、服务名称(与哨兵一起使用)、客户端名称(与哨兵一起使用client list)等。

怀疑你的方法中的一些复杂性导致了目前一些额外的循环。看看上面的说法是否更可靠。