5

Redis への接続を開くのに非常に長い時間がかかることがあります。接続スレッドの数と、おそらくPCの構成に依存するようです。4 コア CPU を搭載した 2 台のワークステーションで 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 に答える