Redis专题(六) ——Redis高可用(复制篇)
(原创内容,转载请注明来源,谢谢)
一、单台服务器
单台redis服务器,会出现单点故障,且需要承受所有的负载。另外,所有的内容都存在单个服务器上,该服务器会成为瓶颈。
使用多台服务器作为redis服务器,需要考虑集群管理,如数据一致性、增加节点、故障恢复等问题。redis对处理这些问题有一套方案。
二、复制
redis的持久化功能保证了数据的持久性,但是如果服务器故障,数据还是可能会丢失,因此需要将数据备份到其他服务器。当一台服务器内容更新,会通知其他服务器进行备份。
多台服务器使用redis时,有主数据库、从数据库的概念。通常主数据库是读写(或只有写操作),从数据库都是只读。主数据库数据的变化会通知从库,让从库进行更新。
1、命令
1)redis配置从数据库,只需要在从数据库配置文件中加入命令:slave of 主库ip 主库端口。该命令可以在开启数据库的时候使用,也可以在运行期间使用。
2)主数据库无需任何配置。
3)查看数据库的从库/主库命令:INFOreplication,该命令返回当前库的角色(master/slave),对于主库还可以看到从库的数量、每个从库的ip与端口、当前连接开启的从库数量,对于从库可以看到主库的ip和端口。
2、注意事项
如果当前数据库已经是某个数据库的从库,再输入slave of 新主库,则会断开和当前主库的连接,并成为新主库的从库,且同步新主库的数据(如果现有数据新的主库也有,会被覆盖)。
运行期间输入slaveof no one命令,使当前数据库与主库断开连接,并且自己成为主库。
3、原理
a. 复制初始化:
1)从数据库启动后,给主库发送sync命令。
2)主库接到命令后,会开始对当前数据保存快照(RDB持久化),且对保存期间客户端发送的写命令进行缓存。保存完毕后,将保存文件和缓存的写命令一起发给从数据库。
3)从数据库收到后,会还原快照,并且执行缓存命令。
复制初始化后,主数据库每当收到写命令,都会发送给从数据库。
断开连接后重连时,2.8之前的redis版本会重新进行一遍复制初始化;2.8开始的版本可以进行增量初始化,加快初始化速度。
b. 协议角度分析复制初始化:
1)从库使用命令连接主库,如果需要输入密码则还要和主库发送auth验证。
2)从库使用replconflistening-port 端口号告诉主库当前监听的端口号。
3)向主库发送sync命令开始同步。主库发送回快照文件和缓存命令,从库收到后写入硬盘的临时文件中。
4)写入完成后,从库会使用该rdb文件替换当前rdb文件。
5)在同步过程中,从库不会阻塞,可以接收客户端的命令。默认情况下,同步还没完成时,会用同步前的数据响应客户端。也可以通过配置文件slave-server-stable-data=no,强制要求同步完成后才可以提供服务,则此时同步期间收到客户端的请求会报错。
6)复制完成后,主数据库的任何写操作,从数据库都会收到异步的命令,并且去执行。
c. 乐观复制
redis采用乐观复制的策略,容忍一定时间内的数据差异,最终数据是一致的。
当主库收到写命令,会立即写完并反馈给客户端,再异步地向从数据库发送命令告知同步,因此存在差异的时间端口。可以配置从库至少连接几个时,主库才可写,通过配置文件的命令min-slaves-to-write。
4、图结构
从数据库不仅可以作为主库的从库,也可以作为其他从数据库的主库。
上图中A变化会同步给B和C,B变化会同步给D和E,但不会同步给A和C。
5、读写分离优势
正常的业务场景中,都是大量的读操作(远大于写操作),甚至带上计算(如sort)等场景,单个服务器很难应付,这是多个数据库的优势,保证主库仅进行写操作和同步数据,从库进行读操作,可以把工作量平均分配给从数据库。
6、从库持久化
持久化比较耗时,当有主从结构时,通常设置主库禁止持久化,由从库进行持久化操作。当主库奔溃时,使用以下方式进行还原:
1)将进行持久化的某台从库服务器,执行slave of no one,使其变成主库。
2)将重新恢复正常后的原主库,执行slave of 步骤1的从库,使其变成原从库的从库。
3)注意事项
主库设置关闭持久化后,一定要同时关闭自动重启功能。因为其没有持久化数据,关闭(无论正常还是异常关闭)后数据全部清空,如果此时自动重启,则所有的从库会同步数据,所有的数据都被清空。
7、无硬盘复制
使用rdb复制,简化逻辑,代码易复用,但是有以下缺点:
1)无法确定主库恢复数据的时间,因为快照的复制时间不确定。
2)复制初始化要在硬盘创建文件,如果硬盘性能差则会很慢(如网络硬盘)。
因此,redis2.8开始的版本,允许主库通过配置文件开启无硬盘复制,即对从库进行复制初始化时,直接通过网络传输给从库,而不是在主库的本地先生成rdb文件,再传输rdb。命令是repl-diskless-sync yes
8、增量复制
a. 当从库断开重连,如果要全量复制,速度较慢。从redis2.8开始,支持增量复制。增量复制如下步骤:
1)从库存储主库的运行id(run id),每个redis实例有唯一运行id,重启后id会变。
2)复制过程中,主库把命令传给从库,并把命令存到挤压队列(backlog)中,记录当前挤压队列存放命令的偏移量。
3)从库接收到主库的命令后,会记录偏移量。
4)从库准备就绪后,从redis2.8开始,不再发送sync,而是发送psync 主库运行id断开前最新偏移量。
b. 主库收到psync后,会进行以下判断确定是否进行增量复制;
1)首先判断运行id是否正确,例如主库重启过则id会是新的。如果运行id不正确,则进行全量复制。
2)判断从库最后同步成功的命令是否在挤压队列中,在的话则可以进行增量复制,否则全量复制。
c. 挤压队列:
挤压队列本质是固定长度序列,大小为1MB,挤压队列越大,则允许断开的时间越长。通过repl-backlog-size设置挤压队列大小,通过repl-backlog-ttl设置全部从库断开连接后挤压队列释放的时间。
——written by linhxx 2017.08.11