04 | 连接池:别让连接池帮了倒忙
该思维导图由 AI 生成,仅供参考
注意鉴别客户端 SDK 是否基于连接池
- 深入了解
- 翻译
- 解释
- 总结
连接池在软件开发中扮演着重要角色,但其配置和使用中可能存在一些问题。本文深入探讨了数据库连接池、Redis连接池和HTTP连接池的使用和配置容易出错的地方,并提出了解决多线程环境下连接复用可能带来的问题的解决方案。通过对Jedis的源码分析,作者指出了在多线程环境下复用Jedis对象可能导致的线程安全问题,并提出了使用JedisPool来获得Jedis实例以修复这些问题的最佳实践。文章通过具体的案例和源码分析,帮助读者更好地理解了连接池的使用方式和注意事项,对于开发人员具有一定的参考价值。文章还通过具体案例和源码分析,帮助读者更好地理解了连接池的使用方式和注意事项,对于开发人员具有一定的参考价值。文章还强调了连接池参数配置的重要性,特别是最大连接数的设置,以及建立完善的监控和报警机制的必要性。文章内容技术性较强,适合对连接池有一定了解的读者阅读。
《Java 业务开发常见错误 100 例》,新⼈⾸单¥59
全部留言(53)
- 最新
- 精选
- Darren置顶实操性比较强,收获满满!!! 自从spring boot 2.x版本后,有较大的改动: 默认的redis的链接池从JedisPool变成了LettucePool,Lettuce主要利用netty实现与redis的同步和异步通信。所以更安全和性能更好; 默认的数据库连接池也变更为HikariCP,HiKariCP 号称是业界跑得最快的数据库连接池,HiKariCP 官方网站解释了其性能之所以如此之高的秘密。微观上 HiKariCP 程序编译出的字节码执行效率更高,站在字节码的角度去优化 Java 代码,HiKariCP 的作者对性能的执着可见一斑,不过遗憾的是他并没有详细解释都做了哪些优化。而宏观上主要是和两个数据结构有关,一个是 FastList,另一个是 ConcurrentBag。 FastList是对Java List的增强,HiKariCP作者认为Java SDK的List在其使用场景下比较慢,因此在SDK提供的List(ArrayList的remove)的基础上做了增强; ConcurrentBag是对Java并发集合的增强, 通过 ThreadLocal 做一次预分配,避免直接竞争共享资源,非常适合池化资源的分配。 试着回答下课后的问题: 第一个问题: JedisPool的设置: 获取链接超时:maxWait TCP超时:JedisPool中有一个soTimeout的属性,在链接的时候,使用socket.setSoTimeout(soTimeout)控制的。 HikariCP的设置: 获取链接超时:connectionTimeout。 This property controls the maximum number of milliseconds that a client (that's you) will wait for a connection from the pool. If this time is exceeded without a connection becoming available, a SQLException will be thrown. Lowest acceptable connection timeout is 250ms. Default: 30000 (30 seconds) TCP超时:数据的库的wait_timeout属性吧 Apache HttpClient设置: 获取链接超时:connectionRequestTimeout 建立链接超时:connectionTimeout 等待响应超时:socketTimeout 第二个问题就不回答了,因为到目前为止,还没有在生产使用过Mongo,😂😂😂😂 上面有些参数感觉说的不对,请老师指点
作者回复: 假设我们希望设置连接超时5s,获取连接超时10s: hikari两个参数设置方式: spring.datasource.hikari.connection-timeout=10000 spring.datasource.url=jdbc:mysql://localhost:6657/common_mistakes?connectTimeout=5000&characterEncoding=UTF-8&useSSL=false&rewriteBatchedStatements=true jedis两个参数设置: JedisPoolConfig config = new JedisPoolConfig(); config.setMaxWaitMillis(10000); try (JedisPool jedisPool = new JedisPool(config, "127.0.0.1", 6379, 5000); Jedis jedis = jedisPool.getResource()) { return jedis.set("test", "test"); } httpclient两个参数设置: RequestConfig requestConfig = RequestConfig.custom() .setConnectTimeout(5000) .setConnectionRequestTimeout(10000) .build(); HttpGet httpGet = new HttpGet("http://127.0.0.1:45678/twotimeoutconfig/test"); httpGet.setConfig(requestConfig); try (CloseableHttpResponse response = httpClient.execute(httpGet)) {...
2020-03-16567 - 👽置顶个人总结: 1. 池化技术的核心在于,在鱼塘养好一群鱼,需要的时候就从里面拿一条,用完再放回去。而不是自己生产一条鱼,然后用完就销毁。从而减少了开销。 2. 大多已经实现的连接池,都是有线程安全处理的。通常比个人创建管理连接更加安全。 3. 使用了连接池技术,就要保证连接池能够被有效复用。频繁创建连接池比频繁创建链接更加耗费资源。 4. 连接池的参数配置要根据实际情况,并不存在多多益善 5. 连接池的主要好处:(1)减少资源消耗,(2)利用现有的线城安全实现,(3)提升并发量
作者回复: 总结的不错
2020-03-16213 - Wiggle Wiggle置顶请问对于连接池的监控,是把监控系统直连JMX,监控、修改操作都走连接池已经实现好的JMX比较好?还是自己做一层封装,对外暴露接口,以编程方式获取、设置参数比较好?
作者回复: 自己封装必要不大,然后如果需要走http的话用jolokia,或者使用prometheus的jmx_exporter以agent方式暴露mbeans,https://github.com/prometheus/jmx_exporter
2020-03-1438 - 蚂蚁内推+v退出程序前为什么要关闭连接池啊,程序都结束了连接不就释放了么
作者回复: 优雅关闭总是更好的
2020-03-14311 - 每天晒白牙干货满满,还需要慢慢消化一下
作者回复: 如有收货,欢迎转发
2020-03-148 - 👽课后题2: 受限于本人英文水平,无奈与使用谷歌翻译阅读文档。从文档中得知,MongoClient 对象的正确使用姿势应该是:使用 MongoClients.create()(或者其他有参) 方法创建,并再整个应用程序中使用它。文档内容如下: MongoClient (从3.7版本开始) 一个MongoClient实例表示到数据库连接池; MongoClient即使有多个线程,您也只需要一个类的实例。 重要 通常,您只MongoClient为给定的MongoDB部署创建一个实例(例如独立实例,副本集或分片群集),并在整个应用程序中使用它。但是,如果您确实创建了多个实例: 所有资源使用限制(例如,最大连接数等)适用于每个MongoClient实例。 要处置实例,请致电MongoClient.close()以清理资源。
作者回复: 是的
2020-03-1636 - 👽hikari具体配置项为application.yml 中 spring.datasource.hikari.connection-timeout 点进去可以发现是 HikariDataSource 类,继承了HikariConfig。 点进HikariConfig可看出 connectionTimeout不允许小于250毫秒,小于250ms会被强制重置为30秒。 参数connectionTimeout定义是并未赋初始值的原始类型long,初始值应该是0L; 所以,个人判断,默认的connectionTimeout数值就是30秒。 如有纰漏,欢迎指正
作者回复: 回答一下Hikari的配置,其ConnectionTimeout是从连接池获取数据库连接的超时,不是和MySQL建立连接的超时,后者需要设置JDBC连接字符串中的connectTimeout属性。对于Hikari的JavaConfig配置这2个参数的方式是: @Bean public DataSource dataSource(){ HikariConfig hikariConfig = new HikariConfig(); hikariConfig.setConnectionTimeout(2400); hikariConfig.setJdbcUrl("jdbc:mysql://localhost:6658/common_mistakes"); hikariConfig.addDataSourceProperty("connectTimeout", "1200"); HikariDataSource dataSource = new HikariDataSource(hikariConfig); return dataSource; }
2020-03-1635 - Husiun每次更新都是第一时间打开,每一课都干货满满,必须给老师赞一个,http那个平时研究不多还需要好好消化一下。
作者回复: 有收货就好
2020-03-145 - justin老师你好,看了这篇文章感觉收获满满,然后关于上面的CloseableHttpClient有个几个疑问: 1、复用同一个tcp连接的时候比每次都创建一个新的tcp连接的QPS高很多,当有大量http请求服务端时,每个http连接都共用同一个tcp连接时,这种情况下不会造成其中一些http请求的响应速度变慢吗。 2、 httpClient = HttpClients.custom().setMaxConnPerRoute(1).setMaxConnTotal(1).evictIdleConnections(60, TimeUnit.SECONDS).build(); 当我尝试去扩大setMaxConnTotal这个最大连接数时,qps反而降低了。如果线上有上千qps的话,设置连接数为1就可以了吗。
作者回复: 1、其实本文说的点不是复用连接,而是复用连接池,也就是CloseableHttpClient,一个TCP连接同时自然无法实现多个HTTP请求的复用 2、文中设置为1只是举例,实际应用的时候显然应该设置一个合理的最大值,不能是1。扩大MaxConnPerRoute和MaxConnTotal之后qps降低,这个有没有实际的性能数据?你是怎么测试的呢?
2020-03-2624 - pedro干货很多,收获很大。问老师一个问题,使用hook来关闭连接池的时候,都会创建一个线程,那如果有多个连接池,每个连接池都有一个线程来调用hook,这样做是否有点奢侈,有没有更优的办法?
作者回复: 可以都放到一个Thread,放到多个的话会并行执行,只要不是太多问题不大。或者用Spring的话还可以使用@PreDestroy来实现资源释放。
2020-03-1424