Redis系统一般以"一主多从"的形式部署,以实现数据库读写分离,提高系统的容错性和降低单个Redis实例的负载压力。主数据库一般具有读和写的权限,而从数据库只有读权限。为了保证主从数据库数据的一致性,Redis提供了复制功能,使得主数据库中的数据向从数据库中同步。
Redis中实现主从数据库部署很简单,下面提供一个测试案例:
在同一台服务器上分别开启两个数据库实例,端口号分别是6379和6380,前者作为主数据库,而后者作为前者的从数据库。具体步骤如下:
- 执行redis-server --port 6379 //启动主数据库实例
- 执行redis-server --port 6380 --slaveof 127.0.0.1 6379 //启动从数据库
- 分别开启二者客户端,执行INFO replication命令,查看二者复制节点的信息
从复制节点的信息中可以看出,6380端口的数据库实例已经成功作为6379端口数据库实例的从数据库。
此时,在主数据库执行写入操作,在从数据库中就可以读取相应的数据了。
启用主从复制的过程并不复杂,但是如果不了解其原理,在需要数据库恢复和数据迁移的情况下,运维就变得十分艰难。下面我们就来探讨一下Redis主从复制的实现原理:
Redis复制的过程可以理解为三个阶段:
- 复制初始化阶段
复制初始化阶段是一个从数据库初次启动时与主数据库进行数据同步的阶段,当一个从数据库启动时会向主数据库发送SYNC命令,而主数据接收到SYNC命令后,会在后台异步地执行一次快照动作(RDB持久化),并将保存快照期接收到的命令缓存起来。当快照完成后,主数据库会将快照文件以及缓存的命令一并发送给从数据库,从数据库接收到后会载入快照中的数据并执行缓存中的命令。至此,主数据库与从数据之间完成了一次数据同步,这个过程就称为复制初始化阶段。
- 复制同步阶段
当复制初始化完成后,主数据库每当执行一条会改变内存数据的命令,都会将该命令异步地发送给从数据库,这个过程就称为复制同步阶段。复制同步阶段贯穿了整个主从同步过程的始终,直到主从关系终止为止。
- 从数据库断线重连
当从数据库与主数据库断开重连后,在Redis2.6及之前的版本采取的做法是重新进行复制初始化,即主数据库重新保存快照执行一次完整地复制动作。然而,在从数据库断线期间,主数据有可能没有执行写命令,或者主数据库中数据的变化很少,这种情况下从数据库重连后的数据恢复过程就变得十分冗余和低效,在网络环境不好的时候这一问题尤为突出。
Redis2.8版本的一个重大改进就是:断线重连能够支持有条件的增量数据传输,当从数据库重新连接上主数据库后,主数据库只需要将断线期间进执行的命令传送给从数据库即可,从而大大地提高了Redis复制的实用性。增量复制的实现原理本篇文章将不作出介绍,感兴趣的小伙伴可以自己去查阅相关资料。
上述就是Redis主从复制的整个流程,下面继续介绍复制过程中的两个细节知识点:
- 无硬盘复制
在复制初始化阶段,从数据库初次启动时会向主数据发送SYNC命令触发其执行一次RDB持久化,这种方式虽然实现简单,但是会存在以下两个问题:
1、生产环境中有时候为了提高性能,会禁用主数据库的RDB快照功能。这是如果进行复制初始化,主数据库还是会生成RDB快照文件,这个快照文件中存储的就是进行复制初始化这一时间点的内存数据,而主数据下次启动时,会将该RDB文件载入到内存中,这使得恢复的数据就是上次复制初始化时间点的数据,这显然是不符合要求的。
2、由于复制初始化阶段需要在硬盘中生成RDB文件,假若硬盘性能很慢时这一过程就会对复制性能产生影响,尤其是在一主多从架构中,每当新增一个从数据库节点都需要主数据库执行一个RDB持久化动作,对硬盘的读写导致效率降低。
基于上述两个问题,从Redis2.8.18版本开始,Redis引入了无硬盘复制选项,开启该选项时,主数据进行复制初始化过程中不会将快照内存持久化到硬盘中,而是通过网络发送给从数据库,从而避免了硬盘的性能瓶颈。在配置文件中通过设置repl-diskless-sync yes开启无硬盘复制功能。
- 乐观复制策略
Redis采用了乐观复制(optimistic replication)的复制策略,即允许主从数据库的内容在一定时间内是不一致的,但二者的数据最终是同步的。简单来说,主从数据库之间的复制本身就是异步的,当主数据库执行一条来自客户端的写命令时,会立即将该命令在主数据库的执行结果返回给客户端,并异步地将该命令传送给从数据库,而不是等到命令传送给从数据库后在响应客户端,这一特性保证了启用主从复制功能后,主数据库的性能不受影响,但另一方面会产生主从数据库内容不一致的时间窗口。
Redis提供了两个配置选项来限制:只有当数据至少同步给了指定数量的从数据库时,主数据库才是可写的:
min-slaves-to-write 3 //只有3个或三个以上的从数据库连接到主数据时,主数据库才是可写的,否则返回错误
min-slaves-max-lag 10 //表示允许从数据库最长失去连接的时间,如果从数据库最后与主数据库连接的时间小于这个阈值,则
//认为从数据库与主数据库还保持着连接
Ending ....