一大早有个同事过来问我,今天xxx系统需要增加6个pod。我们当前的Redis是否能够撑得住呢?
类型 | 版本 | 其他 |
---|---|---|
Redis | 4.0.12 | 三主三从(分布6台虚拟机4c32gb/台) |
Jedis | 2.9 |
首先我们先介绍几个关键的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 | 建议开启,请注意应用本身也需要开启。 |
maxTotal(资源池中的最大连接数),该参数主要从如下四点进行考虑:
举个简单的例子来计算,比如一个命令的时间(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等方式实现监控,从而找到合理值。
参数 | 参数值 |
---|---|
maxTotal | 500 |
maxIdle | 500 |
minIdle | 100 |
pod | 20 |
如上列表为当前pod数量和关键参数配置,从普罗米修斯监控看,该集群内存使用率均整体资源达到30%左右,资源很空闲,所以我们只需要评估连接数是否足够,那就是500 * 26 是否小于 10000 * 3 * 80%,答案很明显,最大连接数符合要求。
以上是一个最大连接数评估的一个过程,那资源不足的时候,程序会有哪些问题呢?下面将介绍两种资源不足的情况
A. blockWhenExhausted 为false,Jedis不会等待资源释放:
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.超时:
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)
当遇到资源评估的时候,稳住。查看下相关的理论,再结合实际一对比,其实很多问题就解决了。本文其实有一些定理总结,具体如下:
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
感谢您的支持!有空帮忙点个赞!
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。