2015-03-29 8 views
2

У меня есть клиент-клиент спрей, который работает на сервере X, который будет подключаться к серверу Y. Сервер Y является довольно медленным (будет 3+ сек для запроса)исключение «слишком много открытых файлов» при предоставлении более параллельных запросов

Это мой HTTP клиентского кода вызов:

def get() { 
    val result = for { 
     response <- IO(Http).ask(HttpRequest(GET,Uri(getUri(msg)),headers)).mapTo[HttpResponse] 
    } yield response 

    result onComplete { 
     case Success(res) => sendSuccess(res) 
     case Failure(error) => sendError(res) 
    } 
} 

Это конфигурация я имею в application.conf:

spray.can { 
    client { 
      request-timeout = 30s 
      response-chunk-aggregation-limit = 0 
      max-connections = 50 
      warn-on-illegal-headers = off 
     } 
     host-connector { 
      max-connections = 128 
      idle-timeout = 3s 
      } 
    } 

Теперь я попытался для злоупотребления сервером X с большим количеством одновременных запросов (используя ab с n = 1000 и c = 100).

До 900 запросов все прошло нормально. После этого сервер бросил много исключений, и после этого я не смог попасть на сервер. Эти исключения:

[info] [ERROR] [03/28/2015 17:33:13.276] [squbs-akka.actor.default-dispatcher-6] [akka://squbs/system/IO-TCP/selectors/$a/0] Accept error: could not accept new connection

[info] java.io.IOException: Too many open files [info] at sun.nio.ch.ServerSocketChannelImpl.accept0(Native Method) [info] at sun.nio.ch.ServerSocketChannelImpl.accept(ServerSocketChannelImpl.java:241) [info] at akka.io.TcpListener.acceptAllPending(TcpListener.scala:103)

и дальше ударяя тот же сервер, он бросил под исключение:

[info] [ERROR] [03/28/2015 17:53:16.735] [hcp-client-akka.actor.default-dispatcher-6] [akka://hcp-client/system/IO-TCP/selectors] null [info] akka.actor.ActorInitializationException: exception during creation

[info] at akka.actor.ActorInitializationException$.apply(Actor.scala:164)

[info] at akka.actor.ActorCell.create(ActorCell.scala:596)

[info] Caused by: java.lang.reflect.InvocationTargetException

[info] at sun.reflect.GeneratedConstructorAccessor59.newInstance(Unknown Source)

[info] Caused by: java.io.IOException: Too many open files [info] at sun.nio.ch.IOUtil.makePipe(Native Method)

Я был ранее с помощью апачского клиента HTTP (который был синхронным), который был в состоянии обрабатывать 10000+ запросов с параллелизмом 100.

Я не уверен, что я что-то упустил. Любая помощь будет оценена по достоинству.

ответ

3

Проблема заключается в том, что каждый раз, когда вы вызываете метод get(), он создает новый актер, который создает хотя бы одно соединение с удаленным сервером. Кроме того, вы никогда не закрываете этого актера, поэтому каждое такое соединение уходит, пока оно не истечет.

Вам нужен только один такой актер для управления всеми вашими HTTP-запросами, поэтому исправить это нужно IO(Http) из метода get() и называть его только один раз. Повторное использование, которое возвратило ActorRef для всех ваших запросов на этот сервер. Закройте его при завершении работы приложения.

Например:

val system: ActorSystem = ... 
val io = IO(Http)(system) 
io ! Http.Bind(... 

def get(): Unit = { 
    ... 
    io.ask ... 
    // or 
    io.tell ... 
} 
+0

Пожалуйста, поправьте меня, если я ошибаюсь, но это не Akka актеры, как предполагается, будет конкретизируется в миллионы? почему 1000 одновременных участников насыщают систему? – srj

+1

Да, вы правы, но это зависит от типа актера. Если ваш актер управляет ограниченными ресурсами, такими как IO, тогда эти ограничения ресурсов применяются соответственно. В этом случае ваша ОС ограничивает количество открытых FD/сокетов на сервере. Нет смысла открывать тысячи TCP-соединений на одном и том же сервере, достаточно было бы нескольких, чтобы отправить тысячи HTTP-запросов. –

+0

Это сработало. Но теперь у меня другое исключение. '[error] akka.ConfigurationException: Logger, указанный в config, не может быть загружен [akka.event.Logging $ DefaultLogger] из-за [akka.event.Logging $ LoggerInitializationException: Logger log1-Logging $ DefaultLogger не ответил LoggerInitialized, отправил вместо этого [TIMEOUT]] ' – Yoda