redis主从复制过程
redis
Redis使用异步复制,当配置好slave后,slave与master创建链接,而后发送sync命令。不管是第一次链接仍是从新链接,master都会启动一个后台进程,将 数据库快照保存到文件中,同时master主进程会开始收集新的写命令并缓存。后台进程完成写文件后,master就发送文件给slave,slave将 文件保存到硬盘上,再加载到内存中,接着master就会把缓存的命令转发给slave,后续master将收到的写命令发送给slave。数据库
若是master同时收到多个slave发来的同步链接命令,master只会启动一个进程来写数据库镜像,而后发送给全部的slave。master同步数据时是非阻塞式的,能够接收用户的读写请求。然而在slave端是阻塞模式的,slave在同步master数据时,并不可以响应客户端的查询。从服务器会周期性的应答从复制流中处理的数据量。缓存
能够一主多从,从服务器是只读的(安全
从Redis 2.6开始,从服务器支持只读模式,而且是默认模式。这个行为是由Redis.conf文件中的slave-read-only 参数控制的,能够在运行中经过CONFIG SET来启用或者禁用。从服务器像DEBUG或者CONFIG这样的管理命令仍是能够运行的。不过你能够经过使用rename-command命令来为这些命令更名来增长安全性),主服务器进行读写时,会转移到从读,减轻服务器压力,主从均可以设置密码,也能够密码不一致bash
当主从服务器之间的链接因为某些缘由断开时,从服务器能够自动进行重链接。当有多个从服务器同时请求同步时,主服务器只进行一个后台存储。服务器
从Redis 2.8版本开始,能够配置主服务器链接N个以上从服务器才容许对主服务器进行写操做。可是,由于Redis使用的是异步主从复制,网络
没办法确保从服务器确实收到了要写入的数据,因此仍是有必定的数据丢失的可能性。app
工做原理以下:less
1)从服务器每秒钟ping一次主服务器,确认处理的复制流数量。异步
2)主服务器记住每一个从服务器最近一次ping的时间。
3)用户能够配置最少要有N个服务器有小于M秒的确认延迟。
4)若是有N个以上从服务器,而且确认延迟小于M秒,主服务器接受写操做。
还能够把这看作是CAP原则(一致性,可用性,分区容错性)不严格的一致性实现,虽然不能百分百确保一致性,但至少保证了丢失的数据不会超过M秒内的数据量。
若是条件不知足,主服务器会拒绝写操做并返回一个错误。
1)min-slaves-to-write(最小从服务器数)
2)min-slaves-max-lag(从服务器最大确认延迟)
当链接断开又从新连上以后,通常都会进行一个完整的从新同步,可是从Redis2.8开始,只从新同步一部分也能够。
部分从新同步工做原理是这样:
主服务器端为复制流维护一个内存缓冲区(in-memory backlog)。主从服务器都维护一个复制偏移量(replication offset)和master run id ,
当链接断开时,从服务器会从新链接上主服务器,而后请求继续复制,假如主从服务器的两个master run id相同,而且指定的偏移量在内存缓冲
区中还有效,复制就会从上次中断的点开始继续。若是其中一个条件不知足,就会进行彻底从新同步(在2.8版本以前就是直接进行彻底从新同步)。
由于主运行id不保存在磁盘中,若是从服务器重启了的话就只能进行彻底同步了。
部分从新同步这个新特性内部使用PSYNC命令,旧的实现中使用SYNC命令。Redis2.8版本能够检测出它所链接的服务器是否支持PSYNC命令,不支持的
话使用SYNC命令。
一个彻底从新同步须要在磁盘上建立一个RDB文件,而后加载这个文件以便为从服务器发送数据。
若是使用比较低速的磁盘,这种操做会给主服务器带来较大的压力。Redis从2.8.18版本开始尝试支持无磁盘的复制。
使用这种设置时,子进程直接将RDB经过网络发送给从服务器,不使用磁盘做为中间存储。
使用repl-diskless-sync配置参数来启动无磁盘复制。使用repl-diskless-sync-delay 参数来配置传输开始的延迟时间,以便等待
更多的从服务器链接上来。
配置
我这里是一台机器上多实例配置主从,采用一主三从,经过haproxy作从的分发。
master:6379
slave:6380、638一、6382
haproxy:6378
master
[root@localhost redis]# cat etc/redis6379.conf |grep -v "#"|sed "/^[[:space:]]*$/d" daemonize yes pidfile /var/run/redis_6379.pid port 6379 logfile /app/redis/logs/redis6379.log databases 16 save 900 1 save 300 10 save 60 10000 dbfilename 6379.rdb dir /app/redis/data/ requirepass ywbz@4.117 ...... [root@localhost bin]# ./redis-cli -p 6379 -a ywbz@4.117 127.0.0.1:6379> info ...... # Replication role:master connected_slaves:3 slave0:ip=127.0.0.1,port=6381,state=online,offset=128886182724,lag=0 slave1:ip=127.0.0.1,port=6380,state=online,offset=128886182724,lag=0 slave2:ip=127.0.0.1,port=6382,state=online,offset=128886120626,lag=1 master_replid:9744431b03d430d64ace5aefd18aa54d3d99b317 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:128886182724 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:128885134149 repl_backlog_histlen:1048576 ...... 127.0.0.1:6379> quit [root@localhost bin]#
slave
[root@localhost redis]# cat etc/redis6380.conf |grep -v "#"|sed "/^[[:space:]]*$/d" daemonize yes pidfile /var/run/redis_6380.pid port 6380 logfile /app/redis/logs/redis6380.log databases 16 save 900 1 save 300 10 save 60 10000 dbfilename 6380.rdb dir /app/redis/data/ slaveof 127.0.0.1 6379 masterauth ywbz@4.117 requirepass ywbz@4.117 [root@localhost bin]# ./redis-cli -p 6380 -a ywbz@4.117 127.0.0.1:6380> info ...... # Replication role:slave master_host:127.0.0.1 master_port:6379 master_link_status:up master_last_io_seconds_ago:1 master_sync_in_progress:0 slave_repl_offset:128890251317 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:9744431b03d430d64ace5aefd18aa54d3d99b317 master_replid2:0000000000000000000000000000000000000000 master_repl_offset:128890251317 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:128889202742 repl_backlog_histlen:1048576 ...... 127.0.0.1:6380> quit [root@localhost bin]#