详细讲解Redis主从结构配置以及复制原理(一)

来源:互联网 发布:微博短域名 编辑:程序博客网 时间:2024/05/17 22:30

Redis是基于内存的NoSql数据库,同时以其卓越的读写性能闻名业内,并且我在这篇博客Redis持久化机制原理分析与解惑-为什么Redis进行RDB持久化数据时,新起一个进程而不是在原进程中起一个线程中讲过Redis的两种数据持久化方式,但是如果Redis读写压力较大的情况下,将所有的数据都存在一个实例中,这将会大大降低Redis的性能,但是我们可以使用Redis提供的主从复制功能来实现数据冗余和读写分离。

Redis在2.8版本之前,对于从机器每次重连到主都会发送SYNC命令进行全量复制,在2.8版本之后从向主发送PSYNC支持断点续传的复制方式,我们接下来依次看看这两种不同的主从复制方式。

(一)我们先看2.6版本全量主从复制流程:

(1) 从节点起动起来之后主动向主节点发送SYNC命令要求同步数据

(2) 主节点收到SYNC命令之后,fork出一个子进程非阻塞主实例的执行RBD持久化机制,执行完RDB之后将rdb文件发给从节点,

在执行RDB期间主节点将写命令写入缓存,当主节点接到多个从发送SYNC命令之后只执行一次RDB

(3) 从节点收到rdb文件之后载入内存,这个过程从节点可以使用旧数据响应客户端请求,也可以返回一个错误信息

(4) 主节点将缓存中的写命令以Redis命令协议的形式发给从节点


(二)下面先使用版本redis-2.6.16.tar.gz构建一个主从架构

(1)解压 tar zxvf  redis-2.6.16.tar.gz

(2)进入到解压后的文件夹redis-2.6.16 执行make命令

(3)复制redis.conf配置文件 为redis_6379.conf、redis_6380.conf、redis_6381.conf

依次修改内容如下:

#主节点配置文件redis_6379.confport 6379#配置log文件logfile master_6379.log#主节点关闭持久化机制#save 900 1#save 300 10#save 60 10000#内存设置为100M,在实际使用中 这里内存实际数值设置要大于实际所需,原因是要为主写命令缓存区预留出空间maxmemory 104857600#从节点配置文件redis_6380.confport 6380#配置log文件logfile slave_6380.logmaxmemory 104857600#设置将该节点设置为 6379端口实例的从节点slaveof 127.0.0.1 6379#从节点配置文件redis_6381.confport 6381#配置log文件logfile slave_6381.logmaxmemory 104857600#设置将该节点设置为 6379端口实例的从节点slaveof 127.0.0.1 6379
(4)进入到src目录下依次执行如下命令:

nohup ./redis-server ../redis_6379.conf &nohup ./redis-server ../redis_6380.conf &nohup ./redis-server ../redis_6381.conf &

(5)我们通过log来看一下主从复制过程

这份是主节点的log



这份是其中一个从节点的log

从主从的log中也可以清晰的看到主从复制的流程,其中从节点我们配置文件中设置了slave-serve-stale-data yes,这样从节点就会非阻塞的方式加载rdb文件,并且使用旧数据响应客户端读请求。


(三)登录客户端查看主从信息

使用如下命令依次登录主从节点

./redis-cli -h 127.0.0.1 -p 6379./redis-cli -h 127.0.0.1 -p 6381

使用info命令看到主从的信息:

主节点主从复制信息如下图,可以看到主节点中有两个从节点,并且从节点都在线


从节点主从复制信息,记录了主节点的相关信息


(四)使用telnet 查看Redis主节点以Redis命令协议形式发送缓存写命令

这里提供一个连接Redis服务端的Jedis工具类给大家

/** * 连接redis服务的工具类 * @author yujie.wang3 * @since 09/08/2017 */public final class RedisUtil {        //Redis服务器IP    private static String ADDR = "10.4.36.87";        //Redis的端口号    private static int PORT = 6379;       //可用连接实例的最大数目,默认值为8;    //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。    private static int MAX_ACTIVE = 100;        //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。    private static int MAX_IDLE = 20;        //等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException;    private static int MAX_WAIT = 10000;        private static int TIMEOUT = 10000;        //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;    private static boolean TEST_ON_BORROW = true;        private static JedisPool jedisPool = null;        /**     * 初始化Redis连接池     */    static {        try {            JedisPoolConfig config = new JedisPoolConfig();            config.setMaxActive(MAX_ACTIVE);            config.setMaxIdle(MAX_IDLE);            config.setMaxWait(MAX_WAIT);            config.setTestOnBorrow(TEST_ON_BORROW);            jedisPool = new JedisPool(config, ADDR, PORT);        } catch (Exception e) {            e.printStackTrace();        }    }        /**     * 获取Jedis实例     * @return     */    public synchronized static Jedis getJedis() {        try {            if (jedisPool != null) {                Jedis resource = jedisPool.getResource();                return resource;            } else {                return null;            }        } catch (Exception e) {            e.printStackTrace();            return null;        }    }        /**     * 释放jedis资源     * @param jedis     */    public static void returnResource(final Jedis jedis) {        if (jedis != null) {            jedisPool.returnResource(jedis);        }    }}

我们使用如下代码写入和读取key

/** * 测试Redis主节点以Redis命令协议的形式向从节点发送写命令 * @author yujie.wang * @since 09/08/2017 */public class RedisTest {public static void main(String[] args) {String key0 = "yujie_";String value = "";for(int i = 0; i <= 10000; i++){String key = key0 + String.valueOf(i);value = String.valueOf(i);//写入keyaddKeys(key, value);System.out.println("add key"+ key + " value: "+ value);try {Thread.sleep(2000);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}//读取keySystem.out.println("get_Key: " + key + " : "+ getKey(key));}}public static String getKey(String key) {Jedis client = RedisUtil.getJedis();String value = client.get(key);RedisUtil.returnResource(client);return value;}public static void addKeys(String key ,String value){Jedis client = RedisUtil.getJedis();client.set(key, value);RedisUtil.returnResource(client);}}

启动程序之后我们使用telnet 127.0.0.1 6379 访问主节点,并发送sync命令:


从这个过程可以看到 主节点首先传过来一个包含内存中数据的rdb文件,之后会以redis命令协议的形式发送写命令,并且每写一个命令就会发送一个命令。基于此我们可以实现redis的读写分离机制。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 施工员证书到期怎么办 银行从业过期了怎么办 国地税合并协税员怎么办 快递员虚报重量怎么办 信用卡刷整数了怎么办 汽车年检尾气不合格怎么办 车辆年检尾气不合格怎么办 年检手刹不合格怎么办 社会保障卡怎么办郑州的 网约车驾驶员证怎么办 干洗出现问题了怎么办 教师工资太低了怎么办 鸽子得了新城疫怎么办 氮肥施多了怎么办 当兵体质差跑步怎么办 手盘核桃脏了怎么办 怀孕吃了巴旦木怎么办 护士证丢了怎么办 扶贫搬迁老房子怎么办 ucl录取差两分怎么办 考研准考证号填错了怎么办? 拿到工伤证后怎么办 专接本有挂科怎么办 小孩发烧后惊厥怎么办 深圳民办学校停办学生怎么办 教育机构不退钱怎么办 智慧树错过选课怎么办 河南城建学院怎么办网 建学校土地手续怎么办 德国预科不能毕业怎么办 想出国打工怎么办手续 终结执行了该怎么办 网银界面打不开怎么办 abr检查结果异常怎么办 大排畸胎儿位置不好怎么办 交社保中途死了怎么办 不知道社保密码怎么办 社保卡没有信息怎么办 医保卡没有信息怎么办 信访局不受理怎么办 没身份证怎么办健康证