mysql、redis 客户端连接池

1.mysql

1.1. mysql 参数

通过下列命令可查看mysql数据库配置的系统参数:

-- 查询所有系统参数
show variables;
--模糊匹配查询系统参数,如:wait_timeout
show variables like '%wait_timeout%';

这里介绍几个和连接池有关联的参数:

1. wait_timeout

非交互连接的最大存活时间,单位:秒。即空闲状态下的连接,超过规定时间后,mysql 会自动断开。

可通过下列命令查看具体的连接的状态:

show processlist;

如果 sleep 状态的进程,占用总比例过高,就可以考虑调小 wait_timeout 值了。

2. max_connections

全局最大连接数。

可通过下列命令查看最大使用的连接数量(Max_used_connections):

show status like 'max%connections%';

再通过下列命令查看最大连接数(max_connections):

show variables like 'max%connections%';

通过 Max_used_connections/max_connections 的占比来判断设置的最大连接数是否合理,理想情况下这个比例应该在85%左右。

max_connections 默认值是100,如果服务器的并发连接请求量比较大,建议调高此值,以增加并行连接数量,当然这建立在机器能支撑的情况下,因为如果连接数越多,介于MySQL会为每个连接提供连接缓冲区,就会开销越多的内存,所以要适当调整该值,不能盲目提高设值。

1.2. druid 连接池配置

核心参数

1. initial-size

初始化时建立物理连接的个数。

2. max-active

连接池同时能维持的最大连接数。

3. min-idle

最多维持多少个空闲连接,即使客户端没有需求,也要至少维持多少个空闲连接,以应对客户端的突发需求。

4. max-idle(已作废)

5. max-wait

连接最大等待时间,单位毫秒。客户端从连接池获取(借出)一个连接后,规定时间内没有归还,则连接池会抛出 GetConnectionTimeoutException 异常。

场景模拟

假设配置的值如下:

spring.datasource.druid.initial-size=5
spring.datasource.druid.min-idle=10
spring.datasource.druid.max-active=50

项目启动时,会自动创建5(initial-size)个连接,就算此时没有数据库访问,也会创建这5个。并且当客户端查询数据库的并发不大于5时,就一直是这5个。

当客户端查询数据库的并发越来越大,超过5时,连接数也就往上增加,但不会超过最大连接数50(max-active)。当并发数超过50时,超过部分的请求就会在队列中等待。

当峰值过去了,并发数降到50一下,多出来的连接空闲后就关闭了,连接数也就随之下降。当连接数最小只会降到10(min-idle),最多维持10个空闲连接。

1.3. hikari 连接池配置

下列翻译自 HikariCP Github参数说明

1. connection-timeout

控制客户端等待来自连接池连接的最大毫秒数。

如果超过此时间而没有可用的连接,则会抛出SQLException。可接受的最低连接超时为250 ms。 默认值:30000(30秒)

2. max-lifetime

控制连接池中连接的最大生存时间。

正在使用中的连接永远不会停止使用,只有在连接关闭后,在达到最大生存周期后才将其删除。值为0表示没有最大生存期(无限生存期),当然这取决于idleTimeout设置。最小允许值是30秒,默认值:30分钟。

建议:设置的时间要比数据库中限制的连接(mysql对应参数 wait_timeout)最大生存时间小几秒钟。

3. minimum-idle

此属性控制HikariCP试图在池中维护的最小空闲连接数。

如果空闲连接低于此值,并且池中的总连接小于最大池大小,HikariCP将尽最大努力快速高效地添加其他连接。默认值:与 maximum-pool-size 相同。

建议:为了最大限度地提高性能和响应峰值需求,我们建议不要设置此值,而是允许HikariCP充当固定大小的连接池。即保持和 maximum-pool-size 值相同。

4. idle-timeout

此属性控制允许连接在池中空闲的最长时间。

仅当 minimum-idle 定义为小于 maximum-pool-size 时,此设置才适用。一旦池达到最小空闲连接数,空闲连接将不会失效。连接是否因空闲而失效取决于+30秒的最大变化和+15秒的平均变化。在此超时之前,连接永远不会以空闲状态退出。值为0表示从不从池中删除空闲连接。最小允许值为10000ms(10秒)。默认值:600000(10分钟)。

建议:因为是建议 minimum-idle 和 maximum-pool-size 保持一致,维护固定大小的连接池,则 idle-timeout 设置不会生效。建议就保持默认值,或者干脆设为0。

5. maximum-pool-size

此属性控制池允许达到的最大大小,包括空闲连接和正在使用的连接。基本上,该值将确定到数据库后端的实际连接的最大数量。当池达到此大小且没有空闲连接可用时,对getConnection() 的调用将在超时前阻塞最多 connection-timeout 毫秒。默认值:10。

建议:没有绝对的值,因为是连接池的最大连接数,所以要根据产线业务 TPS 并发量,以及服务器实际配置各种环境来灵活考量配置,影响因素如下:

  • CPU核心数:首先网上有这么个公式:最大连接数 = ((CPU核心数 * 2) + 有效磁盘数)。可见,最大连接数是和CPU核心数是密切相关的。因为最大连接数是和最大并发线程相关的,当CPU核心数有限时,一味的扩大并发连接数,反而会因为上下文切换导致性能下降。
  • 数据库总连接数: 应用连接池的配置是针对某个服务单实例的,但通常一个数据库是多个服务共享的。假设有10个服务,每个服务平均有8个实例负载,单个连接池的最大连接数设为50。那么总的连接数就是 10 8 50 = 4000。而如果mysql数据库的 max_connections 不到4000,那么必然会导致有些连接失效。

2. redis

2.1. redis 参数

1. 查看允许最大连接数量

执行命令:

config get maxclients

返回结果示例,即最大连接数10000:

maxclients
10000
2. 查看实时连接数量
info clients

返回结果示例,依次返回的内容有:(1)当前客户端连接数、(2)当前所有输出缓存区中队列对象个数的最大值、(3)当前所有输出缓存区中占用的最大容量、(4)正在等待阻塞命令(如:BLPOP)的客户端数量

# Clients
connected_clients:39
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:1

2.2. jedis 连接池配置

1. max-totalmax-active

资源池中的最大连接数。默认值:8。旧版本中是 max-active,jedis 2.4.x 以上都用 max-total 来替代。

想合理设置maxTotal(最大连接数)需要考虑的因素较多,如:

  • 业务希望的Redis并发量;
  • 客户端执行命令时间;
  • Redis资源,例如 nodes * maxTotal 不能超过Redis的最大连接数;
  • 资源开销,例如虽然希望控制空闲连接,但又不希望因为连接池中频繁地释放和创建连接造成不必要的开销。

假设一次命令时间,即borrow|return resource加上Jedis执行命令 ( 含网络耗时)的平均耗时约为1ms,一个连接的QPS大约是1s/1ms = 1000,而业务期望的单个Redis的QPS是50000(业务总的QPS/Redis分片个数),那么理论上需要的资源池大小(即MaxTotal)是50000 / 1000 = 50。

但事实上这只是个理论值,除此之外还要预留一些资源,所以maxTotal可以比理论值大一些。

这个值不是越大越好,一方面连接太多会占用客户端和服务端资源,另一方面对于Redis这种高QPS的服务器,如果出现大命令的阻塞,即使设置再大的资源池也无济于事。

综上所述,在没有达到资源瓶颈前,jedis 最大连接数和能实现并发量是成正比的。如果处于高并发的需求,可以多加连接数。

2. max-idle

资源池允许的最大空闲连接数。默认值:8。

maxIdle实际上才是业务需要的最大连接数,maxTotal 是为了给出余量,所以 maxIdle 不要设置得过小,否则会有new Jedis(新连接)开销,而minIdle是为了控制空闲资源检测。

连接池的最佳性能是 maxTotal=maxIdle,这样就避免了连接池伸缩带来的性能干扰。如果您的业务存在突峰访问,建议设置这两个参数的值相等;如果并发量不大或者maxIdle设置过高,则会导致不必要的连接资源浪费。

可以根据实际总QPS和调用Redis的客户端规模整体评估每个节点所使用的连接池大小。在实际环境中,比较可靠的方法是通过监控来尝试获取参数的最佳值。可以考虑通过JMX等方式实现监控,从而找到合理值。

3. min-idle

资源池允许的最小空闲连接数。默认值:0。

4. block-when-exhausted

当资源池用尽后,调用者是否要等待。只有当值为true时,下面的max-wait-millis才会生效。默认值:true。

5. max-wait-millismax-wait

当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)。默认值:-1(表示永不超时)。旧版本中是 max-wait,jedis 2.4.x 以上都用 max-wait-millis 来替代。

2.3. lettuce 连接池配置

1. max-total

连接池最大连接数(使用负值表示没有限制)。默认值:8。

推荐:cpu核数*2。

2. max-idle

连接池最大空闲连接数(使用负值表示没有限制),仅当 min-idle 和 time-between-eviction-runs 的值都为正时有效。。默认值:8。

推荐:cpu核数*2。

3. min-idle

连接池最小空闲连接数,仅当 min-idle 和 time-between-eviction-runs 的值都为正时有效。默认值:0。

推荐:根据时间场景,是否需要初始化预热等等。

4. time-between-eviction-runs

空闲连接逐出器(独立线程)的运行间隔时间(单位为毫秒)。当值为正值时,空闲连接逐出器才启动。

这个逐出器的任务一旦启动后,不仅可以将连接池中超过 max-idle 数量的空闲连接逐出;还会在连接池中空闲连接数少于 min-idle 时,补齐空闲连接的创建。

推荐:正值,开启任务。

5. max-wait

连接池资源耗尽时,连接尝试分配阻塞时间(单位为毫秒),超时即抛出异常。(使用负值表示没有限制)。默认值:-1ms。

推荐:开启,根据业务设置,不建议设置过大,否则耗尽业务线程池。

2.4. 场景模拟

Jedis 和 Lettuce 采用的连接池是 GenericObjectPoolConfig 所以通用的配置项是相同的,那么就都基于统一配置做场景模拟。

场景一
xxx.max-total=30
xxx.max-idle=20
xxx.min-idle=10

当连接池刚启动,且空闲连接数不超过10。如果需要使用连接时,连接池会一直创建新连接,而不会复用空闲连接。直到连接池中连接数量达到了10(min-idle)。

当连接数超过10,实际连接数又继续增加,但由于总连接数 max-total 是30。当总连接数达到30后,不会创建新的连接,后续连接请求会在等待。

当实际使用的连接数从30降下来后,一部分连接转为了空闲连接。即:在用连接数量在减少,空闲连接数量在增加。但当空闲连接数量大于20(max-idle)时,后续的空闲连接将不会放回连接池,而是直接扔掉。

2.5. jedis vs lettuce

简单的说, Jedis连接池越大越好, Lettuce连接池越小越好, 为什么会有这种差异?

Jedis采用传统BIO网络模型, 在资源允许的范围内, 这种模型下连接数(线程数)越多性能越好。

Lettuce采用NIO网络模型, 底层组件采用Netty, 这种模型下性能和CPU核数相关, 通常云主机CPU核数都不大通常在2-16核, 因此Lettuce连接池配置普遍不宜过大, 过大范围会影响性能。

你可能感兴趣的:(mysql、redis 客户端连接池)