OkHttp: пул соединений и дескрипторы файлов

Мы используем Retrofit/OkHttp3 для всего сетевого трафика из нашего приложения для Android. Пока что все идет довольно гладко.

Тем не менее, у нас теперь время от времени заканчивались дескрипторы файлов в нашем приложении / процессе.

  • Android позволяет использовать до 1024 файловых дескрипторов на процесс
  • OkHttp создаст новый поток для каждого асинхронного вызова
  • Каждый поток, созданный таким образом, будет (по нашему наблюдению) отвечать за 3 новых дескриптора файла (2 канала и один сокет).

Мы смогли отладить это точно, где каждый отправленный асинхронный вызов, используя .enqueue() приведет к увеличению количества открытых файловых дескрипторов на 3.

Проблема в том, что ConnectionPool в OkHttp, кажется, поддерживает потоки соединения гораздо дольше, чем они на самом деле нужны. ( Этот пост говорит о пяти минутах, хотя я нигде не видел, чтобы это было указано.)

  • Это означает, что если вы быстро отправляете запрос, пул подключений будет увеличиваться в размере, равно как и число обработчиков файлов - пока вы не достигнете 1024, где происходит сбой приложения.

Я видел, что можно ограничить количество параллельных вызовов с Dispatcher.setMaxRequests() (хотя кажется неясным, работает ли это на самом деле, см. здесь) - но это все еще не решает проблему с накоплением открытых потоков и файловых дескрипторов.

Как мы можем помешать OkHttp создавать слишком много файловых дескрипторов?

1 ответ

Я отвечаю на свой вопрос здесь, чтобы задокументировать этот вопрос, который у нас был. Нам потребовалось некоторое время, чтобы понять это, и я думаю, что другие тоже могут столкнуться с этим и могут быть рады этому ответу.


Наша проблема заключалась в том, что мы создали один OkHttpClient для каждого запроса, поскольку мы использовали его API-интерфейс конструктора / перехватчика для настройки некоторых параметров для каждого запроса, таких как заголовки HTTP или тайм-ауты.

По умолчанию каждый OkHttpClient поставляется с собственным пулом соединений, что, конечно, увеличивает количество соединений / потоков / файловых дескрипторов и предотвращает правильное повторное использование в пуле.

Наше решение

Мы решили проблему, вручную создав глобальную ConnectionPool в одиночку, а затем передать это OkHttpClient.Builder объект, который строит фактический OkHttpClient,

  • Это по-прежнему позволяет для конфигурации по запросу с использованием OkHttpClient.Builder
  • Уверен все OkHttpClient экземпляры все еще используют общий пул соединений.

Мы смогли правильно определить глобальный пул соединений.

Другие вопросы по тегам