引言
大概是因为Redis是个人开发的产品,所以Redis的高可用方案是被分成了几块来实现:主从复制、主从切换以及虚拟IP或客户端方案。
从Redis 2.8开始加入对Sentinel机制从而实现了服务器端的主从切换,但目前尚未发现实现虚拟IP或客户端切换方案。
主从复制研究
wget http://download.redis.io/releases/redis-2.8.2.tar.gz
tar xzf redis-2.8.2.tar.gz
mv redis-2.8.2 /opt/
cp redis.conf redis-master.conf
cp redis.conf redis-slave.conf
cd /opt/redis-2.8.2
make
以下是关于 Redis 复制功能的几个重要方面:
1. 一个Master可以有多个Slave;
2. Redis使用异步复制。从2.8开始,Slave会周期性(每秒一次)发起一个Ack确认复制流(replication stream)被处理进度;
3. 不仅主服务器可以有从服务器, 从服务器也可以有自己的从服务器, 多个从服务器之间可以构成一个图状结构;
4. 复制在Master端是非阻塞模式的,这意味着即便是多个Slave执行首次同步时,Master依然可以提供查询服务;
5. 复制在Slave端也是非阻塞模式的:如果你在redis.conf做了设置,Slave在执行首次同步的时候仍可以使用旧数据集提供查询;你也可以配置为当Master与Slave失去联系时,让Slave返回客户端一个错误提示;
6. 当Slave要删掉旧的数据集,并重新加载新版数据时,Slave会阻塞连接请求(一般发生在与Master断开重连后的恢复阶段);
7. 复制功能可以单纯地用于数据冗余(data redundancy),也可以通过让多个从服务器处理只读命令请求来提升扩展性(scalability): 比如说, 繁重的 SORT 命令可以交给附属节点去运行。
8. 可以通过修改Master端的redis.config来避免在Master端执行持久化操作(Save),由Slave端来执行持久化。
分别修改redis-master.conf和redis-slave.conf,
daemonize项,改为yes(缺省为no):daemonize yes
maxmemory项,设最大占用内存为50MB:maxmemory 50mb
而有6种内存过期策略,通过maxmemory-policy修改,一般使用默认值或allkeys-lru:
volatile-lru:只对设置了过期时间的key进行LRU(默认值)
allkeys-lru : 是从所有key里 删除 不经常使用的key
volatile-random:随机删除即将过期key
allkeys-random:随机删除
volatile-ttl : 删除即将过期的
noeviction : 永不过期,返回错误
修改redis-slave.conf中的端口,避免和Master的相同:port 7379
Redis复制工作原理:
1. 如果设置了一个Slave,无论是第一次连接还是重连到Master,它都会发出一个SYNC命令;
2. 当Master收到SYNC命令之后,会做两件事:
a) Master执行BGSAVE,即在后台保存数据到磁盘(rdb快照文件);
b) Master同时将新收到的写入和修改数据集的命令存入缓冲区(非查询类);
3. 当Master在后台把数据保存到快照文件完成之后,Master会把这个快照文件传送给Slave,而Slave则把内存清空后,加载该文件到内存中;
4. 而Master也会把此前收集到缓冲区中的命令,通过Reids命令协议形式转发给Slave,Slave执行这些命令,实现和Master的同步;
5. Master/Slave此后会不断通过异步方式进行命令的同步,达到最终数据的同步一致;
6. 需要注意的是Master和Slave之间一旦发生重连都会引发全量同步操作。但在2.8之后版本,也可能是部分同步操作。
部分复制
2.8开始,当Master和Slave之间的连接断开之后,他们之间可以采用持续复制处理方式代替采用全量同步。
Master端为复制流维护一个内存缓冲区(in-memory backlog),记录最近发送的复制流命令;同时,Master和Slave之间都维护一个复制偏移量(replication offset)和当前Master服务器ID(Master run id)。当网络断开,Slave尝试重连时:
a. 如果MasterID相同(即仍是断网前的Master服务器),并且从断开时到当前时刻的历史命令依然在Master的内存缓冲区中存在,则Master会将缺失的这段时间的所有命令发送给Slave执行,然后复制工作就可以继续执行了;
b. 否则,依然需要全量复制操作;
Redis 2.8 的这个部分重同步特性会用到一个新增的 PSYNC 内部命令, 而 Redis 2.8 以前的旧版本只有 SYNC 命令, 不过, 只要从服务器是 Redis 2.8 或以上的版本, 它就会根据主服务器的版本来决定到底是使用 PSYNC 还是 SYNC :
如果主服务器是 Redis 2.8 或以上版本,那么从服务器使用 PSYNC 命令来进行同步。
如果主服务器是 Redis 2.8 之前的版本,那么从服务器使用 SYNC 命令来进行同步。
配置Slave
只需要将redis-slave.conf中REPLICATION段中的slaveof <masterip> <masterport>行的注释去掉,并修改为:
slaveof 127.0.0.1 6379
即完成该Slave的配置,并指向本地端口为6379的Master端。
masterauth
如果Master端通过requirepass设置了密码,Slave需要对应的通过masterauth <password>设置密码;
slave-serve-stale-data
当Slave和Master断开连接时,Slave是直接返回错误提示还是利用历史数据响应客户端(或是直接返回空数据,当全量复制进行时)。yes是缺省值,即利用历史数据响应。
slave-read-only
缺省模式下,Slave服务器是只读的。
repl-ping-slave-peroid
即心跳检测间隔时间,缺省值为10秒。
repl-timeout 60
复制超时
启动Redis
#redis-server redis-master.conf
#redis-server redis-slave.conf
使用ps查看进程
#ps -ef | grep redis
还可以用netstat查看端口
#netstat -tpln
验证主从复制
#redis-cli set test 1000
#redis-cli get test #只能说明目前Master工作正常,不能说明Slave已经复制数据
根据刚刚查看到的端口号,把端口号是6379的Master进程杀掉
#kill -9 XXXX(PID号)
#redis-cli -p 7379 get test #连接到Slave上,读取test
#redis-cli -p 7379 set test 1000 #会提示Slave只读错误,不能写入