互联网三高架构
- 高并发
- 高性能
- 高可用
高可用H.A.(High Availability):指的是通过尽量缩短因日常维护操作(计划)和突发的系统崩溃(非计划)所导致的停机时间,以提高系统和应用的可用性。
比如一年有三次宕机,宕机时间分别是:4小时27分15秒,11分36秒,2分16秒。
则3此总和为866467秒。
1年= 3652460*60 = 31536000秒
可用性= 31536000-866467 / 31536000 * 100% = 97.252%
可用性就是97.252%,业界的目标可用性是5个9,也就是99.999%,即服务器宕机时间低于315秒。
Redis是否高可用?
那单点Redis是否可以高可用?
从机器故障上来看,硬盘故障,系统崩溃都会导致数据丢失,很可能对业务咋熬成灾难性打击。
从容量瓶颈上来看,内存不足,也要无限升级内存。也会导致硬件跟不上。
从上面Redis来看,有必要避免Redis服务器故障,准备多个服务器联通,然后将数据复制多个副本保存在不同的服务器上,保证同步。这样即使有一台服务器宕机,其他服务器依然可以继续提供服务,实现Redis的高可用,同时实现数据的冗余备份。这样的形式就会表现的比较好。
数据库主服务器叫:master,从服务器叫slave。这样master数据复制到slave端中。也就解决了数据同步的问题。这种就叫做主从复制,即master中的数据及时,有效的复制到slave中。
高可用集群
如果master出现问题,我们可以将其中的一个slave作为mater,或者我们让slave额外当做mater。通过这样,我们增加了slave,就可以提高集群的负载能力。
上面只是其中可以想到的,可能会出现问题。
总结
我们再来总结一下主从复制的作用。
- 读写分离:mater写,slave读,提高服务器的读写负载能力。
- 负载均衡:基于主从结构,配合读写分离,有slave分担mater负载,根据需求的变化,改变slave的数量,通过多个从结点分担数据取负载,大大提高Redis服务器并发量和吞吐量。
- 故障恢复:当mater出现问题的时候,有slave提供服务,实现故障的恢复。
- 数据冗余:实现数据热备份,是持久化之外的一种数据冗余方式
- 高可用:基于主从复制,构建哨兵模式与集群,实现Redis的高可用。
主从复制的三个阶段
主从复制一共需要哪些工作,才能完成主从复制?
第一,我们需要连接mater和slave。因为mater有多个,slave需要连接mater。
第二,我们需要将mater的数据同步到slave中。
第三,因为我们的mater是不断的接收数据,所以需要将mater中的数据反复的同步到slave。
因此主从复制主要有三个阶段:
1.复制初始化阶段
2.数据同步阶段
3.命令传播阶段
第一阶段:复制初始化
当执行完slaveof masterip port命令后,slave根据指定的masterip和端口向master发起socket连接。
当socket连接建立后,slave向master发送ping确认master是否可用,如果返回pong则表示可用。
如果master设置了密码,则还要做身份验证。
身份验证通过后进入数据同步阶段。
相关命令:
主从复制开启,我们只需要在master的config下
加入slaveof <masterip> <masterport>
即可。
断开:
在从端断开即可
slaveof no one
如果需要授权,也就是加了密码:
master配置文件设置密码指令:
requirepass <password>
slave客户端配置文件设置密码:
masterauth <password>
第二阶段:数据同步
主库和从库都确认对方信息以后,便可开始数据同步,
此时slave向master发送psync2命令(redis 1.0 sync ,redis2.8 psync ,redis 4.0 psync2)
master收到该命令后创建缓冲区,RDB同步数据,且恢复数据。slave端清空数据。这一阶段恢复所有的数据叫做全量复制。
master/slave 复制策略是采用乐观复制,由于bgsave是异步执行的。缓冲区中还有一部分指令没有完成。就需要发送指令到slave结点,slave接收信息,bgrewriteaof恢复数据。这个时候就叫做部分复制。
全量复制:获取发指令之后原来的所有数据。
部分复制:恢复进行rdb过程中进行的所有数据。
在这个阶段我们需要注意的点:
master需要注意:
1.master数据量巨大,应该避免流量高峰期。
2.复制缓冲区大小设定不合理会导致数据溢出。如果全量复制周期太长,进行部分复制时已经存在丢失的情况,必须进行二次全量复制。导致slave陷入死循环。
我们可以通过在master中修改如下变量,默认1mb:
repl-backlog-size 1mb
3.master单机内存占用主机内存的比例不应该过大,建议使用50%-70%的内存,留下30%-50%的内存用于执行bgsave命令和穿件复制缓冲区。
slave需要注意:
1.为了避免slave进行全量复制,部分复制时服务器响应阻塞或数据不同步,建议关闭此期间的对外服务。
slave-serve-state-data yes/no
2.由于master接收rdb文件,带宽容易不足,需要根据业务需求,进行适量错峰。
3.slave过多时,建议调整拓扑结构,由一主多从结构变为树状结构,中间结点既是master,也是slave。注意使用树状结构时候,由于层级深度,导致深度越高的slave与最顶层的master建数据同步延迟较大,数据一致性变差,应该谨慎选择。
部分复制三要素
- master数据状态被修改后,导致主从服务器数据库不一致,此时需要让主从数据同步到一致的状态,同步的动作称为命令传播。
- master将接收到的数据变更命令发送给slave,slave接收命令后执行命令。
如果命令传播阶段出现了断网的情况,我们还需要根据情况来进行全量复制或者部分复制。
如果短时间网络中断,就还需要部分复制。
如果长时间网络中断,只能进行全量复制。
部分复制的三个核心要素:
- 服务器的运行id(run id)
- 主服务器的复制积压缓冲区
- 主从服务器的复制偏移量
服务器的运行id(runid)
runid | |
---|---|
概念 | 服务器运行id时每台服务器每次运行的身份识别码,一台放服务器多次运行可以生成多个运行id。 |
组成 | 运行id由40位字符组成,是一个随机的16进制字符。 |
作用 | 运行id被用于在服务器建进行传输,识别身份。如果两次操作均对同一台服务器进行,必须每次操作携带对应的运行id,用于识别对方。 |
实现方式 | 运行id在每台服务器启动时自动生成,master在首次连接slave时,会将自己的运行id发送给slave,slave保存此id,通过info server命令,可以查看结点的runnid。 |
复制缓冲区
mater通过命令传播来多slave发送命令。
复制缓冲区,又叫复制积压缓冲区,是一个先进先出(FIFO)的队列,用于存储服务器执行过的命令,每次传播命令,master都会讲传播的命令记录下来,并且存储在复制缓冲区。
当master进行set name zhangsan
类似操作的时候,会通过AOF转化为Offset和字节。并且进入缓冲区。
缓冲区内部有偏移量(offset)和字节值组成。通过offset来区分不同的slave当前数据传播的差异。
master和slave都会记录offset。
master记录发送信息对应的offset
slave记录已经接收到额信息对应的offset。
通过比对offset就知道是否同步完成,如果slave断线后,就可以用来恢复数据。
缓冲区什么时候创建的?
每台服务器启动的时候,如果开启有AOF或被连接成为master结点,就创建缓冲区。
主从复制偏移量
通过上面可以知道这个偏移量就是一个数字,用来描述复制缓冲区的指令字节位置。
细化数据同步流程
通过知道部分复制三要素,我们有了更加细化的认识。我们将数据同步流程中的offset和runid加入,更加细化一些。
Slave端:
1.发送指令:
由于slave端不知道runid和offset,所以全量发送。
psync2 ? -1
psync2 <runid> <offset>
Master端:
2.执行bgsave
记录复制偏移量offset到master端。
以便于发送偏移量让slave端知道。
3.发送
+FULLRESYNC runid offset
通过socket发送RDB文件给slave
Slave端:
4.收到
+FULLRESYNC
保存master的runid和offset,
清空全部数据,通过socket接收RDB文件,恢复RDB数据。
至此4步全量复制完成。
Slave端
5.发送命令psync2 runid offset
这个runid和offset就是master端发送过来,slave端保存的offset。
Master端:
6.接收命令,判定runid是否匹配,判定offset是否在复制缓冲区中。
此时比对的是master端的runid和offset和slave端的runid和offset。
7.如果runid或者offset有一个不满足,则执行全量复制。
由于不满足,就不知道增量复制了,所以再次重新进行全量复制。
7.如果runid或者offset校验通过,
master端的offset与slave端的offset相同,忽略
7.如果runid或者offset校验通过,
master端的offset与slave端的offset不相同,
发送
+continue offset
offset:为master端的offset
通过socket发送复制缓冲区中offset到slave offset数据。
Slave端:
8.接收信息+continue,保存master的offset
执行bgrewriteaof,恢复数据
心跳机制
到了传播阶段通过心跳来进行信息交换。保证双方连接在线。
slave心跳:
发送REPLCONF ACK{offset} 命令来获取数据变更。还有一个作用就是判断master是否下线了。这个周期是1秒发一次。
master心跳:
通过ping来判断slave是否在线。 通过info replication命令就可以查询到slave最后一次连接时间的间隔。lag维持在0或者1就是正常的。
redis提供了一个配置项来限制只有数据至少同步给多少个slave的时候,master才是可写的。
我们可以通过两个参数:
min-slaves-to-write 3 表示只有当3个或以上的slave连接到master,master才是可写的
min-slaves-max-lag 10 表示允许slave最长失去连接的时间,如果10秒还没收到slave的响应,则master认为该
slave以断开
slave数量和延由replconf ack命令作确认。
命令传播阶段的offset策略和部分复制策略是相同的。也会进行全量复制。
只不过发送指令同步阶段为psync2而传播阶段为replconf ack offset。
常见问题:
master cpu占用过高或者slace频繁断开连接
通过设置合理的超时后减,确认是否释放slave。
repl-timeout 默认60秒
master与slave连接断开
提高ping指令发送的频度
repl-ping-slave-preiod
repl-time时间至少是ping 指令的5-10倍,否则很容易判定超时。
多个slave获取相同数据不同步
监控主从结点延迟判断,如果slave延迟过大,暂时屏蔽程序对该slave的数据访问。
slave-serve-stale-data yes/no
开启后仅相应info ,slaveof等少数命令(慎用,除非对数据一致性要求很高)
搭建:
在同一个结点里面搭建
主节点:6379
从节点:6380
主配置文件6379.conf
port 6379
pidfile /var/run/redis_6379.pid
# slaveof <masterip> <masterport>
logfile "6379.log"
requirepass 123456
daemonize yes
bind 0.0.0.0
masterauth 123456
从配置文件6380
port 6380
pidfile /var/run/redis_6380.pid
# 主服务器IP redis5.0以下 slaveof 127.0.0.1 6379
replicaof 127.0.0.1 6379
logfile "6380.log"
requirepass 123456
daemonize yes
bind 0.0.0.0
masterauth 123456
# 设置只读
replica‐read‐only yes
进入控制台:
-p 端口号 -a 用户密码
./redis-cli -p 6380 -a 123456
是否成功:
查看info
master中会显示:
也可以实时连接主从复制:
redis-server --port 6380 --replicaof 127.0.0.16379
实时取消:
取消复制
REPLICAOF no one
服务器在停止复制之后不会清空数据库,而是会继续保留复制产生的所有数据。