目录

1 主从配置方法

2 主从复制的作用

3 主从复制的机制

3.1 全量数据同步(full resyncchrozation)

3.2 增量同步

4 主从复制的实现

4.1 主从关系的建立


1 主从配置方法

  • 配置文件: 在从服务器的配置文件中加入:slaveof   ip  port
  • 启动命令: redis-server启动命令后加入   --slaveof   ip  port    <本地端口:--port  xxxx>
  • 客户端命令: Redis服务器启动后,直接通过客户端执行命令:slaveof  ip  port,则该Redis实例成为从节点。

从模式:

# Redis使用后台模式
daemonize yes
# 关闭保护模式
#protected-mode no
# 注释以下内容开启远程访问
# bind 127.0.0.1
# 修改启动端口为6379
port 6380
# 修改pidfile指向路径(单机多服务建议修改)
pidfile /usr/local/redis-4.0.4/conf/redis_6380.pid
#数据库的存放位置(单机多服务建议修改)
dir /usr/local/redis-4.0.4/db/slave_xxx
#Slaveof命令可以将当前服务器转变为指定服务器的从属服务器(slave server)。
slaveof 192.168.235.128 6379

2 主从复制的作用

  • 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  • 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一种服务的冗余。
  • 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务(即写Redis数据时应用连接主节点,读Redis数据时应用连接从节点),分担服务器负载;尤其是在写少读多的场景下,通过多个从节点分担读负载,可以大大提高Redis服务器的并发量。
  • 读写分离:可以用于实现读写分离,主库写、从库读,读写分离不仅可以提高服务器的负载能力,同时可根据需求的变化,改变从库的数量;
  • 高可用基石:除了上述作用以外,主从复制还是哨兵和集群能够实施的基础,因此说主从复制是Redis高可用的基础。

3 主从复制的机制

Redis的主从复制功能除了支持一个Master节点对应多个Slave节点的同时进行复制外,还支持Slave节点向其它多个Slave节点进行复制。这样就使得架构师能够灵活组织业务缓存数据的传播,例如使用多个Slave作为数据读取服务的同时,专门使用一个Slave节点为流式分析工具服务。Redis的主从复制功能分为两种数据同步模式进行:全量数据同步和增量数据同步。

3.1 全量数据同步(full resyncchrozation)

先执行一次全同步 — 请求master BgSave出自己的一个RDB Snapshot文件发给slave,slave接收完毕后,清除掉自己的旧数据,然后将RDB载入内存。

上图简要说明了Redis中Master节点到Slave节点的全量数据同步过程。当Slave节点给定的replication id 和Master的replication id不一致时,或者Slave给定的上一次增量同步的offset的位置在Master的环形内存中(replication backlog)无法定位时(后文会提到),Master就会对Slave发起全量同步操作。这时无论您是否在Master打开了RDB快照功能,它和Slave节点的每一次全量同步操作过程都会更新/创建Master上的RDB文件。在Slave连接到Master,并完成第一次全量数据同步后,接下来Master到Slave的数据同步过程一般就是增量同步形式了(也称为部分同步)。增量同步过程不再主要依赖RDB文件,Master会将新产生的数据变化操作存放在replication backlog这个内存缓存区,这个内存区域是一个环形缓冲区,也就是说是一个FIFO的队列。

3.2 增量同步

进行增量同步 — master作为一个普通的client连入slave,将所有写操作转发给slave,没有特殊的同步协议。具体过程如下:

为什么在Master上新增的数据除了根据Master节点上RDB或者AOF的设置进行日志文件更新外,还会同时将数据变化写入一个环形内存结构(replication backlog),并以后者为依据进行Slave节点的增量更新呢?主要原因有以下几个:

  • 由于网络环境的不稳定,网络抖动/延迟都可能造成Slave和Master暂时断开连接,这种情况要远远多于新的Slave连接到Master的情况。如果以上所有情况都使用全量更新,就会大大增加Master的负载压力——写RDB文件是有大量I/O过程的,虽然Linux Page Cahe特性会减少性能消耗。

  • 另外在数据量达到一定规模的情况下,使用全量更新进行和Slave的第一次同步是一个不得已的选择——因为要尽快减少Slave节点和Master节点的数据差异。所以只能占用Master节点的资源和网络带宽资源。

  • 使用内存记录数据增量操作,可以有效减少Master节点在这方面付出的I/O代价。而做成环形内存的原因,是为了保证在满足数据记录需求的情况下尽可能减少内存的占用量。这个环形内存的大小,可以通过repl-backlog-size参数进行设置。

Slave重连后会向Master发送之前接收到的Master replication id信息和上一次完成部分同步的offset的位置信息。如果Master能够确定这个replication id和自己的replication id(有两个)一致且能够在环形内存中找到这个offset的位置,Master就会发送从offset的位置开始向Slave发送增量数据。那么连接正常的各个Slave节点如何接受新数据呢?连接正常的Slave节点将会在Master节点将数据写入环形内存后,主动接收到来自Master的数据复制信息。

这里就有一个问题了,我们的replication backlog的size设置为多大合适?

redis为replication backlog设置的默认大小为1M(repl-backlog-size),但是这个值是可以调整的,如果主服务器需要执行大量的写命令,又或者主从服务器之间断线后重连的时间比较长,那么这个大小也许并不合适。如果replication backlog的大小设置不恰当,那么PSYNC命令的复制同步模式就不能正常发挥作用,因此,正确估算和设置replication backlog的size非常重要。

建议:repl-backlog-size​​​​​​​ = reconnect_time_second * write_size_per_second*2

  • reconnect_time_second : 重连时间,以秒未单位
  • write_size_per_second : 每秒写入的命令大小

4 主从复制的实现

下面这段是slava机器上的log

9322:S 22 Feb 21:58:19.363 * Connecting to MASTER 192.168.235.128:6379
9322:S 22 Feb 21:58:19.365 * MASTER <-> SLAVE sync started
9322:S 22 Feb 21:58:19.366 * Non blocking connect for SYNC fired the event.
9322:S 22 Feb 21:58:19.367 * Master replied to PING, replication can continue...
9322:S 22 Feb 21:58:19.369 * Trying a partial resynchronization (request ac9f4efccb61b7e1415c2dcef3cc9580cbab5a02:1).
9322:S 22 Feb 21:58:19.371 * Full resync from master: f6857e8cabdcfef6d8fc376013ec37c21c7bb0eb:23254
9322:S 22 Feb 21:58:19.372 * Discarding previously cached master state.
9322:S 22 Feb 21:58:19.432 * MASTER <-> SLAVE sync: receiving 205 bytes from master
9322:S 22 Feb 21:58:19.435 * MASTER <-> SLAVE sync: Flushing old data
9322:S 22 Feb 21:58:19.436 * MASTER <-> SLAVE sync: Loading DB in memory
9322:S 22 Feb 21:58:19.437 * MASTER <-> SLAVE sync: Finished with success 

首先,在redis内部,所有的命令都维护在一张表格里:

struct redisCommand redisCommandTable[] = {{"get",getCommand,2,"r",0,NULL,1,1,1,0,0},{"set",setCommand,-3,"wm",0,NULL,1,1,1,0,0},{"setnx",setnxCommand,3,"wm",0,NULL,1,1,1,0,0},{"setex",setexCommand,4,"wm",0,NULL,1,1,1,0,0},........}

PS:当然所有的这些command,在启动的时候会调用populateCommandTable函数进行分析,然后把所有的redis command放在server.commands,它是一个字典。

dict commands; / Command table */

当我们在客户端执行slaveof 的,在客户端这一侧会调用replicaofCommand这个函数。

4.1 主从关系的建立

主从复制建立的方式有三种:

  • 在redis.conf文件中配置slaveof 选项,然后指定该配置文件启动Redis生效。
  • 在redis-server启动命令后加上--slaveof 启动生效。
  • 直接使用 slaveof 命令在从节点执行生效。

无论是通过哪一种方式来建立主从复制,都是从节点来执行slaveof命令,那么从节点执行了这个命令到底做了什么,我们上源码伪码:

void replicaofCommand(client *c) {1、判断当前环境是否在集群模式下,因为集群模式下不行执行该命令。2、是否执行的是SLAVEOF NO ONE命令,该命令会断开主从的关系,设置当前节点为主节点服务器。3、设置从节点所属主节点的IP和port。调用了replicationSetMaster()函数。
}

其中replicationSetMaster()函数执行操作的也很简单,总结为两步:

  • 清理之前所属的主节点的信息。
  • 设置新的主节点IP和port等。 因为,当前从节点有可能之前从属于另外的一个主节点服务器,因此要清理所有关于之前主节点的缓存、关闭旧的连接等等。然后设置该从节点的新主节点,设置了IP和port,还设置了以下状态:

slaveof命令是一个异步命令,执行命令时,从节点保存主节点的信息,确立主从关系后就会立即返回,后续的复制流程在节点内部异步执行。那么,如何触发复制的执行呢?

周期性执行的函数:replicationCron()函数,该函数被服务器的时间事件的回调函数serverCron()所调用,而serverCron()函数在Redis服务器初始化时,被设置为时间事件的处理函数。

// void initServer(void) Redis服务器初始化
aeCreateTimeEvent(server.el, 1, serverCron, NULL, NULL)

replicationCron这个函数每秒才执行一次,以下代码执行到serverCron函数的实现:

    /* Replication cron function -- used to reconnect to master,* detect transfer failures, start background RDB transfers and so forth. */run_with_period(1000) replicationCron();

主从关系建立后,从节点服务器的server.repl_state被设置为REPL_STATE_CONNECT,而replicationCron()函数会被每秒执行一次,该函数会发现我(从节点)现在有主节点了,而且我要的状态是要连接主节点(REPL_STATE_CONNECT)。

replicationCron()函数处理这以情况的代码如下:

/* Check if we should connect to a MASTER */
// 如果处于要必须连接主节点的状态,尝试连接
if (server.repl_state == REPL_STATE_CONNECT) {serverLog(LL_NOTICE,"Connecting to MASTER %s:%d",server.masterhost, server.masterport);// 以非阻塞的方式连接主节点if (connectWithMaster() == C_OK) {serverLog(LL_NOTICE,"MASTER <-> SLAVE sync started");}
}

replicationCron()函数根据从节点的状态,调用connectWithMaster()非阻塞连接主节点。connectWithMaster()函数执行的操作可以总结为:

根据IP和port非阻塞的方式连接主节点,得到主从节点进行通信的文件描述符fd,并保存到从节点服务server.repl_transfer_s中,并且将刚才的REPL_STATE_CONNECT状态设置为REPL_STATE_CONNECTING。 监听fd的可读和可写事件,并且设置事件发生的处理程序syncWithMaster()函数。 至此,主从网络建立就完成了,逐步进入了协商交互阶段,使用的是状态机处理的,

Redis教程:主从复制相关推荐

  1. linux redis客户端_你见过能把Redis的主从复制讲这么明白的吗?

    概念 1.Conception(概念) Redis的复制也就是我们所说的主从复制,主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制,Master以写为主,Slave以读为主 ...

  2. redis设置主从复制-slave Replication--解决报错:(error) READONLY You can't write against a read only slave.

    我的个人博客:zhang0peter的个人博客 主节点按照我上篇文章的内容配好redis后就可以了:ubuntu, debian 安装redis,设置开机自动启动和密码,允许外网访问 在从节点安装好r ...

  3. Redis的主从复制与高可用搭建(哨兵模式)

    前言 为什么要使用Redis 首先我们先介绍些redis的基本概念,redis是Nosql数据库,是一个key-value存储系统.虽然redis是key-value的存储系统,但是redis支持的v ...

  4. Redis:主从复制原理

    1. 前言 Redis是一个高性能的K-V内存数据库.对于Redis来说,当访问读请求的并发量增加的时候,Redis主服务器会成为一个性能瓶颈.为了分担读压力,Redis支持主从复制,Redis的主从 ...

  5. Redis教程:NoSQL键值存储

    课程大纲 Redis是使用ANSI C编写的具有可选持久性的开源,网络化,内存中键值数据存储.根据DB-Engines.com的月度排名,Redis是最受欢迎的键值存储. 它的名字意思是远程字典服务器 ...

  6. redis 持久化 + 主从复制+ 集群

    2019独角兽企业重金招聘Python工程师标准>>> 一. Linux 下的 Redis 安装 && 启动 && 关闭 && 卸载 ...

  7. 今天来聊聊 Redis 的主从复制

    作者 | 阿Q 来源 | 阿Q说代码 今天我们就从配置文件.设计原理.面试真题三个方面来聊一聊 Redis 的主从复制. 在 Redis 复制的基础上,使用和配置主从复制非常简单,能使得从 Redis ...

  8. 关于Redis配置主从复制踩到的坑,主机不显示从机的连接信息

    关于Redis配置主从复制踩到的坑!!! 设置单机集群的时候,两台从机都显示连接到主机,但是主机显示连接到的从机数量为0: 主机信息: 从机80: 从机81: 查看从机log日志文件发现错误信息: M ...

  9. Redis系列-主从复制配置

    Redis虽然有着卓越的性能,但我们仍然可以通过master/slave这种简单架构,进行读写分离,进一步挖掘redis的性能,提高系统的可用性. redis怎么进行主从复制呢?redis复制主要是通 ...

  10. 【重难点】【Redis 02】Redis 的持久化、Redis 的主从复制和集群、哨兵

    [重难点][Redis 02]Redis 的持久化.Redis 的主从复制和集群.哨兵 文章目录 [重难点][Redis 02]Redis 的持久化.Redis 的主从复制和集群.哨兵 一.Redis ...

最新文章

  1. 9种不同的方法帮助你提高国内访问Github的速度!
  2. jvm十三:类加载器命名空间
  3. tomca7.0 mysql配置连接池_tomcat7.0+mysql连接池配置
  4. java发送加密报文_RSA加密---从后台到客户端实现报文加解密
  5. QML基础类型之double
  6. Memcached的配置,SSH项目中的整合(com.whalin),Memcached工具类,Memcached的代码调用
  7. Java将一段逗号分割的字符串转换成一个数组(亲测)
  8. 2修改字段名_DevExpress ASP.NET v18.2新功能详解(二)
  9. js 进阶篇 代码等级提升
  10. mysql网页化_页面化操作数据库
  11. 运行caffe自带的两个简单例子
  12. java 调用php文件上传_php上传文件,接口是java,go。
  13. php 计算数组的差值,数组计算差值及项的小计,该如何处理
  14. 如果第一次见面,投资人就能给创业者提出建设性的意见
  15. html中下拉日历控件,HTML5之日历控件
  16. 自制Flash电子相册
  17. 【Vue脚手架安装教程】
  18. 计算机金融学校排名2015,金融学院2015级各专业排名情况统计表
  19. 静态路由 动态路由 php,静态路由汇总(路由聚合)
  20. JAVA7-6 约分最简分式 (15 分)

热门文章

  1. express : 无法将“express”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。express: command not found
  2. 【数据结构笔记10】二叉树的先序、中序、后序遍历,中序遍历的堆栈/非递归遍历算法,层序遍历,确定一个二叉树,树的同构
  3. 加密算法使用(五):RSA使用全过程
  4. EIGRP MD5认证实例
  5. PyQt Graphics View 一个hello world例子
  6. 接收list参数_Python 犄角旮旯--List
  7. 【微软的VDI】Windows Server 2012 RDS存储相关
  8. 用html css设计网站,HTMLCSS构建和设计网站
  9. Kubernetes的client-go库介绍
  10. PHP异步调用实现方式