常见问题及建议
连接泄露
有些客户端应用没有使用连接池,redis连接用完后没有及时释放,导致服务侧的存活连接越来越多;
建议客户端使用连接池,或者在服务侧配置最大空闲存活时间,由服务侧主动断开(该配置默认关闭);
热key导致单点打爆
应用中最热路径(比如点击量最大页面)上的key访问,在大促等活动时可能会产生10倍以上的访问流量,那么对应的redis节点可能出现
cpu、带宽等耗尽,导致业务不可用;
建议客户进行单节点的cpu、带宽监控,及时发现负载不均衡性;并使用本地二级缓存或者多副本存储等方式进行优化;
控制台上“缓存分析”,可以帮助发现热key;
大key导致单点内存耗尽
对于使用list、set、zset(sortedset)、hash,需要从架构、用户量和访问量等分析,是否会出现无限制插入; 监控单节点的容量并配置告警,以发现容量不均衡;
控制台上“节点管理”进行key个数、容量分析,可以判断大key是否存在;
控制台上“缓存分析”,可以帮助发现各种数据类型的大key;
过大的pipeline
可以使用pipeline提升redis访问性能,proxy集群在proxy节点上进行pipeline支持和后端redis的请求分发和响应排序聚合,过大的
pipeline时,单个耗时请求会影响较多请求,proxy上也会占用更多的内存,默认支持最大pipeline为1024;如确认有需求,也可以配 置提升该阈值
Redis缓存在业务系统会遇到的问题
缓存雪崩:
缓存雪崩是指在我们设置缓存时采用了相同的过期时间,导致缓存在某一时刻同时失效, 请求全部转发到DB,DB瞬时压力过重雪崩。
缓存穿透
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时被动写的,并且出于容错 考虑,如果从存储层查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要 到存储层去查询,失去了缓存的意义。在流量大时,可能DB就挂掉了,要是有人利用不存在 的key频繁攻击我们的应用,这就是漏洞
缓存击穿
对于一些设置了过期时间的key,如果这些key可能会在某些时间点被超高并发地访问,是 一种非常“热点”的数据。这个时候,需要考虑缓存被“击穿”的问题,这个和缓存雪崩的 区别在于这里针对某一key缓存,前者则是很多key。
如何使用好Redis缓存
冷热数据区分
虽然 Redis支持持久化,但将所有数据存储在 Redis 中,成本非常昂贵。建议将热数据的数据加载到 Redis 中。低频数
据可存储在 Mysql、 ElasticSearch中。
业务数据分离
不要将不相关的数据业务都放到一个 Redis中。一方面避免业务相互影响,另一方面避免单实例膨胀,并能在故障时降
低影响面,快速恢复。
消息大小限制
由于 Redis 是单线程服务,消息过大会阻塞并拖慢其他操作。保持消息内容在 1KB 以下是个好的习惯。消息过大还会
引起网络带宽的高占用,持久化到磁盘时的 IO 问题。
连接数限制
连接的频繁创建和销毁,会浪费大量的系统资源,极限情况会造成宿主机宕机。请确保使用了正确的 Redis 客户端连接
池配置。
缓存 Key 设置失效时间
作为缓存使用的 Key,必须要设置失效时间。失效时间并不是越长越好,请根据业务性质进行设置。
Redis缓存操作限制
严禁使用 Keys
Keys 命令效率极低,属于 O(N)操作,会阻塞其他正常命令,在 cluster 上,会是灾难性的操作。
严禁使用 Flush
flush 命令会清空所有数据,属于高危操作。
严禁作为消息队列使用
如没有非常特殊的需求,严禁将 Redis 当作消息队列使用。Redis 当作消息队列使用,会有容量、网络、效率、功能方面的多种问题。如需要消息队列,可使用高吞吐的 Kafka 或者高可靠的 RocketMQ。
严禁不设置范围的批量操作
Redis 那么快,慢查询除了网络延迟,就属于这些批量操作函数。大多数线上问题都是由于这些函数引起。
Redis开发使用规范-强制
•所有的key需设置过期时间。
注意过期时间进行打散,防止同一时间过期大量的key , key过期会占用主线程,如果同一时间过期key太多,会短时间内阻塞用户业务
•禁止使用keys、flushall、hgetall等命令,执行O(N)时间复杂度命令,需要注意N的大小。
•禁止使用select功能来在单redis实例做多db区分。 生产系统中需要开启redis密码保护机制。
•禁止开发人员私自连到线上Redis服务。
•设计上避免引入大key和热key,防止出现单节点瓶颈。
•对于已有大key和热Key处理,建议:
- 进行本地缓存,且为了防止本级缓存穿透到Redis造成雪崩,应采用定时异步进行刷新本地缓存的方式。
- 大key上不执行复杂命令,如:O(N) ,O(log(N)+M),O(M*log(N))命令,当N或M较大时。
Redis开发使用规范-建议
• string类型控制在10KB以内,hash、list、set、zset元素尽量不超过5000。
• 使用批量操作提高效率(带m的如mset,mget,hmset,hmget)。
• key的命名前缀为业务缩写,禁止包含特殊字符(比如空格、换行、单双引号以及其他转义字符)。 • Redis事务功能较弱,不建议过多使用。
• 短连接性能差,推荐使用带有连接池的客户端。
• 如果只是用于数据缓存,容忍数据丢失,建议关闭持久化。
Redis大key热Key处理
大Key热Key的风险:
读写大key会导致超时严重,甚至阻塞服务。 如果删除大key,DEL命令可能阻塞Redis进程数十秒,使得其他请求阻塞,对应用程序和Redis集群可用性造成 严重的影响。
建议每个key不要超过M级别。 单分片的处理能力是有限的,只能做到分片横向扩展,所以系统需要避免由于热key引发的性能问题 业务在使用Redis过程中应当避免大key热key的出现,拖慢整个系统的响应时间
使用scan替代keys *
在key数量较少的情况下,我们可以偷懒直接使用keys *来快速查看模式匹配的key列表,但是一旦key数量上升,或 者在高并发的环境下,keys *会带来整个系统的阻塞。因为keys命令时间复杂度是:
Time complexity:O(N) with N being the number of keys in the database, under the assumption that
the key names in the database and the given pattern have limited length. 直接跟database中key数量相关的。替代方案是使用scan命令,首先看看scan的时间复杂度:
Time complexity:O(1) for every call. O(N) for a complete iteration, including enough command calls
for the cursor to return back to 0. N is the number of elements inside the collection. 虽然scan不能一次性返回所有匹配的key,但是scan提供cursor机制来遍历整个database,最重要的是每次scan操 作的时间复杂度是O(1)的,因此只需要多次scan即可得到所有匹配的key。类似的命令还有sscan,hscan,zscan等分 别用于增量迭代set,hash,sorted set等集合元素。
数据淘汰机制
Redis提供了如下数据淘汰策略:
• volatile-lru:根据LRU算法删除设置了过期时间的键值。
• allkeys-lru:根据LRU算法删除任一键值。
• volatile-random:删除设置了过期时间的随机键值。
• allkeys-random:删除一个随机键值。
• volatile-ttl:删除即将过期的键值,即TTL值最小的键值。
• noeviction:不删除任何键值,只是返回一个写错误。
• volatile-lfu: 根据LFU算法删除设置了过期时间的键值。
• allkeys-lfu: 根据LFU算法删除任一键值。
最好为Redis指定一种有效的数据淘汰策略以配合maxmemory设置,避免在内存使用满后发生写入失败的情况。 一般来说,推荐使用的策略是volatile-lru,并辨识Redis中保存的数据的重要性。对于那些重要的,绝对不能丢弃的 数据(如配置类数据等),应不设置有效期,这样Redis就永远不会淘汰这些数据。对于那些相对不是那么重要的, 并且能够热加载的数据(比如缓存最近登录的用户信息,当在Redis中找不到时,程序会去DB中读取),可以设置 上有效期,这样在内存不够时Redis就会淘汰这部分数据。
网友评论