0

0

浅析Redis中的集群主从复制原理

青灯夜游

青灯夜游

发布时间:2022-01-24 10:22:21

|

2755人浏览过

|

来源于掘金社区

转载

本篇文章带大家深入理解下redis集群主从复制原理,希望对大家有所帮助!

浅析Redis中的集群主从复制原理

一、首先思考一个问题,为什么redis性能这么高还需要分布式方案?

1、实现更高性能:高并发应用,单机性能会有影响,需要更多redis服务器分担压力,实现负载均衡

2、实现高可用:如果单机,防止宕机/硬件故障

3、实现可扩展:单机内存和硬件有限制,实现横向扩展

冗余或者分片存储实现如上特性。

二、主从复制-replication配置

和Kafka,Mysql,Rocketmq一样,redis支持集群部署,集群节点有master和slave之分,主节点是master,从节点是slave(最新叫副本replica).slave会通过复制机制,从master同步最新的数据。Redis提供了非常方便的命令开启主从复制。【相关推荐:Redis视频教程

如何配置开启主从复制?

以本机搭建伪集群为例,6379端口是从节点,6378作为主节点。

1、从节点redis.conf配置 replicaof masterip masterport 从节点启动后,自动连接到master节点,开始同步数据.

1.png

如果换了新的master节点,这个配置会被重写。

2、或者在redis-server程序启动时候指定

./redis-server --replicaof masterip masterport

3、或者登录客户端,执行如下命令

slaveof masterip masterport

注意这种方式是运行过程中修改,可以实现故障转移

注意: 一个从节点也可以是其他节点的主节点,形成级联复制的关系。但是其他节点也是从顶层主节点同步数据。

配置好集群后,通过info replication查看集群状态

2.png

通过role命令,可以查看节点在集群中的角色信息

3.png

注意从节点是只读的。写命令会报错。 

4.png

slave如何退出集群? 可以执行如下命令: 

slaveof no one

三、主从复制的流程

1、首先是副本-replica加入集群 

5.png

2、与master建立连接,通过定时器定时检查是否要从主节点同步数据

6.png

源码说明:

//每1s执行这个方法
void replicationCron(void) {
    ...
    //检查是否需要连接到master 如果是REPL_STATE_CONNECT状态,必须连接到master
    //#define REPL_STATE_CONNECT 1  Must connect to master 
    if (server.repl_state == REPL_STATE_CONNECT) {
        serverLog(LL_NOTICE,"Connecting to MASTER %s:%d",
            server.masterhost, server.masterport);
        //和master创建连接    
        if (connectWithMaster() == C_OK) {
            serverLog(LL_NOTICE,"MASTER <-> REPLICA sync started");
        }
    }
    
    //发送ping命令给slave 
    if ((replication_cron_loops % server.repl_ping_slave_period) == 0 &&
        listLength(server.slaves))
    {
        /* Note that we don't send the PING if the clients are paused during
         * a Redis Cluster manual failover: the PING we send will otherwise
         * alter the replication offsets of master and slave, and will no longer
         * match the one stored into 'mf_master_offset' state. */
        int manual_failover_in_progress =
            server.cluster_enabled &&
            server.cluster->mf_end &&
            clientsArePaused();

        if (!manual_failover_in_progress) {
            ping_argv[0] = createStringObject("PING",4);
            replicationFeedSlaves(server.slaves, server.slaveseldb,
                ping_argv, 1);
            decrRefCount(ping_argv[0]);
        }
    }
    
    //发送换行符到所有slave,告诉slave等待接收rdb文件
    listRewind(server.slaves,&li);
    while((ln = listNext(&li))) {
        client *slave = ln->value;

        int is_presync =
            (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START ||
            (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_END &&
             server.rdb_child_type != RDB_CHILD_TYPE_SOCKET));

        if (is_presync) {
            if (write(slave->fd, "\n", 1) == -1) {
                /* Don't worry about socket errors, it's just a ping. */
            }
        }
    }
    ...
}

3、全量复制流程-支持无盘复制或者rdb持久化复制 

7.png

10Web
10Web

AI驱动的WordPress网站自动构建器,托管和页面速度助推器

下载

当slave连接到master后,使用psync(以前是sync命令,它不允许部分重新同步,所以现在改用PSYNC)命令初始化复制,将主节点replication id和处理过最大offset发送到master。

master节点拥有如下两个属性,一个replication id(标志实例),一个offset(标志写入从节点的stream) 

Replication ID, offset

如果主节点缓冲区中没有足够的积压工作,或者如果复制副本引用的是不再已知的历史记录(复制ID),则会发生完全重新同步 

源码说明:

    //没有在rdb进程,没有aof重写进程
    if (server.rdb_child_pid == -1 && server.aof_child_pid == -1) {
        time_t idle, max_idle = 0;
        int slaves_waiting = 0;
        int mincapa = -1;
        listNode *ln;
        listIter li;

        listRewind(server.slaves,&li);
        while((ln = listNext(&li))) {
            client *slave = ln->value;
            //判断slave是否是等待bgsave状态
            if (slave->replstate == SLAVE_STATE_WAIT_BGSAVE_START) {
            //多久没有发送心跳或查询数据了 空闲时间间隔
                idle = server.unixtime - slave->lastinteraction;
                if (idle > max_idle) max_idle = idle;
                slaves_waiting++;
                mincapa = (mincapa == -1) ? slave->slave_capa :
                                            (mincapa & slave->slave_capa);
            }
        }

        if (slaves_waiting &&
            (!server.repl_diskless_sync ||
             max_idle > server.repl_diskless_sync_delay))
        {
            /* Start the BGSAVE. The called function may start a
             * BGSAVE with socket target or disk target depending on the
             * configuration and slaves capabilities. */
             //bgsave rdb生成
            startBgsaveForReplication(mincapa);
        }
    }

复制过程中,slave状态转换流程。

8.png

4、命令传播阶段,执行完全量同步后,主从会进行命令传播实现数据一致。

9.png

四、复制id理解

每次实例作为主实例从头开始重新启动,或者将复制副本提升为主实例,都会为此实例生成一个新的复制ID。如果两个replica的复制id相同,则他们可能在不同的时间,有相同的数据,对于保存最新数据集的给定历史记录(复制ID),偏移量作为一个逻辑时间来理解。需要通过Replication ID, offset两个数据来判断。用来判断从节点同步数据到哪了。

五、主从复制常见问题

1、slave本身有数据,会怎么样?

slave先删除自身的数据,再用rdb文件加载。

2、生成rdb文件的过程中,客户端写命令怎么处理?

保存到内存缓存中,rdb发送完成后发送到slave。 

3、Redis复制如何处理key过期的? 

1、副本不会使key过期,而是等待主机使key过期。当主机使key过期(或由于LRU而将其逐出)时,它将合成一个DEL命令,该命令将传输到所有副本。

2、但是,由于主机驱动的expire,有时副本可能仍然具有逻辑上已过期的内存密钥,因为主服务器无法及时提供DEL命令。为了处理这个问题,副本使用它的逻辑时钟来报告一个key不存在,只用于不违反数据集一致性的读取操作(因为来自主服务器的新命令将到达)

3、在Lua脚本执行期间,不执行密钥过期。当Lua脚本运行时,从概念上讲,主节点中的时间是冻结的,因此给定的键在脚本运行的所有时间内都将存在或不存在。这可以防止key在脚本中间过期,并且需要key才能以保证在数据集中具有相同效果的方式将相同的脚本发送到副本。

一旦复制副本升级为主副本,它将开始独立地使key过期,并且不需要旧主副本的任何帮助。 

六、主从复制总结

1、解决了数据备份的问题,但是rdb文件大,传输大文件,恢复时间也长

2、如果master异常,需要手工将replica选举为master

3、1主多从,1主1从的情况下,还是存在单点问题 

4、Redis版本2.8.18后支持无盘复制,性能更高。

七、复制说明

1、默认用异步复制,通过异步确认同步的命令数量

2、1个master可以有多个副本

3、副本也可以有自己的副本,从redis4.0开始,副本都会从主节点接收完全相同的复制流

4、复制既可以用于可扩展性,也可以用于只读查询的多个副本

更多编程相关知识,请访问:编程入门!!

相关专题

更多
mysql修改数据表名
mysql修改数据表名

MySQL修改数据表:1、首先查看数据库中所有的表,代码为:‘SHOW TABLES;’;2、修改表名,代码为:‘ALTER TABLE 旧表名 RENAME [TO] 新表名;’。php中文网还提供MySQL的相关下载、相关课程等内容,供大家免费下载使用。

653

2023.06.20

MySQL创建存储过程
MySQL创建存储过程

存储程序可以分为存储过程和函数,MySQL中创建存储过程和函数使用的语句分别为CREATE PROCEDURE和CREATE FUNCTION。使用CALL语句调用存储过程智能用输出变量返回值。函数可以从语句外调用(通过引用函数名),也能返回标量值。存储过程也可以调用其他存储过程。php中文网还提供MySQL创建存储过程的相关下载、相关课程等内容,供大家免费下载使用。

244

2023.06.21

mongodb和mysql的区别
mongodb和mysql的区别

mongodb和mysql的区别:1、数据模型;2、查询语言;3、扩展性和性能;4、可靠性。本专题为大家提供mongodb和mysql的区别的相关的文章、下载、课程内容,供大家免费下载体验。

280

2023.07.18

mysql密码忘了怎么查看
mysql密码忘了怎么查看

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql密码忘了怎么办呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

513

2023.07.19

mysql创建数据库
mysql创建数据库

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS 应用软件之一。那么mysql怎么创建数据库呢?php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

250

2023.07.25

mysql默认事务隔离级别
mysql默认事务隔离级别

MySQL是一种广泛使用的关系型数据库管理系统,它支持事务处理。事务是一组数据库操作,它们作为一个逻辑单元被一起执行。为了保证事务的一致性和隔离性,MySQL提供了不同的事务隔离级别。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

384

2023.08.08

sqlserver和mysql区别
sqlserver和mysql区别

SQL Server和MySQL是两种广泛使用的关系型数据库管理系统。它们具有相似的功能和用途,但在某些方面存在一些显著的区别。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

523

2023.08.11

mysql忘记密码
mysql忘记密码

MySQL是一种关系型数据库管理系统,关系数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内,这样就增加了速度并提高了灵活性。那么忘记mysql密码我们该怎么解决呢?php中文网给大家带来了相关的教程以及其他关于mysql的文章,欢迎大家前来学习阅读。

595

2023.08.14

php源码安装教程大全
php源码安装教程大全

本专题整合了php源码安装教程,阅读专题下面的文章了解更多详细内容。

74

2025.12.31

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
进程与SOCKET
进程与SOCKET

共6课时 | 0.3万人学习

Redis+MySQL数据库面试教程
Redis+MySQL数据库面试教程

共72课时 | 6.2万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号