2013-05-27 6 views
5

Для открытия соединения с Redis иногда требуется очень много времени. Похоже, это зависит от количества подключаемых потоков и, может быть, от конфигурации ПК. Я запускаю тест на 50 потоков на двух рабочих станциях с 4-ядерными процессорами, и для открытия соединения требуется 70-100 мс, а на 8-ядерной рабочей станции и 8-ядерном промежуточном сервере потребовалось 1000-1500 мс, а иногда и намного больше. Странная зависимость, но она «воспроизводится». Когда пул приложений IIS перезапускается, и все потоки пытаются восстановить соединение, это приводит к тому, что время простоя кэша. Что я должен изменить, чтобы получить разумное время соединения?Открытие соединения redis слишком медленное

Я использую 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; 
} 
+0

:) Я отредактировал оригинальное сообщение – MihaKuz

+0

Какую именно версию книги вы используете? Это важно, потому что уровень ввода-вывода значительно изменился между версиями. –

+0

1.3.37, последняя версия от NuGet – MihaKuz

ответ

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 (ведущий/ведомый и т.д.), а-имя службы (для использования с дозорных), а-имя клиента (для использования с client list) и т. Д.

I подозреваемый некоторые сложности в вашем методе приводят к некоторому дополнительному циклу на данный момент. Посмотрите, насколько это более надежно.

Смежные вопросы