http://bboyjing.github.io/2016/12/08/Redis%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E5%85%AB%E3%80%90Redis%E4%B8%BB%E4%BB%8E%E5%A4%8D%E5%88%B6%E3%80%91/
对于高负载应用来说,复制(replication)是不可或缺的一个特性,复制可以让其他服务器拥有一个不断地更新的数据副本,从而使得拥有副本数据的服务器可以用于处理客户端发送的读请求。关系型数据库通常会使用一个主服务器(master)向多个从服务器(slave)发送更行,并使用从服务器来处理所有读请求。Redis也采用了同样的方法来实现自己的复制特性,并将其用作扩展性能的一种手段。
复制相关配置选项
之前说过,当从服务器连接主服务器时,主服务器会执行BGSAVE操作,因此要求主服务器的快照持久化功能正常。配置slaveof host port选项即可连接主服务器。下面来测试下:
再安装一个Redis,直接拷贝之前的安装好的文件夹即可,本人安装的两个Redis路径为/opt/redis-3.2.4、/opt/redis-replication
1 2 3
| cd /opt sudo cp -r redis-3.2.4 redis-replication sudo chmod -R 777 redis-replication
|
修改redis-replication的redis.conf文件,改两个配置port和slaveof
1 2
| port 6380 slaveof localhost 6379
|
启动redis-3.2.4
1 2 3 4 5 6 7 8
| cd /opt/redis-3.2.4 ./src/redis-server ./redis.conf //启动交互式命令行并添加两个key ./src/redis-cli 127.0.0.1:6379> set key1 hello OK 127.0.0.1:6379> set key2 world OK
|
启动redis-replication
1 2 3 4 5 6 7 8
| cd /opt/redis-replication ./src/redis-server ./redis.conf //启动交互式命令行 ./src/redis-cli -h localhost -p 6380 //查看数据,6380端口的Redis服务上也有key1和key2了 localhost:6380> keys * 1) "key2" 2) "key1"
|
测试数据更新推送
1 2 3 4 5 6 7 8
| //主服务添加key3 127.0.0.1:6379> set key3 ! OK //从服务收到数据更新 localhost:6380> keys * 1) "key3" 2) "key2" 3) "key1"
|
对于一个正在运行的Redis服务器,可以发送SLAVEOF no one命令来让服务器终止复制操作,不再接受主服务器的数据更新;也可以通过发送SLAVEOF host port命令来让服务器开始复制一个新的主服务器,这个就不测试了,了解下有这个功能。
Redis复制的启动过程
从服务器连接主服务器时,主服务器会创建一个快照文件并将其发送至从服务器,但这只是主从复制执行过程的其中一步,下面列举出复制过程中Redis所有的行为:
步骤 | 主服务器操作 | 从服务器操作 |
---|
1 | 等待命令进入 | 连接(或者重连接)主服务器,发送SYNC命令 |
2 | 开始执行BGSAVE,并使用缓冲区记录BGSAVE之后执行的所有写命令 | 根据配置选项来决定时继续使用现在的数据来处理客户端命令,还是向发送请求的客户端返回错误 |
3 | BGSAVE执行完毕,向从服务器发送快照文件,并在发送期间继续使用缓冲区记录杯知行的写命令 | 丢弃所有旧的数据,开始载入主服务器发来的快照文件 |
4 | 快照文件发送完毕,开始向从服务器发送存储在缓冲区里面的写命令 | 完成对快照文件的解释操作,像往常一样开始接受命令请求 |
5 | 缓冲区存储的写命令发送完毕;从现在开始,没执行一个写命令,就像从服务器发送相同的写命令 | 执行主服务器发来的所有存储在缓冲区里面的写命令;从现在开始,接收并执行主服务器传来的每个写命令 |
由上述步骤可以看出,有必要给Redis主服务器留30%~45%的内存用于执行BGSAVE命令和创建记录写命令的缓冲区。另外,从服务器还有一点需要注意的是,从服务器在进行同步时,会清空自己的所有数据,因为第3步中,从服务器会丢弃所有旧数据。
注:Redis不支持主主复制(master-master replication)lian
当多个从服务器尝试连接同一个主服务器的时候,就会出现下表所示的两种情况中的其中一种:
当有新的从服务器连接主服务器时 | 主服务器的操作 |
---|
上述步骤3尚未执行 | 所有从服务器都会接收相同的快照文件和相同的缓冲区写命令 |
上述步骤3正在执行或者已经执行 | 当主服务器与较早进行连接的从服务器执行完复制所需的5个步骤之后,主服务器会与新连接的从服务器执行一次新的步骤1至步骤5 |
由此可以看出多个从服务器的同步对网络的开销挺大的,有可能会影响到主服务器接收写命令,甚至是与主服务器位于同一网络中的其他硬件。
主从链
上面讲到创建多个从服务器可能造成网络不可用,此时可以使用另外一个解决方案,从服务器拥有自己的从服务器,并由此形成主从链(master/slave chaining)。当读请求的重要性明显高于写请求的重要性,并且读请求的数量需求远远超出一台Redis服务器可以处理的范围时,用户就需要添加新的从服务器来处理读请求,随着负载不断上升,主服务器可能会无法快速地更新所有从服务器。为了缓解这个问题,可以创建一个由Redis主/从节点(master/slave node)组成的中间层来分担主服务器的复制工作,如下图所示:
按照上图的树状结构,只有3台从服务器和主服务器通信,其他都向从服务器同步数据,分散了网络开销。如果12台从服务器都向主服务器同步数据的话,想想也觉得有点牵强了。