RestTemplate: Есть ли способ защитить JVM от огромного размера ответа? - PullRequest
0 голосов
/ 24 апреля 2020

При использовании RestTemplate для общения с внешней службой я неоднократно видел ошибки OutOfMemory в нашем приложении, потому что служба передает потоки данных (из-за плохой реализации на их стороне, в случае ошибок они были отправка больших стековых трасс в каждом элементе массива, который обычно содержит несколько тысяч). Это заканчивалось примерно 6 ГБ данных, сериализовано Джексоном в нашем приложении и полностью взорвало Xmx jvm.

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

Есть ли решение для этого? Мы используем httpcomponents apache httpclient 4.5.5, но любая другая базовая реализация будет приемлемой.

Помимо RestTemplates, приветствуется также решение для реактивного WebClient Spring.

Ответы [ 2 ]

1 голос
/ 24 апреля 2020

Это должно быть реализовано в базовой клиентской библиотеке HTTP (Spring поддерживает разные, такие как JDK-клиент, apache клиент, okHTTP ..)

Здесь вы говорите о apache -httpcomponent, не так ли? проверить это HttpEntity.getContent()? Он на самом деле возвращает InputStream, который вы можете прочитать самостоятельно и определить, когда размер был превышен ..

https://hc.apache.org/httpcomponents-core-4.4.x/httpcore/apidocs/org/apache/http/HttpEntity.html

0 голосов
/ 28 апреля 2020

Для записей, вот окончательное решение. Проблема c состояла в том, чтобы загрузить список объектов, которые могут быть очень большими, используя нумерацию страниц (через elasti c api search scroll).

ResponseExtractor<Car[]> responseExtractor = responseEntity -> {
    long pageContentLengthInBytes = responseEntity.getHeaders().getContentLength();
    long presumableFreeMemoryInBytes = this.getAvailableFreeMemoryAmount();

    if (presumableFreeMemoryInBytes - TWENTY_MEGABYTES < pageContentLengthInBytes) {
        log.error("Not enough memory to store the page ({} avaiable, content-length={}, trashing it", presumableFreeMemoryInBytes, pageContentLengthInBytes);
        responseEntity.close();
        return null;
    }
    return objectMapper.readValue(responseEntity.getBody(), Car[].class);
};

Car[] responseEntities = this.restTemplate.execute(uri, HttpMethod.GET, null, responseExtractor);
   /**
     * Returns the current amount of memory which may be allocated until an out-of-memory error occurs.
     * see https://stackoverflow.com/a/12807848/8836232
     */
    private long getAvailableFreeMemoryAmount() {
        long allocatedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
        return Runtime.getRuntime().maxMemory() - allocatedMemory;
    }
...