vert HttpClient性能非常好,但是使用不当,就会出现非常难于定位的问题。很多问题非常严重,比如挂死,分析日志、堆栈都可能看不出任何原因。因此在写代码的时候,就需要非常注意。下面有几个排查点:
-
设置请求超时时间。必须合理设计超时时间,否则异常情况,会导致连接不释放。如果在response里面做其他操作,还需要重设超时时间。 例如:
HttpClientRequest clietRequest = httpClient.request(context.request().method(), uri.getPort(), uri.getHost(), "/" + path + params).setTimeout(10000); //设置请求超时时间 clietRequest.handler(clientResponse -> { clietRequest.setTimeout(10000); //如果解析响应还可能超时,那么也必须重设超时时间 context.request().response().setStatusCode(clientResponse.statusCode()); context.request().response().headers().setAll(clientResponse.headers()); LOGGER.info("remote response begins"); clientResponse.handler(data -> { context.request().response().write(data); LOGGER.info("remote response data transfer"); }); clientResponse.endHandler((v) -> { context.request().response().end(); LOGGER.info("remote response data transfer end"); }); clientResponse.exceptionHandler(e -> { LOGGER.info("e", e); }); }); 2. 设置闲置超时时间和最大队列大小。如果不设置,也可能导致连接不释放。新进来请求没有连接可用,造成等待挂死。需要注意的是,闲置超时时间的单位是秒,和其他接口不同。如果不看文档,肯定就弄错了。 vertx.createHttpClient( new HttpClientOptions().setSsl(false) .setVerifyHost(false) .setTrustAll(true) .setKeepAlive(true) .setConnectTimeout(2000) .setIdleTimeout(10)// 闲置超时时间 .setMaxWaitQueueSize(10)); //最大队列大小 3. 设置exceptionHandler。request和response都需要设置合理的异常处理,以跟踪错误。 clietRequest.exceptionHandler(e -> { LOGGER.error("xxxxx", e); context.response().end(); }); clietRequest.connectionHandler(h -> { h.exceptionHandler(eh -> { LOGGER.error("conn", eh); }); LOGGER.info("connection " + h); }); 在上述代码中,还有个坑 context.request().response().headers().setAll(clientResponse.headers()); 将一个请求的响应头全部拷贝到另外一个响应的头中(看起来是纯粹的HTTP转发)。这个操作是不对的。因为有些响应头是HTTP的控制消息,比如:Content-Length, Transfer-Encoding。一旦将两个头拷贝进去,就可能影响到HTTP报文的完整性(丢失或者多出额外的字节)。代码需要做一些特殊处理,不要拷贝这两个头。 |