前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java里的各种连接池你真的懂了?

Java里的各种连接池你真的懂了?

作者头像
JavaEdge
发布2021-12-07 08:55:40
6150
发布2021-12-07 08:55:40
举报
文章被收录于专栏:JavaEdgeJavaEdge

使用连接池务必确保复用

池的本质意义在于复用: 创建连接池时,很可能一次性创建了多个连接,大多数连接池考虑到性能,会在初始化的时候维护一定数量的最小连接(毕竟初始化连接池的过程一般是一次性的),可以直接使用。如果每次使用连接池都按需创建连接池,那么很可能你只用到一个连接,但是创建了N个连接。 连接池一般会有一些管理模块,即连接池的结构示意图中的绿色部分。 大多数的连接池都有闲置超时。连接池会检测连接的闲置时间,定期回收闲置的连接,把活跃连接数降到最低(闲置)连接的配置值,减轻服务端的压力。 一般闲置连接由独立线程管理,启动空闲检测的连接池相当于还会启动一个线程。 有些连接池还需独立线程负责连接保活功能。因此,启动一个连接池相当于启动了N个线程。

连接池不释放,还可能会引起线程泄露:

连接池不复用

使用这个连接来请求一个会返回OK字符串的服务端接口:

访问该接口几次后执行jstack,可以看到有很多叫作Connection evictor的线程,且这些线程不会销毁

代码语言:javascript
复制
➜  ~ jstack 86194 | grep evictor
"Connection evictor" #120 daemon prio=5 os_prio=31 tid=0x00007fbe708ac000 nid=0xd207 waiting on condition [0x0000700009b90000]
"Connection evictor" #119 daemon prio=5 os_prio=31 tid=0x00007fbe70475000 nid=0x13713 waiting on condition [0x00007000066f4000]
"elasticBounded-evictor-1" #115 daemon prio=5 os_prio=31 tid=0x00007fbe6f090800 nid=0xd503 waiting on condition [0x000070000b0cf000]
"Connection evictor" #85 daemon prio=5 os_prio=31 tid=0x00007fbe6e5a4800 nid=0x14307 waiting on condition [0x0000700009c93000]

大部分都是HttpClient到Tomcat的连接:

代码语言:javascript
复制
➜  ~ lsof -nP -i4TCP:30666 | wc -l
       8

有空闲连接回收策略

代码语言:javascript
复制
➜  ~ lsof -nP -i4TCP:30666
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
java    91607 apple  518u  IPv6 0xe45224391c3078b1      0t0  TCP *:30666 (LISTEN)
java    91607 apple  526u  IPv6 0xe4522438da39cf31      0t0  TCP 127.0.0.1:64404->127.0.0.1:30666 (ESTABLISHED)
java    91607 apple  528u  IPv6 0xe4522438da3a0031      0t0  TCP 127.0.0.1:30666->127.0.0.1:64404 (ESTABLISHED)
java    91607 apple  529u  IPv6 0xe4522438da39db71      0t0  TCP 127.0.0.1:64414->127.0.0.1:30666 (ESTABLISHED)
java    91607 apple  530u  IPv6 0xe45224390b2aedd1      0t0  TCP 127.0.0.1:30666->127.0.0.1:64414 (ESTABLISHED)
java    91607 apple  531u  IPv6 0xe45224390b2b0651      0t0  TCP 127.0.0.1:64422->127.0.0.1:30666 (ESTABLISHED)
java    91607 apple  532u  IPv6 0xe45224390b2ad551      0t0  TCP 127.0.0.1:30666->127.0.0.1:64422 (ESTABLISHED)

# 60s后连接处于CLOSE_WAIT状态,最终彻底关闭。
➜  ~ lsof -nP -i4TCP:30666
COMMAND   PID  USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
java    91607 apple  518u  IPv6 0xe45224391c3078b1      0t0  TCP *:30666 (LISTEN)
java    91607 apple  529u  IPv6 0xe4522438da39db71      0t0  TCP 127.0.0.1:64414->127.0.0.1:30666 (CLOSE_WAIT)

以上结果表明CloseableHttpClient属内部带有连接池的API

如何做到复用

CloseableHttpClient声明为static,只创建一次,并在JVM关闭前通过addShutdownHook钩子关闭连接池,在使用的时候直接使用CloseableHttpClient即可,无需每次都创建。

定义一个case2接口实现服务端接口调用:

定义个case3接口,修复之前按需创建CloseableHttpClient的代码,每次用完后确保连接池可关闭

使用wrk对case2和case3分别压测60s,可见两种使用方式的性能差异:

  • 每次创建连接池的QPS是725
代码语言:javascript
复制
➜  ~ wrk -c1 -t1 -d 10s http://localhost:30666/httpclientnotreuse/case3
Running 10s test @ http://localhost:30666/httpclientnotreuse/case3
  1 threads and 1 connections
 	Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     1.75ms    2.94ms  39.59ms   97.61%
    Req/Sec   728.82    170.53     0.95k    69.00%
  7260 requests in 10.00s, 816.67KB read
Requests/sec:    725.78
Transfer/sec:     81.64KB
  • 复用连接池的QPS是2515
代码语言:javascript
复制
➜  ~ wrk -c1 -t1 -d 10s http://localhost:30666/httpclientnotreuse/case2
Running 10s test @ http://localhost:30666/httpclientnotreuse/case2
  1 threads and 1 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency   411.81us  387.15us  11.83ms   97.72%
    Req/Sec     2.53k   193.26     2.76k    83.17%
  25428 requests in 10.10s, 2.79MB read
Requests/sec:   2517.61
Transfer/sec:    283.21KB

大的性能差距就在于TCP连接的复用。定义连接池时,我将最大连接数设置为1。所以,复用连接池方式复用的始终应该是同一个连接,而新建连接池方式应该是每次都会创建新的TCP连接。

Wireshark验证

若调用case3接口,每次创建新的连接池发起HTTP请求,可以看到每次请求服务端30666的客户端端口都是新的。这里我发起了三次请求,程序通过HttpClient访问服务端30666的客户端端口号,分别是63696、63697、63698

即每次都是新的TCP连接,去掉HTTP这个过滤条件,即可看到TCP握手、挥手过程

而复用连接池方式的接口case2的表现就完全不同了。可以看到,第二次HTTP请求的客户端端口56377和第一次连接的端口是一样的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-03-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 使用连接池务必确保复用
  • 连接池不复用
    • 如何做到复用
      • Wireshark验证
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档