正文
HttpClient组件使用的地方较多,很多HTTP客户端都是封装的HTTPClient(spring restTempalte就是基于HTTPClient构建的);HTTPClient可以设置的参数较多,部分参数的设置堆系统影响较大,需要对各个参数有个透彻的了解。
以下是基于使用PoolingHttpClientConnectionManager
项目 | 说明 | 默认值 | 备注 |
---|---|---|---|
maxConnTotal | HTTPClient能够创建的最大连接数 | 20 | 达到上线后,需要等待其他连接销毁后才能继续创建 该数值设得过小在高并发的场景下会阻塞客户端调用 |
maxConnPerRoute | HTTPClient | 2 | 相同域名允许创建的最大连接数 该值过小影响与maxConnTotal一样 |
maxIdleTime | 连接允许的最大空闲时间 | 10秒 | 如果不设置不会清理空闲连接,可能造成服务端连接数耗尽 |
defaultRequestConfig#connectTimeout | 连接超时时间 (tcp三次握手完成时间) | -1(无超时) | 不设置会导致无限等待,有雪崩的风险 (前端无响应刷新页面,会不断发送业务请求) |
defaultRequestConfig#socketTimeout | 2帧网络包之间的间隔时间 或者说socket调用InputStream读数据的超时时间 | -1(无超时) | 影响同defaultRequestConfig#connectTimeout |
defaultRequestConfig#connectionRequestTimeout | 连接池创建连接时的超时时间 | -1(无超时 | maxConnTotal设置过小,导致创建连接时阻塞, connectionRequestTimeout用于设置这个超时时间 超时后抛出异常(Timeout waiting for connection from pool) |
socketTimeout测试及说明
任何网络框架,底层都是基于jdk的Socket。
HTTPClient的socketTimeout参数对应的是Socket的soTimeout,代表读请求的阻塞时间。超过该时间后,抛出异常(java.net.SocketTimeoutException: Read timed out)
public static void main(String[] args) throws IOException {
new Thread(() -> {
try {
ServerSocket serverSocket = new ServerSocket(8001);
while (true) {
Socket socket = serverSocket.accept();
OutputStream outputStream = socket.getOutputStream();
for(int i = 0;i<5;i++) {
Thread.sleep(1000);
outputStream.write('a');
}
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
try {
Socket socket = new Socket("127.0.0.1",8001);
socket.setSoTimeout(2000);
InputStream inputStream = socket.getInputStream();
System.out.println(inputStream.read(new byte[1024]));
} catch (IOException e) {
e.printStackTrace();
}
}).start();
}
测试1-SoTimeout>服务端的睡眠时间
日志打印1,表示只读到1个字节。
测试结果说明
read操作并不一次性读取完整的数据,而是当前接收多少就读多少。因为从Socket这一层并不知道服务端要传多少数据,只能读多少算多少。tcp协议只是个传输协议,因此要设计http等应用层协议,才能正确的工作。
测试2-SoTimeout<服务端的睡眠时间
测试结果-抛出异常
java.net.SocketTimeoutException: Read timed out
at java.net.SocketInputStream.socketRead0(Native Method)
at java.net.SocketInputStream.socketRead(SocketInputStream.java:116)
at java.net.SocketInputStream.read(SocketInputStream.java:171)
at java.net.SocketInputStream.read(SocketInputStream.java:141)
at java.net.SocketInputStream.read(SocketInputStream.java:127)
at com.example.demo.DemoApplication.lambda$main$1(DemoApplication.java:54)
at java.lang.Thread.run(Thread.java:748)
测试结果说明
因为SoTimeout<服务端的睡眠时间,客户端在读到有效数据前已经超过设定的SoTimeout,因此抛出异常。