redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排 序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文 件,并且在此基础上实现了master-slave(主从)同步。
1.安装配置
1.1安装
cd /home/tools # 解压安装包后拷贝到/usr/local目录 tar -zxvf redis-3.0.4.tar.gz cp -r /home/tools/redis-3.0.4 /usr/local # 进入拷贝的src目录 cd /usr/local/redis/src # 安装 make MALLOC libc1.2将配置文件redis.conf拷贝到/etc/redis
cp -r /usr/local/redis/redis.conf /etc/redis
配置详情请参考http://blog.sina.com.cn/s/blog_636415010101970j.html
1.3编写开机启动脚本
vi /etc/init.d/redis
输入如下内容:
PATH=/usr/local/bin:/sbin:/usr/bin:/bin REDISPORT=6379 EXEC=/usr/local/redis/src/redis-server REDIS_CLI=/usr/local/redis/src/redis-cli PIDFILE=/var/run/redis.pid # redis config file path CONF="/etc/redis/redis.conf" case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed." else echo "Starting Redis server..." $EXEC $CONF fi if [ "$?"="0" ] then echo "Redis is running..." fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE exists, process is not running." else PID=$(cat $PIDFILE) echo "Stopping..." $REDIS_CLI -p $REDISPORT SHUTDOWN while [ -x $PIDFILE ] do echo "Waiting for Redis to shutdown..." sleep 1 done echo "Redis stopped" fi ;; restart|force-reload) ${0} stop ${0} start ;; *) echo "Usage: /etc/init.d/redis {start|stop|restart|force-reload}" >&2 exit 1 esac
chmod -R 755 /etc/init.d/redis
完成后设置开机启动:
chkconfig redis on
或在/etc/rc.d/rc.local中添加
service redis start
至此,基本的安装配置完成。
2.Sentinel架构实现主从容灾切换
2.1实现目标
目标清单:
1) 192.168.31.220、192.168.31.221和192.168.31.222为三台redis服务器。初始状态下220为master,221和222为slave,slave的数据来源于master。
2)redis服务器上各自存在一个Sentinel,监控本机redis的运行情况,并通知给闭路环上其它的redis节点;
3)当master发生异常(例如:宕机和断电等)导致不可运行时,Sentinel将通知给其它节点,而剩余节点上的Sentinel将重新选举出新的master,而原来的master重新恢复正常后,则一直扮演slave角色;
4)规定整个架构体系中,master提供读写服务,而slave只提供读取服务。
2.2实现过程
2.2.1编辑master(220)的配置文件
vi /etc/redis/redis.conf
# 开启守护模式 daemonize yes # 指定数据存储目录 dir /home/data/redis # 打开aof持久化 appendonly yes # 每秒一次aof写 appendfsync everysec
2.2.2编辑slave(221和222上)的配置文件
在2.2.1节的基本上加入如下配置项:
# 指定所属的主机 slaveof 192.168.31.220 6379 # 指定从机"只读" slave-read-only yes
2.2.3编辑Sentinel文件
# 将sentinel配置文件拷贝到/etc/redis目录后编辑 cp /usr/local/redis/sentinel.conf /etc/redis/sentinel.conf vi /etc/redis/sentinel.conf
# sentinel通讯端口 port 26379 # sentinel需要监控的master/slaver信息,格式为sentinel monitor <mastername> <masterIP> <masterPort> <quorum> # 其中<quorum>应该小于集群中slave的个数,当失效的节点数超过了<quorum>,则认为整个体系结构失效 sentinel monitor redisMaster 192.168.31.220 6379 2 # master被当前sentinel实例认定为失效的间隔时间,格式为sentinel down-after-milliseconds <mastername> <milliseconds> sentinel down-after-milliseconds redisMaster 10000 # 当新master产生时,同时进行“slaveof”到新master并进行同步复制的slave个数 # 在salve执行salveof同步时,将会终止客户端请求。 # 此值较大,意味着“集群”终止客户端请求的时间总和和较大。 # 此值较小,意味着“集群”在故障转移期间,多个salve向客户端提供服务时仍然使用旧数据。 sentinel parallel-syncs redisMaster 1 # failover过期时间。当failover开始后,在此时间内仍然没有触发任何failover操作,当前sentinel将会认为此次failoer失败。 sentinel failover-timeout redisMaster 60000
完成后,将此配置文件拷贝到其它节点的相同目录下。
2.2.4启动所有主从上的sentinel
前提是它们各自的server已成功启动
cd /usr/local/redis/src ./redis-sentinel /etc/redis/sentinel.conf
2.3测试
2.3.1在任意一个节点上查看主从机的复制信息
cd /usr/local/redis/src
1)查看Master节点信息:
./redis-cli -h 192.168.31.220 -p 6379 info Replication
从上图可看出,此时220的角色为master,有两个slave(221和222)被连接成功。此时打开master的sentinel.conf,在末尾可看到如下自动写入的内容:
2)查看Slave节点信息:
./redis-cli -h 192.168.31.221 -p 6379 info Replication
从上图可看出,此时221(或222,将命令行的ip换为222)的角色为slave,它们所属的master为220。此时打开slave的sentinel.conf,在末尾可看到如下自动写入的内容:
3)客户端连接到master后,set一条测试数据
./redis-cli -h 192.168.31.220 -p 6379
set name daniele_220
4)连接到任意一个节点上后,通过get命令可以获取数据
get name5)在任意一个slave上执行诸如set这样的写入操作时,将得到如下示例的错误信息:
6)关掉任意一个slave节点,所有节点的sentinel都可以检测到,出现如下示例信息:
从上图可看出221被sentinel检测到已处于关闭状态,此时再来查看剩余节点的主从信息,它们的角色不会发生变化,只是master上的connected_slaves变为了1
7)重启被关闭的slave节点,所有节点的sentinel都可以检测到,出现如下示例信息:
从上图可看出221又被sentinel检测到已处于可用状态,此时再来查看节点的主从信息,它们的角色仍然不会发生变化,master上的connected_slaves又变为了2
8)关掉220master节点,待所有节点的sentinel都检测到后,再来查看两个Slave节点的主从信息,发现其中一个节点的角色通过选举后会成为master:
从上图的最后一行监控信息可看出,222此时被选举为master,此时打开的222的redis.conf文件,slaveof配置项已被自动删除了。而221和220的redis.conf文件中slaveof配置项的值被自动修改为192.168.31.222 6379。
在这个新master上执行诸如set这样的写入操作将被成功执行
set name daniele_222
9)重启220,待所有节点的sentinel都检测到后,再来查看所有节点的主从信息,此时222的master角色不会被重新抢占,而220角色会从原来的master变为了slave
此时执行get name得到的值为daniele_222,而不是原来的daniele_220,因为220重启后会自动从新的master中同步数据。此时打开220的redis.conf文件,会在末尾找到如下信息:
3.总结
Redis sentinel模块是在2.4+版本中提供的一套主从自动切换的解决方案,主要为集群提供了master存活检测,集群服务监控, 自动故障转移和角色转换等功能,从一个方面说是提高了redis集群的可用性。
从2.3节中可看出,自动故障转移和角色转换归根结底就是一个写redis.conf和sentinel.conf的过程,通过在节点的redis.conf中写入/删除slaveof配置来实现角色的转换,通过在节点的sentinel.conf中写入不同的known-slave和known-sentinel等来实现故障转移。而这一系列的过程是有时间消耗的,当master失效时,在sentinel没有选举出新master之前,整个架构体系是没有一个“可写”节点的。因此,在这期间如果客户端程序发起了写入操作将会报错。同理,在sentinel没有选举出新master之前,不要立即重启失效的master,否则也会使整个架构体系没有一个“可写”节点,所有redis的角色都为slave(这应该算是一个BUG吧)。
另外,在经过了自动故障转移和角色转换这一完整的过程后,使整个架构体系中的master地址发生了变化,作为客户端应用程序来说,同样需要一套监听机制将master的连接换成新的地址,否则在严格的“读写分离”场景下将会出现错误。Jedis是redis官方推荐的JAVA API,其中在2.2.2+版本提供了对Sentinel的支持,应用可通过redis.clients.jedis.JedisSentinelPool.getResource()取得的Jedis实例会及时更新到新的主实例地址。具体可参考http://www.tuicool.com/articles/naeEJbv和http://segmentfault.com/a/1190000002690506
redis3.x最大的亮点在于提供了另一套集群方案(reids-cluster),它会将数据按照hash slot(哈希槽)的方式存储在不同的节点上,真正实现了分布式集群的目标。