1 Redis 内存过大可能导致的问题
Redis的高性能、稳定性是不用怀疑的,但当redis塞进的数据过多,内存过大,可能会出现如下问题。
1.1 主库宕机后重建从库时间长
在sentinel或者Cluster架构下,当主库宕机时,会发生主从切换的动作。从该集群剩余从库中选出一个从库并将其升级为主库,该从库升级为主库后再将剩余从库挂载至其下成为其从库,最终恢复整个主从集群结构。
这里有两个阶段:
- 主库切换
- 从库的重新挂载
Redis现在不能像mysql、mongodb那样基于同步的点位在主库发生变化后从新的主库继续同步数据。 Redis集群中一旦从库换主,就需要从库清空然后从新主库完整同步一份数据再进行续传。
整个从库重做流程是这样的:
- 主库bgsave自身数据到磁盘
- 主库发送rdb文件到从库
- 从库开始加载
- 加载完毕开始续传,同时开始提供服务
因此Redis的内存体积越大以上每一个步骤的时间都会被拉长。
1.2 扩容问题
很多时候会出现流量的突发性增长,通常在找到原因之前我们的应急做法就是扩容了。 当Redis 内存较大时,扩容从库的时间也会增加。
1.3 持久化操作阻塞主线程的长
Redis是单线程的内存数据库,在redis需要执行耗时的操作时,会fork一个新进程来做,比如bgsave,bgrewriteaof。
Fork新进程时,虽然可共享的数据内容不需要复制,但会复制之前进程空间的内存页表,这个复制是主线程来做的,会阻塞所有的读写操作,并且随着内存使用量越大耗时越长。
例如:
内存20G的redis,bgsave复制内存页表耗时约为750ms,redis主线程也会因为它阻塞750ms。
2 解决Redis内存过大的方法
为了规避Redis 内存过大带来的问题,一般建议设置8G,当然也需要结合业务的实际情况进行调整。
在单实例内存有限的情况下,可以通过如下方法来减少内存的使用。
2.1 设置过期时间
对具有时效性的key设置过期时间,通过redis自身的过期key清理策略来降低过期key对于内存的占用,同时也能够减少业务的麻烦,不需要定期清理了。
2.2 及时清理无用数据
例如一个redis承载了3个业务的数据,一段时间后有2个业务下线了,那你就把这两个业务的相关数据清理掉。
2.3 尽量对数据进行压缩
例如一些长文本形式的数据,压缩能够大幅度降低内存占用。
2.4 关注内存增长并定位大容量key
redis必须关注内存,这里可以分析redis实例中哪些key比较大从而帮助业务快速定位异常key(非预期增长的key,往往是问题之源)。