文章转载自:http://www./index/archives/427.html#codesyntax_1 1、背景1.1 Redis简介官方网站:http:///,Redis是REmote DIctionary Server的缩写。 Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。它跟 memcached 类似,不过数据可以持久化,而且支持的数据类型很丰富。它在保持键值数据库简单快捷特点的同时,又吸收了部分关系数据库的优点。从而使它的位置处于关系数据库和键值数据库之间。Redis不仅能保存Strings类型的数据,还能保存Lists类型(有序)和Sets类型(无序)的数据,而且还能完成排序(SORT)等高级功能,在实现INCR,SETNX等功能的时候,保证了其操作的原子性,除此以外,还支持主从复制等功能。Redis可以被看成是一个数据结构服务器。 Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。 1.2 瓶颈当前卡布西游项目,数据存储采用MySQL,主游戏库共分为20个库,分布在5台机器上,每个库数据量约为10G,各机器均采用RAID5加速磁盘访问;当同时在线人数达到5W时,DB磁盘IO压力很大,导致游戏卡,在线人数再上不去了。而Redis数据读写都是直接操作内存,可有效解决这一瓶颈。 1.3 解决方案概述将部分数据压缩导入到redis后,总数据量约15G(转换成redis数据类型数据量),一主一从模型,共两组。一台机器内存32G,开20个实例,共40个实例;预估每个实例最多存储2G数据(现在没这么多)。多实例方便做持久化。 主库不做AOF,也不做快照,只在每晚12点计划任务做一次快照并转移到异地。从库开启AOF并1秒落地。 主库每5分钟插入一个时间点(crontab实现),方便从库AOF记录时间点,用于定点还原。 2、安装配置2.1 硬件配置Dell R410 32G内存;两个CPU,每个CPU 4个核心;300G硬盘 2.2 安装a)安装TCMalloc库 Source Code
wget http://download.savannah./releases/libunwind/libunwind-0.99-alpha.tar.gz b)安装google-perftools: Source Code wget http://google-perftools./files/google-perftools-1.8.2.tar.gz tar zxf google-perftools-1.7.tar.gz cd google-perftools-1.7/ ./configure make make install echo "/usr/local/lib" > /etc/ld.so.conf.d/usr_local_lib.conf /sbin/ldconfig c)安装redis Source Code wget http://redis./files/redis-2.2.14.tar.gz tar xzvf redis-2.2.14.tar.gz cd redis-2.2.14 make USE_TCMALLOC=yes //make之后会在 src目录下产生redis-server redis-cli redis-benchmark redis-check-dump 将其拷贝到/usr/local/redis/bin目录下,将配置文件redis.conf拷贝到/usr/local/redis/etc目录 //统一建立目录,方便管理 mkdir -p /usr/local/redis/bin mkdir -p /usr/local/redis/etc mkdir -p /usr/local/redis/var mkdir -p /data/redis-data
检查tcmalloc是否生效
出现以下信息说明生效 redis-ser 13768 root mem REG 8,5 1616491 788696 /usr/local/lib/libtcmalloc.so.0.1.0 //装完后,可能libtcmalloc没有注册,没有上面信息,在mysqld_safe文件里加一条: export LD_PRELOAD=/usr/local/lib/libtcmalloc.so`` //再重启mysql(线上操作谨慎!!!)(使用tmalloc,内存分配效率更高) 2.3 配置//当前规划一共开40个实例,每台机器20个实例,下面以实例01为例: //配置文件名: redis6001.conf ~ redis6040.conf Source Code daemonize yes pidfile /var/run/redis6001.pid port 6001 timeout 300 loglevel debug logfile /usr/local/redis/var/debug6001.log syslog-enabled yes databases 16 rdbcompression yes dbfilename redis6001.rdb dir /data/redis-data/redis6001 slave-serve-stale-data yes requirepass My#redis appendonly no no-appendfsync-on-rewrite no vm-enabled no 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 3、主从同步备份及相关脚本3.1 主从同步目的目标主从的主要目的:数据持久化,灾难恢复,冗余。主库不落地,减少消耗。 3.2 主从配置从库安装配置同主库一致,主库无需任何改动(允许从库访问),从库需增加两个地方配置:slaveof + AOF slaveof 192.168.3.180 6301 masterauth My#redis appendonly yes appendfilename appendonly01.aof appendfsync everysec //配置文件名: slave6001.conf ~ slave6040.conf Source Code 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 3.3 备份备份策略:主库每晚12点串行给每个实例做一次快照(bgsave);从库每晚12点串行对AOF文件打包备份(tar),打包备份后做一次AOF文件压缩(bgrewriteaof)。每天的数据起始点是前一天晚上rewriteaof后的数据。 主库每晚12点串行给每个实例做一次快照(bgsave)。主库备份脚本(redis_bgsave.sh)
REDISPASSWORD=My#redis
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 :对单个实例)
exit fi
REDISNAME=$1
LOGFILE=/data/logs/redisbak/redis_allbak_${CURDATE}.log
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
fi sleep 5 /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgrewriteaof sleep 5
find /data/backup/redis/ -mtime +7 | xargs rm -rf echo “Backup $REDISNAME ok at $CURTIME !” >> $LOGFILE 从库对所有实例备份(/data/sh/redis_allbak.sh)
do
done 4、操作注意事项
5、灾难恢复5.1 主库故障,快速恢复到最近状态描述:主库挂了(redis程序挂了/机器宕机了),从库正常,恢复到主库挂掉的时间点:去从库手动做一次快照,拷贝快照到主库相应目录,启动,OK。 在从库做一次快照,转移快照文件到其他目录,将快照文件目录拷贝到主库相应目录,启动主库,OK! ( /data/sh/redis_bgsave_cp.sh )
REDISPASSWORD=My#redis
do /usr/local/redis/bin/redis-cli -h 127.0.0.1 -p $PORT -a $REDISPASSWORD bgsave sleep 5 done sleep 15
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
done 在主库将原来数据目录重命名。 从从库拷贝快照文件到主库。 启动主库。 5.2 恢复到当天12点状态注意备份数据(当前状态AOF+正常退出快照)! 停止redis。 解压AOF(/data/sh/redis_untar.sh)
DAY=20111102 SDIR=/data/backup/redis/20111102_00/ cd $SDIR
do tar -zxf slave${PORT}$DAY*.tar.gz sleep 2 done 切割AOF(/data/sh/redis_sed.sh)
DDIR=/data/redis_recovery/ TAG=”TAG111101_1200″
do SDIR=/data/backup/redis/20111102_00/ SAOF=${SDIR}/slave${PORT}.aof
num=$[$line + 3] mkdir -p ${DDIR}/slave${PORT}/ sed “${num},\$d” $SAOF > ${DDIR}/slave${PORT}/slave${PORT}.aof done 将原来数据目录重命名。 将切割出来的AOF目录重命名为配置文件的数据目录。(注释主从同步配置项)。 启动从库。 做快照,拷贝到主库,启动主库(同5.1)。 5.3 恢复到两天或几天前12点状态从库每晚备份要备份AOF未bgrewriteaof之前的数据,可根据当天晚上12点备份,没有bfrewriteaof之前的AOF文件来进行恢复,方法同5.2。 6、监控6.1 Nagios监控
used_memory_human:1.49G
db0:keys=2079581,expires=0 //监控进程数(每台机器redis实例数) define service{
} //监控主从同步状态(获取从库master_link_status与keys的值) //status=down直接严重警告,keys相差10警告,keys相差100严重警告 define service{
} //监控实例内存使用大小,1.8G警告,2G严重警告 define service{
} 7、资料7.1 参考资料//Redis入门手册(zh_v1.0).pdf http://www./cn/articles/tq-why-choose-redis // 为什么使用 Redis及其产品定位 http://www./cn/articles/tq-redis-memory-usage-optimization-storage // Redis内存使用优化与存储 http://www./cn/articles/tq-redis-copy-build-scalable-cluster // Redis复制与可扩展集群搭建 http://blog./index.php/2011/08/802 // Redis中7种集合类型应用场景 7.2 版本最新稳定版: wget http://redis./files/redis-2.2.14.tar.gz // 2011.10.1 wget http://redis./files/redis-2.4.2.tar.gz // 2011.11.15 wget http://redis./files/redis-2.4.10.tar.gz // 2012.04.16 8、卡布西游Redis分布8.1 服务器分布服务器分布: 实例名: 端口: … … … 8.2 mysql转redis规则1.Key命名规则 Key采用字母+数字的形式 避免多个应用使用同一个key的时候互相覆盖,主项目中的key采用GJ#[UID] 例:GJ12345678 2.字段命名规则 主项目中的key内包含多个字段 代表多个应用 目前给每个应用预留的字段取值范围为100(实际使用中字段不应该超过10个左右不然使用哈希的意义不大了)。 当前的预留字段划分: 100~199为成就相关(当前使用150、151 对应MySQL的achieve_user表的history与current字段) 200~299为妖怪相关(当前使用200 对应MySQL的spirit_store表 实际应用时应该会再多2个字段 对应MySQL的spiritmaster与spirit表) 3.实例划分规则 预计将划分40个实例 玩家数据根据玩家的UID取模来分配到不同的实例中(是否再分库未确定) 4.其他使用Redis划分规则 目前庄园也有部分数据使用redis 不过数据是放在一个单独的redis实例中(119.147.164.24) 根据应用不同使用不同的库和key值 Key命名规则为[应用名]-[UID] 例: GrowTimes-12345678 / StolenList-12345678 9、相关测试数据//测试数据跟存储的数据以及机器硬件配置等有关,具体环境可能不太一样,仅做参考。 9.1 启动关闭启动:1.6G AOF文件,132M RDB,启动时间107s,产生debug.log 128M,使用内存1.71G。 2G数据,启动约2分钟,主从同步约2分钟(内网)。 关闭:shutdown时间很短,一般1~2s,shutdown之前必须做save,save时间跟数据量有关,一般几秒。 9.2 数据量大小简单set(set a 1),3万条约1M AOF,300K RDB;12万条约4M AOF,1M RDB。 set一条记录,AOF会记录些什么:
9.3 备份打包纯文本AOF:
当前线上使用redis,数据导入是二进制流格式(AOF文件为数据文件,非文本文件),而且导入前已经过一次压缩,所以压缩比例很低。 9.4 其他测试实例配置文件中的数据目录不存在,实例无法启动。 AOF边写边打包(tar),不会造成数据损坏,tar只是读文件。 Redis运行过程中删除数据目录,不能bgsave,不能写AOF,从库能同步;从建目录也不能bgsave,不能写AOF。 Bgsave是放后台去执行的,所以bgsave;shutdown连写在一起会出问题,bgsave还未执行完就已经shutdown了。改用save。 主库实例重启后,从库会重新”全同步”一次,保存数据与主库一致。 网络闪断不会造成主从数据丢失,网络恢复后可以续传。 A实例快照文件,放B实例数据目录启动(文件名改成B实例数据文件),OK! 执行rewriteaof/ bgrewriteaof后,reidis根据内存数据,重新建立AOF,AOF重新排列顺序。 10、客户端连接redis10.1 PHP安装phpredis: phpredis软件包地址(试了N个版本 只有这1个能在我们的定制系统环境装上 蛋疼) http://ftp./pub/NetBSD/packages/distfiles/php-redis/nicolasff-phpredis-2.1.3-0-g43bc590.tar.gz cd /dist/src tar xzf ../dist/nicolasff-phpredis-2.1.3-0-g43bc590.tar.gz cd nicolasff-phpredis-43bc590 /usr/local/php/bin/phpize
./configure –with-php-config=/usr/local/php/bin/php-config make && make install 配置php.ini vi /usr/local/php/lib/php.ini 加入: extension = “redis.so” 重启 fastcgi 生效 /root/fastcgi_restart # php -m //查看是否有redis,检查是否安装成功。 Redis扩展测试 测试代码: < ?php$redis = new Redis();$redis - >connect(’127.0.0.1′,6379);$redis->set(‘test’,'hello world!’);echo $redis->get(‘test’); ?> 返回 hello world !表示成功
10.2 C++
这个是官方的库,里面有个例子 跑这个,带参数 ./hiredis-test 例子应该是test.c |
|
来自: CedarRapids > 《待分类1》