一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
连接池跟线程池一样,也是一种池化技术,主要目的都是实现复用。连接池的主要实现了连接的复用。当客户端需要连接的时候,直接从连接池获得即可,不需要重新建立新的连接,这样减少了直接创建连接的资源消耗。同时连接池内部实现了连接建立、连接心跳保持、连接管理、空闲连接回收、连接可用性检测等功能。
平时用到的连接池主要有:数据库连接池、Redis连接池、HTTP连接池。
如何判断客户端SDK是否基于连接池?可以通过命名方式判断(并不绝对)
- 连接池和连接分离的API: XXXPool 类负责连接池实现,再从池中获取连接XXXConnection
- 内部带有连接池的API:XXXClient
- 非连接池的API:XXXConnection
使用连接池需要注意的问题:
一、如果客户端SDK没有使用连接池,在多线程的情况下对同一个连接进行复用,可能会产生线程安全问题。
如:Jedis jedis = new Jedis("127.0.0.1", 6379)
,为非连接池的API,如果在并发环境下使用同一个jedis,则会出现线程安全问题。
可以替换为JedisPool连接池方式创建连接
JedisPool jedisPool = new JedisPool("127.0.0.1", 6379);
Jedis resource1 = jedisPool.getResource();
Jedis resource2 = jedisPool.getResource();
二、使用连接池要确保连接池的复用。比如某个XXXClient客户端内部已经使用了连接池,我们就不能频繁的创建XXXClient对象,把XXXClient声明为static即可。
三、合理配置连接池的参数,最重要的是最大连接数,它决定了连接池能使用的连接数量上限。如果设置过大,客户端需要消耗更多的资源维护连接;服务器由于对应多个客户端,每一个客户端保持大量的连接,服务器压力更大。如果设置过小,可能会因为获取连接的等待时间太长,导致吞吐量低下。甚至超时无法获取连接。
最大连接数需要根据实际调试情况来确定,通常先确定最终应用的并发,再根据这个并发留出一半的余量来设置最终的最大连接数。更合适的做法,对重要资源进行持续检测,设置一半的使用量作为报警阈值,出现预警后及时扩容。
参考:《Java 业务开发常见错误 100 例》的【04 | 连接池:别让连接池帮了倒忙】]