RestTemplate: 有什么方法可以保护jvm免受巨大响应大小的影响?

问题描述 投票:0回答:1

当使用RestTemplate与外部服务对话时,我不止一次在我们的应用中看到OutOfMemory错误,因为服务的数据流有几千兆的数据(由于他们那边的一个不好的实现,在错误的情况下,他们在数组的每一个元素中都发回了很大的堆栈痕迹,通常包含几千个)。它的结局是大约6GB的数据,在我们的应用程序中被jackson序列化,并且完全爆炸了jvm的Xmx。

我看了一下,但似乎没有任何方法可以防止这种情况,即当流式响应超过给定大小时,中止请求。

有什么办法可以解决这个问题吗?我们使用的是apache的httpcomponents httpclient 4.5.5,但任何其他的底层实现都可以接受。

除了RestTemplate,也欢迎Spring的反应式WebClient的解决方案。

java spring resttemplate
1个回答
1
投票

这必须在底层的HTTP客户端库中执行(spring支持不同的库,比如JDK客户端,apache客户端,okHTTP...)。

在这里你说的是apache-httpcomponent,你检查过这个吗?HttpEntity.getContent() 实际上,它返回的是一个输入流,你可以自己读取,并确定何时已经超过了大小。

https:/hc.apache.orghttpcomponents-core-4.4.xhttpcoreapidocsorgapachehttpHttpEntity.html。


0
投票

记录一下,这是最终的解决方案。问题是要加载一个可能非常大的对象列表,使用分页(通过弹性搜索滚动api)。

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;
    }
© www.soinside.com 2019 - 2024. All rights reserved.