使用Jersey的JAX RS的内存问题 [英] Memory issue with JAX RS using jersey

查看:154
本文介绍了使用Jersey的JAX RS的内存问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们目前在生产服务器上遇到了一些麻烦,因为它消耗了太多的内存.泄密事件之一可能来自球衣客户.我发现了以下两个其他问题以及操作方法:

We currently have some trouble on a productive server as it consumes way too much memory. One of the leaks could come from the jersey client. I found the following two other questions and a how to:

  1. 如何正确共享JAX-RS 2.0客户端
  2. 关闭JAX RS客户端/响应
  3. https://blogs.oracle.com/japod/entry/how_to_use_jersey_client
  1. How to correctly share JAX-RS 2.0 client
  2. Closing JAX RS Client/Response
  3. https://blogs.oracle.com/japod/entry/how_to_use_jersey_client

我从中得到的好处是,我应该重用Client以及WebTargets? 还建议关闭响应,但是如何使用.request()完成此操作?

What I get from it, I should reuse the Client and potentially also the WebTargets? Also closing responses is advised, but how can I do this with .request()?

代码示例,每小时使用不同的路径被调用约1000次:

Code example, this is getting called about 1000 times per hour with different paths:

public byte[] getDocument(String path) {
    Client client = ClientBuilder.newClient();
    WebTarget target = client.target(config.getPublishHost() + path);
    try {
        byte[] bytes = target.request().get(byte[].class);
        LOGGER.debug("Document size in bytes: " + bytes.length);
        return bytes;
    } catch (ProcessingException e) {
        LOGGER.error(Constants.PROCESSING_ERROR, e);
        throw new FailureException(Constants.PROCESSING_ERROR, e);
    } catch (WebApplicationException e) {
        LOGGER.error(Constants.RESPONSE_ERROR, e);
        throw new FailureException(Constants.RESPONSE_ERROR, e);
    } finally {
        client.close();
    }
}

所以我的问题是如何正确使用API​​来防止上述示例的泄漏?

推荐答案

Client实例应重用

Client 实例是管理基础客户端通信基础结构的重量级对象.因此,初始化和处理 Client 实例可能是一项相当昂贵的操作.

Client instances should be reused

Client instances are heavy-weight objects that manage the underlying client-side communication infrastructure. Hence initialization as well as disposal of a Client instance may be a rather expensive operation.

文档建议仅创建 Client 实例必须先正确关闭,然后再处置,以避免资源泄漏.

The documentation advises to create only a small number of Client instances and reuse them when possible. It also states that Client instances must be properly closed before being disposed to avoid leaking resources.

您可以重复使用 WebTarget 实例(如果您对同一路径执行多个请求).重复使用 WebTarget 实例是如果它们具有某些配置,则建议使用.

You could reuse WebTarget instances if you perform multiple requests to the same path. And reusing WebTarget instances is recommended if they have some configuration.

Response 实例包含未消耗的实体输入流的容器应该被关闭.对于仅处理响应标头和状态代码,而忽略响应实体的情况,这是典型的情况.请参阅此 answer 了解有关关闭

Response instances that contain an un-consumed entity input stream should be closed. This is typical for scenarios where only the response headers and the status code are processed, ignoring the response entity. See this answer for more details on closing Response instances.

对于问题中提到的情况,您希望确保 Client 实例可用于所有getDocument(String)方法调用.

For the situation mentioned in your question, you want you ensure that the Client instance is reused for all getDocument(String) method invocations.

例如,如果您的应用程序基于CDI,则创建 Client 实例,当构造该bean并在销毁它之前对其进行处置.在下面的示例中, Client 实例存储在一个单例bean中:

For instance, if your application is CDI based, create a Client instance when the bean is constructed and dispose it before its destruction. In the example below, the Client instance is stored in a singleton bean:

@Singleton
public class MyBean {

    private Client client;

    @PostConstruct
    public void onCreate() {
        this.client = ClientBuilder.newClient();
    }

    ...

    @PreDestroy
    public void onDestroy() {
        this.client.close();
    }
}

您不需要(或也许您不能)重用 Response 实例是当您将实体读入byte[]时会自动关闭.

You don't need to (or maybe you can't) reuse the WebTarget instance (the requested path changes for each method invocation). And the Response instance is automatically closed when you read the entity into a byte[].

连接池可以改善性能.

如我以前的 answer 中所述,默认情况下,泽西岛的运输层由 HttpUrlConnectorProvider .您可以根据需要替换默认的连接器,并使用连接池以获得更好的性能.

As mentioned in my older answer, by default, the transport layer in Jersey is provided by HttpURLConnection. This support is implemented in Jersey via HttpUrlConnectorProvider. You can replace the default connector if you want to and use a connection pool for better performance.

Jersey通过

Jersey integrates with Apache HTTP Client via the ApacheConnectorProvider. To use it, add the following dependecy:

<dependency>
    <groupId>org.glassfish.jersey.connectors</groupId>
    <artifactId>jersey-apache-connector</artifactId>
    <version>2.26</version>
</dependency>

然后创建 Client 实例如下:

And then create your Client instance as following:

PoolingHttpClientConnectionManager connectionManager = 
        new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(100);
connectionManager.setDefaultMaxPerRoute(5);

ClientConfig clientConfig = new ClientConfig();
clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager);
clientConfig.connectorProvider(new ApacheConnectorProvider());

Client client = ClientBuilder.newClient(clientConfig);

有关其他详细信息,请参见有关连接器的泽西岛文档

For additional details, refer to Jersey documentation about connectors.

这篇关于使用Jersey的JAX RS的内存问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆