Riak Java HTTPClientAdapter TCP CLOSE_WAIT
Riak Java HTTPClientAdapter TCP CLOSE_WAIT
TLDR:
大量 TCP 连接处于 OPEN_WAIT 状态,正在关闭服务器
设置:
riak_1.2.0-1_amd64.deb 安装在 Ubuntu12 上
SpringMVC 3.2.5
riak-client-1.1.0.jar
Tomcat7.0.51 托管在 Windows Server 2008 R2 上
JRE6_45
完整描述:
我如何确保 Java RiakClient 正确清理它与我没有留下大量 CLOSE_WAIT tcp 连接的连接?
我有一个 Spring MVC 应用程序,它使用 Riak java 客户端连接到远程 instance/cluster。
我们在托管 Spring MVC 应用程序的服务器上看到大量 TCP 连接,这些连接会继续增加,直到服务器无法再连接到任何东西,因为没有可用端口。
重新启动 Riak 集群不会清除连接。
重新启动 webapp 确实会清除额外的连接。
我们正在使用 HTTPClientAdapter 和 REST api。
当连接到关系数据库时,我通常会通过在连接上显式调用 close 或通过向池和事务管理器注册数据源然后使用 @Transactional 注释我的服务来清理连接。
但是自从使用了 HTTPClientAdapter 之后,我希望它更像一个 HttpClient。
使用 HttpClient,我会使用 Response 实体,使用 EntityUtils.consume(...),以确保正确清理所有内容。
HTTPClientAdapter 确实有一个关闭方法,我看到它在在线示例中被调用。
当我追踪到实际 RiakClient 的方法调用时,该方法是空的。
此外,当我深入研究源代码时,它没有在任何地方关闭 HttpResponse 上的 Stream 或使用任何响应实体(与标准 Apache EntityUtils 示例一样)。
下面是调用方式的示例。
private RawClient getRiakClientFromUrl(String riakUrl) {
return new HTTPClientAdapter(riakUrl);
}
public IRiakObject fetchRiakObject(String bucket, String key, boolean useCache) {
try {
MethodTimer timer = MethodTimer.start("Fetch Riak Object Operation");
//logger.debug("Fetching Riak Object {}/{}", bucket, key);
RiakResponse riakResponse;
riakResponse = riak.fetch(bucket, key);
if(!riakResponse.hasValue()) {
//logger.debug("Object {}/{} not found in riak data store", bucket, key);
return null;
}
IRiakObject[] riakObjects = riakResponse.getRiakObjects();
if(riakObjects.length > 1) {
String error = "Got multiple riak objects for " + bucket + "/" + key;
logger.error(error);
throw new RuntimeException(error);
}
//logger.debug("{}", timer);
return riakObjects[0];
}
catch(Exception e) {
logger.error("Error fetching " + bucket + "/" + key, e);
throw new RuntimeException(e);
}
}
我能想到的唯一选择是与适配器分开创建 RiakClient,这样我就可以访问 HttpClient,然后访问 ConnectionManager。
我目前正在努力切换到 PBClientAdapter 以查看是否有帮助,但出于这个问题的目的(并且因为团队的其他成员可能出于某种原因不喜欢我切换),让我们假设我必须继续通过 HTTP 连接。
所以已经快一年了,所以我想我会继续post我是如何解决这个问题的。
解决方案是将我们使用的客户端实现更改为 java 客户端提供的 HTTPClientAdapter,传递配置以实现池和最大连接数。下面是一些代码示例,说明如何执行此操作。
首先,我们使用的是旧版本的 RIAK,所以这里是 amven 依赖项:
<dependency>
<groupId>com.basho.riak</groupId>
<artifactId>riak-client</artifactId>
<version>1.1.4</version>
</dependency>
下面是示例:
public RawClient riakClient(){
RiakConfig config = new RiakConfig(riakUrl);
//httpConnectionsTimetolive is in seconds, but timeout is in milliseconds
config.setTimeout(30000);
config.setUrl("http://myriakurl/);
config.setMaxConnections(100);//Or whatever value you need
RiakClient client = new RiakClient(riakConfig);
return new HTTPClientAdapter(client);
}
我实际上在我的实现中打破了一点,并使用 Spring 来注入值;我只是想展示一个简化的例子。
通过将超时设置为小于标准的五分钟,系统将不会挂起连接太久(因此,5 分钟 + 无论您将超时设置为多少)都会导致连接进入 close_wait状态更快。
当然,设置池中的最大连接数可防止应用程序打开数以千计的连接数。
TLDR:
大量 TCP 连接处于 OPEN_WAIT 状态,正在关闭服务器
设置:
riak_1.2.0-1_amd64.deb 安装在 Ubuntu12 上 SpringMVC 3.2.5 riak-client-1.1.0.jar Tomcat7.0.51 托管在 Windows Server 2008 R2 上 JRE6_45
完整描述:
我如何确保 Java RiakClient 正确清理它与我没有留下大量 CLOSE_WAIT tcp 连接的连接?
我有一个 Spring MVC 应用程序,它使用 Riak java 客户端连接到远程 instance/cluster。
我们在托管 Spring MVC 应用程序的服务器上看到大量 TCP 连接,这些连接会继续增加,直到服务器无法再连接到任何东西,因为没有可用端口。
重新启动 Riak 集群不会清除连接。
重新启动 webapp 确实会清除额外的连接。
我们正在使用 HTTPClientAdapter 和 REST api。
当连接到关系数据库时,我通常会通过在连接上显式调用 close 或通过向池和事务管理器注册数据源然后使用 @Transactional 注释我的服务来清理连接。
但是自从使用了 HTTPClientAdapter 之后,我希望它更像一个 HttpClient。 使用 HttpClient,我会使用 Response 实体,使用 EntityUtils.consume(...),以确保正确清理所有内容。
HTTPClientAdapter 确实有一个关闭方法,我看到它在在线示例中被调用。 当我追踪到实际 RiakClient 的方法调用时,该方法是空的。 此外,当我深入研究源代码时,它没有在任何地方关闭 HttpResponse 上的 Stream 或使用任何响应实体(与标准 Apache EntityUtils 示例一样)。
下面是调用方式的示例。
private RawClient getRiakClientFromUrl(String riakUrl) {
return new HTTPClientAdapter(riakUrl);
}
public IRiakObject fetchRiakObject(String bucket, String key, boolean useCache) {
try {
MethodTimer timer = MethodTimer.start("Fetch Riak Object Operation");
//logger.debug("Fetching Riak Object {}/{}", bucket, key);
RiakResponse riakResponse;
riakResponse = riak.fetch(bucket, key);
if(!riakResponse.hasValue()) {
//logger.debug("Object {}/{} not found in riak data store", bucket, key);
return null;
}
IRiakObject[] riakObjects = riakResponse.getRiakObjects();
if(riakObjects.length > 1) {
String error = "Got multiple riak objects for " + bucket + "/" + key;
logger.error(error);
throw new RuntimeException(error);
}
//logger.debug("{}", timer);
return riakObjects[0];
}
catch(Exception e) {
logger.error("Error fetching " + bucket + "/" + key, e);
throw new RuntimeException(e);
}
}
我能想到的唯一选择是与适配器分开创建 RiakClient,这样我就可以访问 HttpClient,然后访问 ConnectionManager。
我目前正在努力切换到 PBClientAdapter 以查看是否有帮助,但出于这个问题的目的(并且因为团队的其他成员可能出于某种原因不喜欢我切换),让我们假设我必须继续通过 HTTP 连接。
所以已经快一年了,所以我想我会继续post我是如何解决这个问题的。
解决方案是将我们使用的客户端实现更改为 java 客户端提供的 HTTPClientAdapter,传递配置以实现池和最大连接数。下面是一些代码示例,说明如何执行此操作。
首先,我们使用的是旧版本的 RIAK,所以这里是 amven 依赖项:
<dependency>
<groupId>com.basho.riak</groupId>
<artifactId>riak-client</artifactId>
<version>1.1.4</version>
</dependency>
下面是示例:
public RawClient riakClient(){
RiakConfig config = new RiakConfig(riakUrl);
//httpConnectionsTimetolive is in seconds, but timeout is in milliseconds
config.setTimeout(30000);
config.setUrl("http://myriakurl/);
config.setMaxConnections(100);//Or whatever value you need
RiakClient client = new RiakClient(riakConfig);
return new HTTPClientAdapter(client);
}
我实际上在我的实现中打破了一点,并使用 Spring 来注入值;我只是想展示一个简化的例子。
通过将超时设置为小于标准的五分钟,系统将不会挂起连接太久(因此,5 分钟 + 无论您将超时设置为多少)都会导致连接进入 close_wait状态更快。
当然,设置池中的最大连接数可防止应用程序打开数以千计的连接数。