你的Redis集群撑得住吗?

2021-03-21 18:40:36 浏览数 (1)

1 前言

一大早有个同事过来问我,今天xxx系统需要增加6个pod。我们当前的Redis是否能够撑得住呢?

2 场景介绍

2.1 Redis和Jedis版本以及重要参数介绍

类型

版本

其他

Redis

4.0.12

三主三从(分布6台虚拟机4c32gb/台)

Jedis

2.9

关键参数详解

2.2 Jedis 关键参数详解

首先我们先介绍几个关键的Jedis参数,方便我们后续的资源评估。

参数

说明

默认值

建议值

maxTotal

资源池中的最大连接数

8

详见《2.2.1 关键参数建议》

maxIdle

资源池允许的最大空闲连接数

8

详见《2.2.1 关键参数建议》

minIdle

资源池确保的最少空闲连接数

0

详见《2.2.1 关键参数建议》

blockWhenExhausted

当资源耗尽的时候,调用者是否等待。只有当值为true时,下面的maxWaitMillis才会生效。

true

建议使用默认值。

maxWaitMillis

当资源池连接用尽后,调用者的最大等待时间(单位为毫秒)。

-1(表示永不超时)

不建议使用默认值。

testOnBorrow

向资源池借用连接时是否做连接有效性检测(ping)。检测到的无效连接将会被移除。

false

业务量很大时候建议设置为false,减少一次ping的开销。

testOnReturn

向资源池归还连接时是否做连接有效性检测(ping)。检测到无效连接将会被移除。

false

业务量很大时候建议设置为false,减少一次ping的开销。

jmxEnabled

是否开启JMX监控

true

建议开启,请注意应用本身也需要开启。

2.2.1 关键参数建议

maxTotal(资源池中的最大连接数),该参数主要从如下四点进行考虑:

  1. 业务希望Redis能达到的并发数;
  2. 客户端执行的时间;
  3. Redis资源,例如Redis cluster(三主三从)pod数 *maxTotal < 3 * 单个Redis 分片的最大连接数(默认是10000),也就是要小于30000,正常情况我们还会为改参数乘于一个预留系数 0.8 ,所以公式为: pod数 *maxTotal < 3 * 10000 * 0.8 < 24000;
  4. 资源开销,例如虽然希望控制空闲连接,但又不希望因为连接池中频繁地释放和创建连接造成不必要的开销。

举个简单的例子来计算,比如一个命令的时间(borrow|return resource Jedis执行命令 网络开销的时间)为1ms,那么一个连接的QPS计算公式为:1s/1ms=1000。如果业务希望我们集群的QPS能达到100w,有10个应用pod, 那计算公式为1000000/1000/10=100。那么maxTotal配置为100。

当然这个值只是一个理论值,我们在预设这个值的时候,需要预留一些资源,所以这个实际值就要比理论值设置大一点,但是这个值不是越大越好,一方面连接太多会占用客户端和服务端资源,另一方面对于Redis这种高QPS的服务器,如果出现大命令的阻塞,即使设置再大的资源池也无济于事。

maxIdle与minIdle

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

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

minIdle为资源池确保的最少空闲连接数,这个参数很重要。我们经常会在Jedis pool预热这一块用到这个参数。由于一些原因(如超时时间设置较小等),项目在启动成功后可能会出现超时。JedisPool定义最大资源数、最小空闲资源数时,不会在连接池中创建Jedis连接。初次使用时,池中没有资源使用则会先new Jedis,使用后再放入资源池,该过程会有一定的时间开销,所以建议在定义JedisPool后,以最小空闲数量为基准对JedisPool进行预热。

综上,您可以根据实际总QPS和调用Redis的客户端规模整体评估每个节点所使用的连接池大小。

使用监控获取合理值

在实际环境中,比较可靠的方法是通过监控来尝试获取参数的最佳值。可以考虑通过JMX等方式实现监控,从而找到合理值。

2.3 最佳实践评估

参数

参数值

maxTotal

500

maxIdle

500

minIdle

100

pod

20

如上列表为当前pod数量和关键参数配置,从普罗米修斯监控看,该集群内存使用率均整体资源达到30%左右,资源很空闲,所以我们只需要评估连接数是否足够,那就是500 * 26 是否小于 10000 * 3 * 80%,答案很明显,最大连接数符合要求。

3.其他

以上是一个最大连接数评估的一个过程,那资源不足的时候,程序会有哪些问题呢?下面将介绍两种资源不足的情况

A. blockWhenExhausted 为false,Jedis不会等待资源释放:

代码语言:txt复制
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
…
Caused by: java.util.NoSuchElementException: Pool exhausted
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:464)

B.超时:

代码语言:txt复制
redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resource from the pool
…
Caused by: java.util.NoSuchElementException: Timeout waiting for idle object
at org.apache.commons.pool2.impl.GenericObjectPool.borrowObject(GenericObjectPool.java:449)

4 总结

当遇到资源评估的时候,稳住。查看下相关的理论,再结合实际一对比,其实很多问题就解决了。本文其实有一些定理总结,具体如下:

  1. 应用端最大连接数估算公式: maxTotal * pod数 < max_clients(redis cluster 单个分片的max_clients)* 分片数 * 80% (预留百分比);
  2. 应用端最大空闲连接数设置: 0 < maxIdle <= maxTotal;
  3. 比较常见的配置推荐: maxIdle == maxTotal == Tomcat 线程数,此配置均满足以上公式。

5 参考文献

1. https://github.com/redis/jedis/blob/master/src/main/java/redis/clients/jedis/JedisPoolConfig.java

2. https://www.alibabacloud.com/help/doc-detail/145231.htm?spm=a2c63.p38356.b99.30.70386695h1A3OP

3. https://www.alibabacloud.com/help/doc-detail/98726.html?spm=a2c5t.11065259.1996646101.searchclickresult.3b337b7aaLFVkZ

感谢您的支持!有空帮忙点个赞!

0 人点赞