RestTemplate:有没有办法保护 jvm 免受巨大响应大小的影响?
RestTemplate: Is there a way to protect jvm agains huge response size?
当使用 RestTemplate 与外部服务对话时,我不止一次在我们的应用程序中看到 OutOfMemory 错误,因为该服务流式传输大量数据(由于他们这边的实施不当,如果出现错误,他们他们在数组的每个元素中发送回大堆栈跟踪,通常包含几千个)。它以大约 6gb 的数据结束,由 jackson 在我们的应用程序中序列化并完全爆炸了 jvm 的 Xmx。
我环顾四周,但似乎没有任何方法可以防止这种情况发生,即当流式响应超过给定大小时中止请求。
有解决办法吗?我们正在使用 apache 的 httpcomponents httpclient 4.5.5,但任何其他底层实现都是可以接受的。
除了 RestTemplates,Spring 的响应式 WebClient 的解决方案也将受到欢迎。
这必须在底层 HTTP 客户端库中强制执行(spring 支持不同的库,例如 JDK 客户端、apache 客户端、okHTTP..)
你在这里谈论 apache-httpcomponent ,你检查过这个 HttpEntity.getContent()
吗?
它实际上 returns 一个 InputStream ,您可以自己阅读并确定何时超过大小..
https://hc.apache.org/httpcomponents-core-4.4.x/httpcore/apidocs/org/apache/http/HttpEntity.html
作为记录,这里是最终解决方案。问题在于使用分页(通过弹性搜索滚动 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
*/
private long getAvailableFreeMemoryAmount() {
long allocatedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
return Runtime.getRuntime().maxMemory() - allocatedMemory;
}
当使用 RestTemplate 与外部服务对话时,我不止一次在我们的应用程序中看到 OutOfMemory 错误,因为该服务流式传输大量数据(由于他们这边的实施不当,如果出现错误,他们他们在数组的每个元素中发送回大堆栈跟踪,通常包含几千个)。它以大约 6gb 的数据结束,由 jackson 在我们的应用程序中序列化并完全爆炸了 jvm 的 Xmx。
我环顾四周,但似乎没有任何方法可以防止这种情况发生,即当流式响应超过给定大小时中止请求。
有解决办法吗?我们正在使用 apache 的 httpcomponents httpclient 4.5.5,但任何其他底层实现都是可以接受的。
除了 RestTemplates,Spring 的响应式 WebClient 的解决方案也将受到欢迎。
这必须在底层 HTTP 客户端库中强制执行(spring 支持不同的库,例如 JDK 客户端、apache 客户端、okHTTP..)
你在这里谈论 apache-httpcomponent ,你检查过这个 HttpEntity.getContent()
吗?
它实际上 returns 一个 InputStream ,您可以自己阅读并确定何时超过大小..
https://hc.apache.org/httpcomponents-core-4.4.x/httpcore/apidocs/org/apache/http/HttpEntity.html
作为记录,这里是最终解决方案。问题在于使用分页(通过弹性搜索滚动 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
*/
private long getAvailableFreeMemoryAmount() {
long allocatedMemory = (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory());
return Runtime.getRuntime().maxMemory() - allocatedMemory;
}