Redis 连接失败问题排查和解决
当你的应用服务在连接 Redis 时出现了拒绝连接的场景,首先你可以根据调整 Redis 实例参数 maxclients 的配置。maxclients 代表着最大同时连接的客户端个数,Proxy 集群实例不支持该参数,取值范围 1,000~50,000,默认值:10,000,可以调整的再大一些。
客户端拒接连接问题
如果你使用的是集群模式,而使用客户端连接进行连接 Cluster 集群时,连接失败出现 Read timed out 或 Could not get a resource from the pool。
分析排查方向
排查是否使用了 keys 命令,keys 命令会消耗大量资源,造成 Redis 阻塞。建议使用 scan 命令替代,且避免频繁执行。
当 Redis 数据持久化即 AOF 时,会触发偶现的磁盘性能问题,导致连接异常,可更换 Redis 所在磁盘升级为 ssd 盘,磁盘性能更高,或若不需要持久化可关闭 AOF。
unexpected end of stream 错误,导致业务异常
分析排查方向
Jedis 连接池调优,建议参考 Jedis 参数配置建议进行配置连接池参数。
Jedis 连接池优势
Lettuce 客户端及 Jedis 客户端比较如下:
Lettuce:
Lettuce 客户端没有连接保活探测,错误连接存在连接池中会造成请求超时报错。
Lettuce 客户端未实现 testOnBorrow 等连接池检测方法,无法在使用连接之前进行连接校验。
Jedis:
Jedis 客户端实现了 testOnBorrow、testWhileIdle、testOnReturn 等连接池校验配置。
开启 testOnBorrow 在每次借用连接前都会进行连接校验,可靠性最高,但是会影响性能(每次 Redis 请求前会进行探测)。
testWhileIdle 可以在连接空闲时进行连接检测,合理配置阈值可以及时剔除连接池中的异常连接,防止使用异常连接造成业务报错。
在空闲连接检测之前,连接出现问题,可能会造成使用该连接的业务报错,此处可以通过参数控制检测间隔(timeBetweenEvictionRunsMillis)。
因此,Jedis 客户端在面对连接异常,网络抖动等场景下的异常处理和检测能力明显强于 Lettuce,可靠性更强。
maxTotal(最大连接)
根据 Web 容器的 Http 线程数来进行配置,估算单个 Http 请求中可能会并行进行的 Redis 调用次数,例如:Tomcat 中的 Connector 内的 maxConnections 配置为 150,每个 Http 请求可能会并行执行 2 个 Redis 请求,在此之上进行部分预留,则建议配置至少为:150 x 2 + 100= 400。
限制条件
单个 Redis 实例的最大连接数。maxTotal 和客户端节点数(CCE 容器或业务 VM 数量)数值的乘积要小于单个 Redis 实例的最大连接数。
例如:Redis 主备实例配置 maxClients 为 10000,单个客户端 maxTotal 配置为 500,则最大客户端节点数量为 20 个。
maxIdle(最大空闲连接)
建议配置为 maxTotal 一致。
minIdle(最小空闲连接)
一般来说建议配置为 maxTotal 的几分之一。
例如,此处常规配置建议为:100。对于性能敏感的场景,防止经常连接数量抖动造成影响,也可以配置为与 maxIdle 一致,例如:400。
maxWaitMillis(最大获取连接等待时间)
单位:毫秒
获取连接时最大的连接池等待时间,根据单次业务最长容忍的失败时间减去执行命令的超时时间得到建议值。
例如:Http 最大容忍超时时间为 15s,Redis 请求的 timeout 设置为 10s,则此处可以配置为 5s。
timeout(命令执行超时时间)
单位:毫秒
单次执行 Redis 命令最大可容忍的超时时间,根据业务程序的逻辑进行选择,一般来说处于对网络容错等考虑至少建议配置为 210ms 以上。特殊的探测逻辑或者环境异常检测等,可以适当调整达到秒级。
minEvictableIdleTimeMillis(空闲连接逐出时间)
大于该值的空闲连接一直未被使用则会被释放,单位:毫秒
如果希望系统不会经常对连接进行断链重建,此处可以配置一个较大值(xx 分钟),或者此处配置为-1,并且搭配空闲连接检测进行定期检测。
timeBetweenEvictionRunsMillis(空闲连接探测时间间隔)
单位:毫秒
根据系统的空闲连接数量进行估算,例如,系统的空闲连接探测时间配置为 30s,则代表每隔 30s 会对连接进行探测,如果 30s 内发生异常的连接,经过探测后会进行连接排除。
根据连接数的多少进行配置,如果连接数太大,配置时间太短,会造成请求资源浪费。对于几百级别的连接,常规来说建议配置为 30s,可以根据系统需要进行动态调整。
testOnBorrow(进行获取连接检测)
向资源池借用连接时是否做连接有效性检测(ping),检测到的无效连接将会被移除。
对于业务连接极端敏感的,并且性能可以接受的情况下,可以配置为 True,一般来说建议配置为 False,启用连接空闲检测。
testWhileIdle
是否在空闲资源监测时通过 ping 命令监测连接有效性,无效连接将被销毁。一般设置为 True。
testOnReturn
向资源池归还连接时是否做连接有效性检测(ping),检测到无效连接将会被移除。一般设置为 False。
maxAttempts
在 JedisCluster 模式下,您可以配置 maxAttempts 参数来定义失败时的重试次数。建议配置 3-5 之间,默认配置为 5。
根据业务接口最大超时时间和单次请求的 timeout 综合配置,最大配置不建议超过 10,否则会造成单次请求处理时间过长,接口请求阻塞。
排查是否大 key 较多,建议根据优化大 key 排查优化。
string 类型控制在 10KB 以内,hash、list、set、zset 元素尽量不超过 5000。
Key 的命名前缀为业务缩写,禁止包含特殊字符(比如空格、换行、单双引号以及其他转义字符)。
Redis 事务功能较弱,不建议过多使用。
短连接性能差,推荐使用带有连接池的客户端。
如果只是用于数据缓存,容忍数据丢失,建议关闭持久化。
Key/热 Key 的优化方法
什么是大 Key,大 Key 可以分为两种情况?
Key 的 Value 较大,例如一个 String 类型的 Key 大小达到 10MB,或者一个集合类型(Hash,List,Set 等)的元素总大小达到了 100MB。一般我们定义单个 String 类型的 Key 大小达到 10KB,或者集合类型的 Key 总大小达到 50MB,则定义其为大 Key。
Key 的元素较多,例如一个 Hash 类型的 Key,其元素数量达到了 10000。一般我们定义集合类型的 Key 中元素超过 5000 个,则认为其为大 Key。
热 Key
通常以一个 Key 被操作的频率和占用的资源来判定其是否为热 Key,例如:
某个集群实例一个分片每秒处理 10000 次请求,其中有 3000 次都是操作同一个 Key。
某个集群实例一个分片的总带宽使用(入带宽+出带宽)为 100Mbits/s,其中 80Mbits 是由于对某个 Hash 类型的 Key 执行 HGETALL 所占用。
进行大 Key 拆分,分为以下几种场景:
该对象为 String 类型的大 Key:可以尝试将对象分拆成几个 Key-Value, 使用 MGET 或者多个 GET 组成的 pipeline 获取值,分拆单次操作的压力,对于集群来说可以将操作压力平摊到多个分片上,降低对单个分片的影响。
该对象为集合类型的大 Key,并且需要整存整取:在设计上严格禁止这种场景的出现,因为无法拆分。有效的方法是将该大 Key 从 Redis 去除,单独放到其余存储介质上。
该对象为集合类型的大 Key,每次只需操作部分元素:将集合类型中的元素分拆。以 Hash 类型为例,可以在客户端定义一个分拆 Key 的数量 N,每次对 HGET 和 HSET 操作的 field 计算哈希值并取模 N,确定该 field 落在哪个 Key 上,实现上类似于 Redis Cluster 的计算 slot 的算法。
无法拆分的大 Key 建议使用此方法,将不适用 Redis 能力的数据存至其它存储介质,如 SFS 或者其余 NoSQL 数据库,并在 Redis 中删除该大 Key。
注意:
禁止使用 DEL 直接删除大 Key,可能会造成 Redis 阻塞,甚至主备倒换。高版本 4.0 以上,可以使用 unlink。
合理设置过期时间并对过期数据定期清理。
合理设置过期时间,避免历史数据在 Redis 中大量堆积。由于 Redis 的惰性删除策略,过期数据可能并不能及时清理,如果发现 Redis 过期 Key 清理较慢,可以手动使用 scan 进行扫描删除。
热 Key,如何处理控制
使用读写分离。
如果热 Key 主要是读流量较大,则可以实现读写分离架构,降低对主节点的影响。还可以增加多个副本以满足读需求,但是备机较多也有相应的影响,即所有的备节点都直接和主节点保持同步,这样能保证备节点之间相互独立,且复制延迟较小。缺点是在备节点数量较多的情况下,主节点的 CPU 和网络负载会较高。
使用客户端缓存/本地缓存。
该方案需要提前了解业务的热点 Key 有哪些,设计客户端/本地和远端 Redis 的两级缓存架构,热点数据优先从本地缓存获取,写入时同时更新,这样能够分担热点数据的大部分读压力。缺点是需要修改客户端架构和代码,改造成本较高。
设计熔断/降级机制。
热 Key 极易造成缓存击穿,高峰期请求都直接透传到后端数据库上,从而导致业务雪崩。因此热 Key 的优化一定需要设计系统的熔断/降级机制,在发生击穿的场景下进行限流和服务降级,保护系统的可用性。
作者:洛神灬殇
链接:https://juejin.cn/post/7199643079284179003
来源:稀土掘金
评论