虽然Redis提供了持久化的功能保证了在Redis服务器重启时数据不会丢失,但保存在磁盘上的数据文件依旧有可能因为磁盘损坏而丢失,所以Redis提供了复制功能来在多台Redis服务器上同步数据,这样即使有一台Redis服务器保存数据的文件损坏,数据也不会丢失。

    同步后的Redis数据库分为两类:主数据库(master),从数据库(slave),它们结构如下图:

redis赋值命令 redis数据复制_redis赋值命令

    主从是相对的,对于A、B、C三个数据库来说,A是主数据库,而B、C是从数据库,而对于B、D、E来说,B又是主数据库,D、E是从数据库。主从数据库数据的流向只能顺着箭头方向,例如,在A中执行set username yamikaze,那么在B、C、D等数据库中使用get username都能得到数据,而在B中使用set age 11,在D、E、F中能得到数据,但在A、C中返回是(nil)。

同时在A中set username后,从数据库只能查看,而不能修改。最后,从数据库只能与一个主数据库想关联。

    1、实现主从同步

从数据库的配置文件中加入配置。slaveof 主数据库ip 主数据库端口即可,主数据库不用做任何配置。

    也可以启动数据库然后执行指令slaveof host port进行管理,如果重复执行这个指令,且host port正确,Redis会断开与原主数据库的连接,然后与指定的host建立连接。

    ①、启动多个Redis实例,如下图,指定不同端口号即可。

redis赋值命令 redis数据复制_服务器_02

    ②、让①中端口为6379的Redis作为主数据库,端口6340作为从数据库,端口6350作为6340的从数据库。然后执行指令得到结果如图:

redis赋值命令 redis数据复制_redis赋值命令_03

    可以看到在从数据库中无法修改从主数据库同步过来的数据,可以修改配置文件中的slave-read-only从yes改为no,然后重启该实例,再进行以上操作。可以看到修改成功,但主数据库数据没有发生改变

redis赋值命令 redis数据复制_服务器_04

    然后主数据库进行的每一个写指令都将传递给从服务器,所以在主服务器删除了k1,从服务器也会删除k1.

    ③、如果主服务器崩溃或者其他原因不能正常运行提供服务,可以在从服务器运行指令slaveof no one将从服务器升级为主服务器。升级后的从服务器可以对数据进行修改,不用讲slave-read-only改为no,因为执行该指令后不再是从服务器了。

redis赋值命令 redis数据复制_服务器_05

    简单测试代码如下:


package org.yamikaze.redis.persistence;

import redis.clients.jedis.Jedis;
import static org.junit.Assert.*;

/**
 * 测试从服务器
 * @author yamikaze
 */
public class SlaveServer {

    private Jedis jedis;
    private String key = "username";

    public SlaveServer() {
        jedis = new Jedis("192.168.1.103", 6340);
    }

    public void slaveOf(String host, int port) throws Exception{
        jedis.slaveofNoOne();
        jedis.del(key);

        String username = jedis.get(key);
        assertTrue(username == null);
        String message = jedis.slaveof(host, port);
        assertTrue("OK".equals(message));
        //当前线程睡眠一秒,给从数据库同步主数据库的数据时间。
        Thread.sleep(1000);
        username = jedis.get(key);
        assertNotNull(username);

    }

    public static void main(String[] args) throws Exception {
        SlaveServer ss = new SlaveServer();
        ss.slaveOf("192.168.1.103", 6379);
    }
}


    如果主数据库配置了密码(在配置文件加上了requirepass 密码),那么在从数据库的配置文件中要加上masterauth 密码,然后从数据库会自动调用AUTH指令进行认证。


参考资料

    《Redis入门指南》

    《Redis设计与实现》