5

有时打开与 Redis 的连接需要很长时间。看起来这取决于连接线程的数量,也许还取决于 PC 配置。我在两个具有 4 核 CPU 的工作站上运行 50 个线程的测试,打开连接需要 70-100 毫秒,而在 8 核工作站和 8 核登台服务器上需要 1000-1500 毫秒,有时甚至更多。奇怪的依赖,但它是可复制的。当 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;
}
4

1 回答 1

2

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

var connection = TryGetConnection();
while (connection == null)
{
    connection = TryGetConnection();
}

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

var task = connection.Open();
connection.Wait(task);

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

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

var connection = TryGetConnection();
// no loop here

和:

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;
    }
}

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

myserver:6389,syncTimeout=1000

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

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

于 2013-05-30T12:57:54.910 回答