公司线上redis主从环境下的持久化策略调整:
描述:
之前线上项目使用redis,部署了redis主从环境。redis的主从复制功能非常强大,一个master可以拥有多个slave,而一个slave又可以拥有多个slave,如此下去,形成了强大的多级服务器集群架构。由于主redis采用了AOF和save快照的持久化,长时间下去,aof文件不断增大,磁盘空间使用率逐渐暴增。
考虑到性能问题,需要对redis持久化做些调整,调整如下:
1)主库不开启AOF持久化,并关闭save快照功能(即注释默认的三个save设置),只在每晚12点定时手动做一次bgsave快照,并将快照文件转移到异地。即主库上不产生appendonly.aof持久化文件,做的快照数据放在.rdb文件里(如dump.rdb,由于是压缩配置(rdbcompression yes表示快照文件要压缩),所以快照文件要比aof文件小),然后将这个快照文件dump.rdb转移到其他的服务器上,防止主服务器宕机造成的损失!
2)从库开启AOF持久化并1秒落地,同样不做快照save。并在每晚12点做一次bgrewriteaof压缩appendonly.aof持久化文件,压缩前先对aof文件进行备份。
--------------------------------------------------------------------------------------------------------------------------------------------
按照这种方法进行redis持久化调整,由于线上redis的主库之前采用了AOF和save快照的持久化,之后将这两种都关闭,从库采用AOF持久化。出现了下面的现象:
就是主库关闭AOF和save快照后,主redis上的appendonly.aof持久化文件在一段时间内还在刷,在增大,这是正常的,由于之前开启的缘故,刷过一段时间,主redis的appendonly.aof持久化文件就不刷了,只有从redis的appendonly.aof持久化文件在刷了
--------------------------------------------------------------------------------------------------------------------------------------------
主从redis部署的主要目的:数据持久化,灾难恢复,冗余。主库不落地,减少消耗。
1)主库不做AOF,不做快照,允许从库访问即可。
2)从库开启AOF,不做save
3)备份策略:
主库每晚12点整给每个实例手动做一次bgsave快照,并将快照文件备份到远程节点上。
从库每晚12点整对AOF文件打包备份(tar),打包备份后做一次AOF文件压缩(bgrewriteaof)。每天的数据起始点是前一天晚上rewriteaof后的数据。
主库服务器脚本:
即主库快照之后,将快照文件转移到异地即从库机器192.168.1.121/135上面。
1 2 3 4 5 6 7 8 9 | [root@192-168-1-132 redis] # cat redis_bgsave.sh #!/bin/bash CURHOUR=` date +%Y%m%d_%H` /usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 bgsave sleep 10 rsync -av /data/redis/dump .rdb root@192.168.1.121: /data/backup/192 .168.1.132-save/$CURHOUR/ rsync -av /data/redis/dump .rdb root@192.168.1.135: /data/backup/192 .168.1.132-save/$CURHOUR/ sleep 10 date >> /data/logs/bgsave .log |
从库服务器脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | [root redis] # cat redis_backup.sh #!/bin/bash CURDATE=` date +%Y%m%d` CURHOUR=` date +%Y%m%d_%H` CURTIME=` date +%Y%m%d_%H%M%S` LOGFILE= /data/logs/redisbak/redis_allbak_ ${CURDATE}.log REDISNAME=appendonly.7000 DDIR= /data/backup/redis/ $CURHOUR mkdir -p ${DDIR} RDIR= /data/redis cd ${RDIR} tar -zcf $DDIR/${REDISNAME}_${CURTIME}. tar .gz appendonly.7000.aof if [ $? != 0 ]; then echo "tar error $REDISNAME.aof" >> $LOGFILE fi sleep 5 /usr/local/bin/redis-cli -h 127.0.0.1 -p 6379 bgrewriteaof sleep 5 ### delete old backup data dir ### #/bin/rm -rf `date -d -30day + "%Y%m%d"` find /data/backup/redis/ -mtime +30 | xargs rm -rf echo "Backup $REDISNAME ok at $CURTIME !" >> $LOGFILE |
[root redis]# crontab -e
59 23 * * * /bin/bash /data/redis/redis_backup.sh >/dev/null 2>&1
[root@cdn redis]# cd /data/backup/redis/20161207_13
[root@cdn 20161207_13]# ls
appendonly.7000_20161207_133131.tar.gz
-------------再看一例----------------------------------------------------------------------------------------------------------------------
公司线上一个项目数据存储采用MySQL,共分为10个库,分布在4台机器上,每个库数据量约为10G,各机器均采用RAID5加速磁盘访问;
当同时在线人数达高峰期(10w),DB磁盘IO压力巨大,导致访问巨慢,,在线人数就很难上不去了。
针对上面描述情况,使用redis后可有效解决这一瓶颈,因为Redis数据读写都是直接操作内。
解决方案:
将部分数据压缩导入到redis后,总数据量约30G(转换成redis数据类型数据量),一主一从模型,共两组。
一台机器内存32G,开10个实例,共20个实例,多实例方便做持久化。
同样适用于上面的redis持久化策略调整方案(思路和上面一致)
主从库配置:
主库:关闭save开展,aof默认不打开,允许从库访问。主库设置了密码访问requirepass My#redis
从库:需增加配置:开启AOF持久化,关闭save快照,设置密码;
从库10个实例的配置文件分别为:slave6001.conf ~ slave6010.conf
slave6001.conf配置内容如下(其他实例拷贝这个,修改端口等其他信息即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | daemonize yes pidfile /var/run/slave6001 .pid port 6001 timeout 300 loglevel debug logfile /usr/local/redis/var/debug6001 .log syslog-enabled yes databases 16 rdbcompression yes dbfilename slave6001.rdb dir /data/redis-data/slave6001 slaveof 192.168.0.139 6001 masterauth My #redis slave-serve-stale-data yes requirepass My #redis appendonly yes appendfilename slave6001.aof appendfsync everysec no-appendfsync-on-rewrite no vm-enabled no vm-swap- file /tmp/redis .swap vm-max-memory 0 vm-page-size 32 vm-pages 134217728 vm-max-threads 4 hash -max-zipmap-entries 512 hash -max-zipmap-value 64 list-max-ziplist-entries 512 list-max-ziplist-value 64 set -max-intset-entries 512 activerehashing yes |
主库每晚12点给每个实例手动做一次bgsave快照。主库备份脚本(redis_bgsave.sh)
1 2 3 4 5 6 7 8 9 | #!/bin/bash #date=`date +%y%m%d_%H%M%S` REDISPASSWORD=My #redis for PORT in ` seq 6001 6010` do /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgsave sleep 10 done date >> /usr/local/redis/var/bgsave .log |
从库每晚12点拷贝每个实例的AOF到其他目录并对其打包,压缩包要有异地备份,之后再压缩AOF(bgrewriteaof)。
从库备份AOF并bgrewriteaof脚本(redis_backup.sh :对单个实例)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #!/bin/sh ## FD:File Dir ## RD:Runing Dir ## 第一个参数为redis实例名 if [ $ # -ne 1 ]; then echo “Usage:$0 redis_name” exit fi CURDATE=` date +%Y%m%d` CURHOUR=` date +%Y%m%d_%H` CURTIME=` date +%Y%m%d_%H%M%S` REDISPASSWORD=My #redis REDISNAME=$1 PORT=` echo $REDISNAME | cut -c6-9` LOGFILE= /data/logs/redisbak/redis_allbak_ ${CURDATE}.log if [ "${REDISNAME}" = "" ]; then echo “redis name Error!” exit 1 else if [ ! -d "/data/redis-data/${REDISNAME}" ]; then echo “redis name Error!” exit 1 fi fi DDIR= /data/backup/redis/ $CURHOUR mkdir -p ${DDIR} RDIR= /data/redis-data/ $REDISNAME cd ${RDIR} tar -zcf $DDIR/${REDISNAME}_${CURTIME}. tar .gz $REDISNAME.aof if [ $? != 0 ]; then echo “ tar error $REDISNAME.aof” >> $LOGFILE #exit 1 fi sleep 5 /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgrewriteaof sleep 5 ### delete old backup data dir ### #/bin/rm -rf `date -d -7day +”%Y%m%d”` find /data/backup/redis/ -mtime +7 | xargs rm -rf echo “Backup $REDISNAME ok at $CURTIME !” >> $LOGFILE |
从库对所有实例备份(/data/sh/redis_allbak.sh)
1 2 3 4 5 6 7 | #!/bin/sh CURDATE=` date +%Y%m%d` LOGFILE= /data/logs/redisbak/redis_allbak_ ${CURDATE}.log for PORT in ` seq 6001 6010` do /data/sh/redis_backup .sh slave${PORT} && echo “slave${PORT} ok ` date +%Y%m%d_%H%M%S`” >> $LOGFILE 2>&1 || echo “slave${PORT} backup error” >> $LOGFILE 2>&1 done |
操作注意事项
1)若主库挂了,不能直接开启主库程序。若直接开启主库程序将会冲掉从库的AOF文件,这样将导致只能恢复到前一天晚上12的备份。
2)程序在跑时,不能重启网络(程序是通过网络接口的端口进行读写的)。网络中断将导致中断期间数据丢失。
3)确定配置文件全部正确才启动(尤其不能有数据文件名相同),否则会冲掉原来的文件,可能造成无法恢复的损失。
灾难恢复
1)主库故障,快速恢复到最近状态描述:主库挂了(redis程序挂了/机器宕机了),从库正常,恢复到主库挂掉的时间点:去从库手动做一次快照,拷贝快照到主库相应目录,启动,OK。
在从库做一次快照,转移快照文件到其他目录,将快照文件目录拷贝到主库相应目录,启动主库,OK!
( /data/sh/redis_bgsave_cp.sh )
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #!/bin/bash REDISPASSWORD=My #redis for PORT in ` seq 6001 6010` do /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgsave sleep 5 done sleep 15 for PORT in ` seq 6001 6010` do SDIR= /data/redis-data/slave ${PORT}/ DDIR= /data/redis_recovery/redis-data/ mkdir -p $DDIR /redis ${PORT}/ cd $SDIR cp -rf slave${PORT}.rdb $DDIR /redis ${PORT} /redis ${PORT}.rdb #sleep 1 done |
在主库将原来数据目录重命名。
从从库拷贝快照文件到主库。
启动主库。
2)恢复到当天12点状态注意备份数据(当前状态AOF+正常退出快照)!
停止redis。
解压AOF(/data/sh/redis_untar.sh)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | #!/bin/bash DAY=20111102 SDIR= /data/backup/redis/20161102_00/ cd $SDIR for PORT in ` seq 6001 6010` do tar -zxf slave${PORT}_$DAY_*. tar .gz sleep 2 done 切割AOF( /data/sh/redis_sed .sh) #!/bin/bash DDIR= /data/redis_recovery/ TAG=”TAG111101_1200″ for PORT in ` seq 6001 6010` do SDIR= /data/backup/redis/20161102_00/ SAOF=${SDIR} /slave ${PORT}.aof line=` sed -n “/$TAG/=” $SAOF` num=$[$line + 3] mkdir -p ${DDIR} /slave ${PORT}/ sed “${num},\$d” $SAOF > ${DDIR} /slave ${PORT} /slave ${PORT}.aof done |
将原来数据目录重命名。
将切割出来的AOF目录重命名为配置文件的数据目录。(注释主从同步配置项)。
启动从库。
做快照,拷贝到主库,启动主库(同上面第1)步)。
3)恢复到两天或几天前12点状态从库每晚备份要备份AOF未bgrewriteaof之前的数据,可根据当天晚上12点备份,没有bfrewriteaof之前的AOF文件来进行恢复,方法同上面的第2)步。
***************当你发现自己的才华撑不起野心时,就请安静下来学习吧***************