当前位置: 首页 > 科技观察

为什么Redis内存不宜过大

时间:2023-03-14 17:48:42 科技观察

这几年的线上业务表明,redis这种内存数据库的高性能和稳定性是毋庸置疑的,但是我们有太多的数据塞进redis和内存太大了。那么一旦出现问题,可能会给我们带来灭顶之灾(我想很多公司都遇到过)下面是我们遇到的一些问题:1主库宕机先看一下主库宕机容灾过程:如图下面,当主库宕机时,我们最常见的容灾策略是“切主”。具体是从集群剩余的从库中选择一个从库升级为主库。从库升级为主库后,将剩余的从库挂载到其下,成为它的从库,最后恢复整个主从库。集群结构。以上就是一个完整的容灾过程,其中开销最大的过程是从库的重挂载,而不是主库的切换。这是因为redis无法像mysql、mongodb那样,在主库发生变化后,根据同步点继续从新的主库同步数据。redis集群中一旦从库变更为master,redis的做法是清除替换主库的从库,然后从新的主库完全同步一份数据,再继续传输。从库的整个redo过程如下:主库bg将自己的数据保存到磁盘。主库将rdb文件发送给从库。从库开始加载,加载完成后恢复,同时开始提供服务。很明显,这个过程中redis的内存体积越大,上面每个步骤的时间都会加长,实际测试数据如下(我们认为我们的机器性能更好):可以看出,当数据达到20G,一个从库的恢复时间缩短了将近20分钟。如果有10个从库,依次恢复需要200分钟。如果此时从库承受大量的读请求,你能承受这么长的恢复时间吗?看到这里你肯定会问:为什么不能同时重做所有的从库呢?这是因为如果所有的从库同时向主库请求rdb文件,主库的网卡会立即跑满,进入无法正常提供服务的状态。这时,主库又死了,只是雪上加霜。当然,我们可以批量恢复从库,比如两两一组,这样所有从库的恢复时间只从200分钟减少到100分钟。这不是五十步和一百步吗?另一个重要的问题在于第四点,在标红的位置,resume可以理解为一个简化的mongodboplog,它是一个固定容量的内存空间,我们称之为“同步缓冲区”。redis主库的写操作会在这个区域存储一份,然后发送给从库。如果上面的1、2、3步耗时过长,很可能同步缓冲区会被重写。这个时候,slave库找不到对应的resume位置怎么办?答案是重做步骤1、2和3!但是因为我们解决不了1、2、3这几个耗时的步骤,从库就会永远进入一个恶性循环:没有停止向主库请求完整的数据,导致主库的网卡受到严重影响图书馆。2扩容问题很多时候流量会突然增加。通常,我们的应急方法是先扩容,再查找原因。根据场景一的表格,一个20G的redis扩容一个从库需要将近20分钟。业务在这个关键时刻能忍20分钟吗?它可能会在扩展完成之前死亡。3、网络不好导致从库重做,最终引发雪崩。这个场景最大的问题就是主库和从库的同步中断了。这个时候很可能从库还在接受写请求。缓冲区很可能被覆盖。这时候从库上次同步的位置已经丢失了。虽然网络恢复后主库没有变化,但是从库必须重做,因为从库的同步位置丢失了,也就是问题1中的1,2,3。4步。如果此时主库内存过大,从库的重做速度会很慢,发送到从库的读请求会受到严重影响。将在相当长的一段时间内受到严重影响。4内存越大,阻塞主线程触发持久化操作的时间就越长。Redis是一个单线程内存数据库。当redis需要执行耗时操作时,它会fork一个新的进程来做,比如bgsave,bgrewriteaof。fork一个新进程时,虽然不需要复制可共享数据内容,但会复制前一个进程空间的内存页表。这个拷贝是由主线程完成的,它会阻塞所有的读写操作,并且随着内存使用量的增加Bigger需要更长的时间。例如:对于20G内存的redis,bgsave复制内存页表需要750ms左右,redis主线程也会因此阻塞750ms。解决方案解决方案当然是尽可能减少内存的使用。一般来说,我们是这样做的:1.为时间敏感的key设置过期时间,使用redis自带的过期key清理策略来减少过期key。对于内存占用,也可以减少业务上的麻烦,也不需要定期清理。2.redis不存储垃圾是废话,但是有没有人和我们分享同样的问题?3、及时清理无用数据。比如一个redis承载了3个业务的数据,如果2个业务在一段时间后下线了,那么你就应该清理这2个业务的相关数据。4尽量压缩数据。内存使用5关注内存增长,定位大容量key无论是DBA还是开发人员,如果使用redis,一定要关注内存。否则,你其实是无能的。这里可以分析redis实例中哪些key比较大,帮助业务快速定位异常的key(意外增长的key往往是问题的根源)6如果pika实在不想这么累,那就迁移业务交给新开源的pika,让大家不用太在意内存,redis内存过大带来的问题都不是问题了。***祈祷上线的5000个redis实例不要出现异常~~~