5.2 Master-Slave复制
5.2.1 概述
- slave可以在配置文件、启动命令行参数、以及redis-cli执行SlaveOf指令来设置自己是奴隶。
- 测试表明同步延时非常小,指令一旦执行完毕就会立刻写AOF文件和向Slave转发,除非Slave自己被阻塞住了。
- 比较蠢的是,即使在配置文件里设了slavof,slave启动时依然会先从数据文件载入一堆没用的数据,再去执行slaveof。
- “Slaveof no one”,立马变身master。
- 2.8版本将支持PSYNC部分同步,master会拨出一小段内存来存放要发给slave的指令,如果slave短暂的断开了,重连时会从内存中读取需要补读的指令,这样就不需要断开两秒也搞一次全同步了。但如果断开时间较长,已经超过了内存中保存的数据,就还是要全同步。
- Slave也可以接收Read-Only的请求。
5.2.2 slaveof执行过程,完全重用已有功能,非常经济
- 先执行一次全同步 — 请求master BgSave出自己的一个RDB Snapshot文件发给slave,slave接收完毕后,清除掉自己的旧数据,然后将RDB载入内存。
- 再进行增量同步 — master作为一个普通的client连入slave,将所有写操作转发给slave,没有特殊的同步协议。
5.2.3 Trouble Shooting again
有时候明明master/slave都活得好好的,突然间就说要重新进行全同步了:
1.Slave显示:# MASTER time out: no data nor PING received…
slave会每隔repl-ping-slave-period(默认10秒)ping一次master,如果超过repl-timeout(默认
60秒)都没有收到响应,就会认为Master挂了。如果Master明明没挂但被阻塞住了也会报这个错。可以适当调大repl-timeout。
2.Master显示:# Client addr=10.175.162.123:44670 flags=S oll=104654
omem=2147487792 events=rw cmd=sync scheduled to be closed ASAP for
overcoming of output buffer limits.
当slave没挂但被阻塞住了,比如正在loading Master发过来的RDB,
Master的指令不能立刻发送给slave,就会放在output
buffer中(见oll是命令数量,omem是大小),在配置文件中有如下配置:client-output-buffer-limit slave
256mb 64mb 60,
这是说负责发数据给slave的client,如果buffer超过256m或者连续60秒超过64m,就会被立刻强行关闭!!!
Traffic大的话一定要设大一点。否则就会出现一个很悲剧的循环,Master传输一个大的RDB给Slave,Slave努力的装载,但还没装载
完,Master对client的缓存满了,再来一次。
平时可以在master执行 redis-cli client list 找那个cmd=sync,flag=S的client,注意OMem的变化。
5.3 Fail-Over
Redis-sentinel是2.6版开始加入的另一组独立运行的节点,提供自动Fail Over的支持。
5.3.1 主要执行过程
- Sentinel每秒钟对所有master,slave和其他sentinel执行Ping,redis-server节点要应答+PONG或-LOADING或-MASTERDOWN.
- 如果某一台Sentinel没有在30秒内(可配置得短一些哦)收到上述正确应答,它就会认为master处于sdown状态(主观Down)
- 它向其他sentinel询问是否也认为该master倒了(SENTINEL is-master-down-by-addr ), 如果quonum台(默认是2)sentinel在5秒钟内都这样认为,就会认为master真是odown了(客观Down)。
- 此时会选出一台sentinel作为Leader执行fail-over, Leader会从slave中选出一个提升为master(执行slaveof no one),然后让其他slave指向它(执行slaveof new master)。
5.3.2 master/slave 及 其他sentinel的发现
master地址在sentinel.conf里,
sentinel会每10秒一次向master发送INFO,知道master的slave有哪些。
如果master已经变为slave,sentinel会分析INFO的应答指向新的master。以前,sentinel重启时,如果master已经
切换过了,但sentinel.conf里master的地址并没有变,很可能有悲剧发生。另外master重启后如果没有切换成slave,也可能有悲
剧发生。新版好像修复了一点这个问题,待研究。
另外,sentinel会在master上建一个pub/sub
channel,名为”sentinel:hello”,通告各种信息,sentinel们也是通过接收pub/sub
channel上的+sentinel的信息发现彼此,因为每台sentinel每5秒会发送一次自己的host信息,宣告自己的存在。
5.3.3 自定义reconfig脚本
- sentinel在failover时还会执行配置文件里指定的用户自定义reconfig脚本,做用户自己想做的事情,比如让master变为slave并指向新的master。
- 脚本的将会在命令行按顺序传入如下参数: <master-name>
<role(leader/observer)> <state(上述三种情况)> <from-ip>
<from-port> <to-ip> <to-port>
- 脚本返回0是正常,如果返回1会被重新执行,如果返回2或以上不会。 如果超过60秒没返回会被强制终止。
觉得Sentinel至少有两个可提升的地方:
- 一是如果master 主动shutdown,比如系统升级,有办法主动通知sentinel提升新的master,减少服务中断时间。
- 二是比起redis-server太原始了,要自己丑陋的以nohup sentinel > logfile 2>&1 & 启动,也不支持shutdown命令,要自己kill pid。
5.4 Client的高可用性
基于Sentinel的方案,client需要执行语句SENTINEL get-master-addr-by-name mymaster
可获得当前master的地址。
Jedis正在集成sentinel,已经支持了sentinel的一些指令,但还没发布,但sentinel版的连接池则暂时完全没有,在公司的项目里
我参考网友的项目自己写了一个。
淘宝的Tedis driver,使用了完全不同的思路,不基于Sentinel,而是多写随机读, 一开始就同步写入到所有节点,读的话随便读一个还活着的节点就行了。但有些节点成功有些节点失败如何处理? 节点死掉重新起来后怎么重新同步?什么时候可以重新Ready? 所以不是很敢用。
另外如Ruby写的redis_failover,也是抛开了Redis Sentinel,基于ZooKeeper的临时方案。
Redis作者也在博客里抱怨怎么没有人做Dynamo-style 的client。
6. 运维
6.1 安装
- 安装包制作:没有现成,需要自己编译,自己写rpm包的脚本,可参考utils中的install_server.sh与redis_init_script。
但RHEL下设定script runlevel的方式不一样,redis_init_script中要增加一句 “# chkconfig:
345 90 10″ ,而install_server.sh可以删掉后面的那句“chkconfig –level 345 reis” - 云服务:Redis Cloud,在Amazon、Heroku、Windows Azure、App Frog上提供云服务,供同样部署在这些云上的应用使用。其他的云服务有GarantiaData,已被redis-cloud收购。另外还有Redis To Go, OpenRedis, RedisGreen。
- CopperEgg统计自己的用户在AWS上的数据库部署:mysqld占了50%半壁江山, redis占了18%排第二, mongodb也有11%, cassandra是3%,Oracle只有可怜的2%。
- Chef Recipes:brianbianco/redisio,活跃,同步更新版本。
6.2 部署模型
- Redis只能使用单线程,为了提高CPU利用率,有提议在同一台服务器上启动多个Redis实例,但这会带来严重的IO争用,除非Redis不需要持久化,或者有某种方式保证多个实例不会在同一个时间重写AOF。
- 一组sentinel能同时监控多个Master。
- 有提议说环形的slave结构,即master只连一个slave,然后slave再连slave,此部署有两个前提,一是有大量的只读需求需要在slave完成,二是对slave传递时的数据不一致性不敏感。
6.3 配置
约30个配置项,全都有默认配置,对redif.conf默认配置的修改见附录1。
6.3.1 三条路
- 可以配置文件中编写。
- 可以在启动时的命令行配置,redis-server –port 7777 –slaveof 127.0.0.1 8888。
- 云时代大规模部署,把配置文件满街传显然不是好的做法, 可以用redis-cli执行Config Set指令, 修改所有的参数,达到维护人员最爱的不重启服务而修改参数的效果,而且在新版本里还可以执行 Config Rewrite 将改动写回到文件中,不过全部默认值都会打印出来,可能会破坏掉原来的文件的排版,注释。
6.3.2 安全保护
- 在配置文件里设置密码:requirepass foobar。
- 禁止某些危险命令,比如残暴的FlushDB,将它rename成”":rename-command FLUSHDB “”。
6.4 监控与维护
综述: Redis监控技巧
6.4.1 监控指令
Info指
令将返回非常丰富的信息。
着重监控检查内存使用,是否已接近上限,used_memory是Redis申请的内存,used_memory_rss是操作系统分配给Redis的物
理内存,两者之间隔着碎片,隔着Swap。 还有重点监控 AOF与RDB文件的保存情况,以及master-slave的关系。Statistic
信息还包括key命中率,所有命令的执行次数,所有client连接数量等, CONFIG RESETSTAT 可重置为0。
Monitor指令可以显示Server收到的所有指令,主要用于debug,影响性能,生产环境慎用。
SlowLog 检查慢操作(见2.性能)。
6.4.2 Trouble Shooting支持
- 日志可以动态的设置成verbose/debug模式,但不见得有更多有用的log可看,verbose还会很烦的每5秒打印当前的key情况和client情况。指令为config set loglevel verbose。
- 最爱Redis的地方是代码只有2.3万行,而且编码优美,而且huangz同学还在原来的注释上再加上了中文注释——Redis 2.6源码中文注释版 ,所以虽然是C写的代码,虽然有十年没看过C代码,但这几天trouble shooting毫无难度,一看就懂。
- Trobule shotting的经历证明antirez处理issue的速度非常快(如果你的issue言之有物的话),比Weblogic之类的商业支持还好。
6.4.3 持久化文件维护
- 如果AOF文件在写入过程中crash,可以用redis-check-aof修复,见5.1.2
- 如果AOF rewrite和 RDB snapshot的过程中crash,会留下无用的临时文件,需要定期扫描删除。
6.4.4 三方工具
官网列出了如下工具,但暂时没发现会直接拿来用的:
- Redis Live,基于Python的web应用,使用Info和Monitor获得系统情况和指令统计分析。 因为Monitor指令影响性能,所以建议用cron定期运行,每次偷偷采样两分钟的样子。
- phpRedisAdmin,基于php的Web应用,目标是MysqlAdmin那样的管理工具,可以管理每一条Key的情况,但它的界面应该只适用于Key的数量不太多的情况,Demo。
- Redis Faina,基于Python的命令行,Instagram出品,用户自行获得Monitor的输出后发给它进行统计分析。由于Monitor输出的格式在Redis版本间不一样,要去GitHub下最新版。
- Redis-rdb-tools 基于Python的命令行,可以分析RDB文件每条Key对应value所占的大小,还可以将RDB dump成普通文本文件然后比较两个库是否一致,还可以将RDB输出成JSON格式,可能是最有用的一个了。
- Redis Sampler,基于Ruby的命令行,antirez自己写的,统计数据分布情况。
|