Java: IOUtils.toByteArray (ввод) занимает слишком много времени для некоторых запросов, вызывающих высокий TP99.9 - PullRequest
0 голосов
/ 06 мая 2020

Я использую следующий фрагмент кода для регистрации своих запросов. Большую часть времени мои запросы обслуживаются в пределах 100 мс. Но иногда чтение буфера занимает слишком много времени, что приводит к высокому TP99.9.

final HttpServletRequest rq = (HttpServletRequest) request;
final BufferedReqWrapper brq = new BufferedReqWrapper(rq);

А затем в BufferedReqWrapper

private final BufferingIPStream bis;


public BufferedReqWrapper(final HttpServletRequest req, final Integer maxBytesToBuffer) throws IOException
    {
        super(req);
        bis = new BufferingIPStream(super.getInputStream());
    }

В BufferingIPStream

public BufferingIPStream(final InputStream delegate) throws IOException
    {
        this.delegate = delegate;
        buffer = fillBuffer(delegate);
    }

, а метод fillbuffer -

private byte[] fillBuffer(final InputStream input) throws IOException
{
    return IOUtils.toByteArray(input);
}

Этот код отлично работает для большинства запросов, но иногда занимает много времени, что приводит к задержке более 1000 мс (TP99.9 становится высоким).

Ответы [ 2 ]

1 голос
/ 06 мая 2020

Существует ряд возможных причин для этого:

  1. Клиент (например, браузер) может находиться на медленной машине или в медленной сети. IOUtils.toByteArray ... или что-то еще ... может читать данные из удаленной системы только с той скоростью, с которой они поступают по сети.

  2. Некоторые запросы могут быть большими; т.е. намного больше, чем типичный. Запрос большего размера займет больше времени, чтобы преобразовать его в byte[].

  3. Вы могли видеть паузы G C. Если настройка G C хорошо адаптирована к вашей рабочей нагрузке, длинные паузы G C должны быть редкими. Однако возможно, что определенные шаблоны запросов приводят к тому, что G C приостанавливается на достаточно долгое время, чтобы получить длительные запросы.

Стоит отметить, что чтение большого запроса в a byte[] потребует несколько выделений памяти, причем самое большое из них в 2 раза превышает размер вашего запроса. Большие выделения памяти с большей вероятностью приведут к (более дорогим) коллекциям старого поколения. В худшем случае чрезмерно большие коллекции могут вызвать «полную» сборку мусора, которая (в зависимости от выбора и настройки G C) может привести к значительным паузам.

Наконец, вы не должны сбрасывать со счетов возможность что длительное время запроса на самом деле связано с чем-то еще, происходящим в вашем веб-приложении ... или с другим процессом ... или с другим виртуальным сервером на том же гипервизоре, что и ваш.

Я бы посоветовал:

  • размеры запросов на ведение журнала, чтобы увидеть, коррелируют ли они с медленными запросами
  • протоколирование IP-адресов клиентов и поиск корреляции
  • включение G C ведение журнала и поиск корреляции
  • если у вас есть графики загрузки системы (ЦП, дисковый ввод-вывод, сетевой ввод-вывод), ищите корреляцию

Используйте свои наблюдения, чтобы попытаться выяснить, в чем, вероятно, проблема быть. (Угадывать причину без каких-либо доказательств - плохая идея ...)

1 голос
/ 06 мая 2020

Ожидается, что InputStream чтение является блокирующим, что означает, что когда вы вызываете read, метод будет заблокирован (ждет, пока данные не станут доступными). IOUtils.toByteArray каким-то образом будет полагаться на метод потока read.

...