Риски использования Apache CloseableHttpClient в синглтоне - PullRequest
0 голосов
/ 22 мая 2018

Я использую Apache Http Client 4.5.3 и в настоящее время выполняю рефакторинг некоторого кода.

В настоящее время у меня есть одноэлементный Util, в котором есть несколько методов, в обязанности которых входит попадание в API с помощью запросов на получение, публикаций, исправлений и т. Д. Ранее мы использовали HttpClientBuilder для создания объекта CloseableHttpClient длякаждый вызов каждого метода.Грубо говоря, архитектура для Singleton выглядит примерно так:

import com.google.gson.Gson
import org.apache.http.client.methods.{HttpGet, HttpPost}
import org.apache.http.entity.StringEntity
import org.apache.http.impl.client.{CloseableHttpClient, HttpClientBuilder}
import org.apache.http.util.EntityUtils
import org.json4s.DefaultFormats
import org.json4s.jackson.JsonMethods.parse

object ApiCallerUtil {

  case class StoreableObj(name:String, id:Long)
  case class ResponseKey(key:Long)

  def getKeyCall(param:String): ResponseKey = {
    implicit val formats = DefaultFormats
    val get = new HttpGet("http://wwww.someUrl.com/api/?value=" + param)
    val client:CloseableHttpClient = HttpClientBuilder.create().build()
    val response = client.execute(get)
    try {
      val entity = response.getEntity
      val entityStr = EntityUtils.toString(entity)
      parse(entityStr).extract[ResponseKey]
    } finally {
      response.close()
      client.close()
    }
  }

  def postNewObjCall(param:String, i:Long): Boolean = {
    val post = new HttpPost(("http://wwww.someUrl.com/api/createNewObj"))
    val client = HttpClientBuilder.create().build()
    post.setHeader("Content-type", "application/json")
    val pollAsJson = new Gson().toJson(StoreableObj(param, i))
    post.setEntity(new StringEntity(pollAsJson))
    val response = client.execute(post)
    try {
      if (response.getStatusLine.getStatusCode < 300) true else false
    } finally {
      response.close()
      client.close()
    }
  }

  //... and so on

}

Замечания о том, как это используется - во всей нашей системе есть много классов, которые используют этот Singleton Util для выполнения вызовов API.Этот синглтон будет проходить через короткие периоды интенсивного использования, когда несколько классов будут нажимать на одни и те же вызовы с большой частотой (до @ 1000 раз в течение нескольких минут), а также периоды, когда он срабатывает несколько раз в течение длительного периода времени (один или два раза в час) или совсем не часами.Кроме того, все URL-адреса, которые он просматривает, будут начинаться с одного и того же URL-адреса (например, www.someUrl.com/api/)

Но мне интересно, имеет ли смысл реализовывать его, когда val client = HttpClientBuilder.create().build вызывается один раз как частный valдля доступной только для объекта переменной.Таким образом, он создается только один раз, при создании объекта.Вот где я делаю паузу, в документации Apache говорится две вещи:

1.2.1.[Закрыть] Реализации HttpClient должны быть поточно-ориентированными.Рекомендуется повторно использовать один и тот же экземпляр этого класса для выполнения нескольких запросов.

1.2.2.Когда экземпляр [Closeable] HttpClient больше не нужен и собирается выйти из области видимости, важно закрыть его диспетчер соединений, чтобы убедиться, что все соединения, поддерживаемые менеджером, закрыты и системные ресурсы, выделенные этими соединениями, освобождены.

Я прочитал большую часть документации, но не имею четкого ответа на следующие вопросы:

  1. Есть ли риск того, чтоЭкземпляр CloseableHttpClient как частная глобальная переменная?Я беспокоюсь, что что-то может быть закрыто, если оно устарело, и что через некоторое время мне придется его осилить, или, в случае интенсивного использования, это создаст слишком много узкого места.Согласно приведенному выше п. 1.2.2, переменная «никогда» не выйдет из области видимости, поскольку это одноэлементный объектНо поскольку я собираю только клиента и передаю ему объекты HttpRequest, а не подключаю его к API за пределами одного запроса, кажется, это не имеет значения.

  2. В связи с тем, как используется этот ApiCallerUtil Singleton, было бы разумно использовать их HttpClientConnectionManager или.PoolingHttpClientConnectionManager для поддержания постоянного соединения с www.someUrl.com/api/?Будет ли увеличение производительности того стоить?Пока что текущая реализация не имеет каких-либо существенных недостатков в производительности.

Спасибо за любые отзывы!

1 Ответ

0 голосов
/ 23 мая 2018
  1. Нет (основываясь на моем 15-летнем опыте работы с HttpClient).

  2. Это действительно зависит от различных факторов (накладные расходы на рукопожатие сеанса TLS,и так далее).Я полагаю, что очень хотелось бы убедиться, что ряд связанных запросов выполняется по постоянному соединению.В течение длительного периода бездействия может потребоваться исключить все незанятые соединения из пула соединений.Это дает дополнительное преимущество, заключающееся в уменьшении вероятности возникновения проблемы со устаревшим (полузакрытым) соединением.

...