赞
踩
目录
谈到分布式系统,涉及到一个关键问题:单点问题
如果一个服务器只有一个节点(只用一个物理服务器部署整个程序),那么出现以下问题:
因此引入分布式系统,主要也是为了解决上述的单点问题~ 分布式系统中,往往需要多个服务器来部署 redis 服务,从而构成 redis 集群,此时就可以让这个集群给整个分布式系统中的其他服务,提供更稳定 / 更高效的数据存储功能.
本章主要来讲一下 redis 部署方式中的主从模式.
Ps:本章节相关操作不需要记忆!后续工作中如果用到了能查到即可. 重点理解流程和原理.
重点:为什么引入主从模式?什么是主从模式(由简到详)?主从模式有哪些结构?主从模式是如何同步数据的?实时复制时的心跳包机制?
在 redis 主从模式下,由一个主节点和多个从节点构成(所谓一山不能容二虎),从节点通过复制主节点得到,并且后续主节点数据发生变化,从节点也必须 “听” 主节点的(从节点的数据跟随主节点一起变化,保持一致) .
如果我修改了从节点的数据呢?redis 主从模式中,从节点上的数据不允许修改,只能读取数据,而主节点既可以进行 “写操作” 也可以进行 “读操作” ~ 为什么这么搞呢?实际上更准确的说,主从模式,主要是针对 “读操作” 进行 并发量 & 可用性 的提高,因为实际的业务场景中,读操作往往比写操作更频繁~
如果节点挂了怎么办?
如果是挂掉了某一个从节点,没什么影响,此时继续从主节点或者其他从节点读取数据,效果是完全一样的.
如果改掉的是主节点,是有一定影响的,因为主节点还负责 “写数据” .
这样结构的好处?
由于从节点的数据和主节点时刻保持一致,因此其他客户端从从节点这里读取数据,和主节点这里读取数据是没区别的! 如果后续有客户端来读取数据,就可以从节点中随便挑一个,来读取数据,引入更多的资源,支持的并发量也就大大提高了~
举个例子?
从节点就像是刚到公司的实习生,是不能在没有熟悉业务和文档的前提下去干活的,因此刚来的实习生任务只有一个,就是熟悉业务(读操作),而你的导师就像主节点,只能有一个,他的工作就是完成自己需求(写操作,读操作),并且他来告诉你你要去读什么文档、熟悉什么业务(从节点通过复制主节点得到).
配置 redis 主从结构,需要启动多个 redis 服务器,分配在一个个单独的主机上(分布式),但是考虑到我们目前每个人,大概只有一个云服务器,因此就来实现一下,在一个云服务器主机上,运行多个 redis-server 进程~
本来 redis-server 的端口是 6379 ,此时就不能让其他节点启动时也用 6379 了,我们有一下两种方式来指定 redis-server 的端口号:
假设我要配置一个主节点和两个从节点,步骤如下:
主节点的配置不变,只需要修改从节点的配置即可,因此我们只需要复制两份主节点的配置文件,并修改这两份文件的端口和后台运行方式即可.
在两个配置文件末尾加 slaveof 配置主从结构(绑定父节点为 6379 端口).
通过 redis-server 命令来启动刚刚配置好的这两个节点.
Ps:如果 redis 服务启动后修改了配置文件就需要重启才能起效。
1.如果是通过 redis-server 启动服务器,就必须搭配 kill 命令来停止.
2.如果是通过 service redis-server start 启动服务器,必须搭配 service redis-server stop 来停止.
3.如果使用 kill 命令停止 service redis-server start ,这个 redis-server 进程会自动启动.
通过 netstat -anp 命令就可以查看从节点和主节点的绑定情况
在复制两个会话,启动两个从节点的 redis 客户端,此时 redis 从节点上就只能读数据,不能写入数据了
在 redis 客户端,通过 info replication 就可以查看当前节点的复制状态了.
(这里简单看一下,后面有详细介绍~)
值得注意的是,从节点和主节点之间的数据同步,不是瞬间完成的,并且同时主节点上也会 “源源不断” 的收到其他 “修改数据” 的请求,因此这个时候就需要使用 offset 来记录当前主节点和从节点的数据同步情况,当 从节点 的 offset 等于 主节点的 offset 时,表明此时数据完全一致.
在当前从节点的 redis 客户端中使用 slaveof no one 可以断开现有的主从复制关系,并且自身成为新的主节点~
Ps:这里从节点断开复制后并不会抛弃原有数据,只是无法再获取主节点上的数据变化,这就像是你是一个土匪,加入了别人的帮派,几年以后,感觉自己学了不少东西,于是就脱离了现在的帮派,自己出来占山为王~
通过 slaveof 命令还可以实现切主操作,将当前从节点的数据源切换到另⼀个主节点,并且切换后会先删除当前节点的所有数据,再复制新的主节点数据。执行 slaveof {newMasterIp} {newMasterPort} 命令即可。
例如将端口号为 6381 从节点的 “主”,换成 端口号为 6380,如下
Ps:此处的修改是临时的,如果重启 redis 服务器,就会按照最初再配置文件中设置的内容来建立主从关系.
默认情况下,从节点使⽤ slave-read-only=yes 配置为只读模式。由于复制只能从主节点到从节 点,对于从节点的任何修改主节点都⽆法感知,修改从节点会造成主从数据不⼀致。所以建议线上不 要修改从节点的只读模式。
TCP 内部支持 naqle 算法,目的就是为了节省网络带宽(目的和 tcp 的捎带应答一样,针对小的 tcp 数据报,就多攒点,攒够了再发,这样就减少了发送的次数)。通过 repl-disable-tcp-nodelay 这个选项就可以进行配置 naqle 算法是否开启.
值得注意的是,实际的工作中,需要根据实际场景来决定是否开启:
一般游戏开发,或者是视频直播,这种即时性要求特别强的,就像需要关闭 naqle 算法.
拓扑结果就描述了若干个节点之间,按照什么样的方式进行组织连接的.
这种结构有一个特点,就是当写请求的数据太多的时候,也会给主节点带来压力,可以通过关闭主节点的 AOF ,只在从节点上开启 AOF 来分担持久化压力,避免影响性能。
但是这种设定方式有一个缺陷,就是主节点一旦挂了,就不能让他自动重启,如果自动重启,此时没有 AOF 文件就会丢失数据,进一步的同步到从节点上,就会把 从节点的数据也给搞丢了.
改进的办法就是当主节点挂了以后,让主节点从从节点这里获取 AOF 文件再启动.
实际的开发中,读请求 远远超过 写请求,也难辞上述的 一主一从结构就有点难以应对了,就需要接下来的一主多从结构来支持
这种结构就是适合有大量到 读请求 场景,帮助主节点分担大部分的 读请求 压力, 但实际随着从节点个数的增加,向主节点中写入一条数据,就需要同步给多个从节点,反而影响性能.
为了解决这个问题,就需要引入树形主从~
这种结构,从节点也可以将其他从节点当作主节点,分担了主节点将数据同步到从节点上的压力,但是一旦数据进行修改,同步的延时是要比刚才更长的.
Redis 使用 psync 命令完成主从数据同步,从节点会自动执行 psync,也就是从节点会去主节点这边拉取数据.
psync replicationid offset
这个命令主要就是要理解两个参数:replicationid 、offset.
replication id 就表示要从那个主节点上获取数据.
replication id 是由主节点生成的,生成的时机是在,主节点启动的时候会生成(同一主节点,每次重启,生成的 replication id 都是不同的),从节点晋升为主节点的时候也会生成。
当从节点和主节点建立了复制关系,就会从主节点这边拉取到 replication id.
通过 info replication 可以获取到当前 replication id 的值.
这里还可以看到 replid2,但是一般是用不上的,有一个情况就是假设有两个节点,主节点 A 和 从节点 B,如果 A 和 B 通信的过程中出现了网络抖动,B 可能就认为 A 挂了,就会把 replid 的值交给 replid2,然后 B 就会自己成为主节点,给自己生成一个 replid,此时,B 也会记得之前的主节点 A 的 replid,就是现在的 replid2。
等后续网络稳定了,B 还可以根据 replid2 重新回到 A 的怀抱中~(这里需要手动干预,但是哨兵机制可以自动完成)
打个比方
这就好比你在一个公司干的挺好的,但是公司有一天突然倒闭了,于是就出来自己创业,但是创业的途中你还和之前公司的老板保持很好的关系,突然有一天,原来的公司重新建立起来了,你就通过保持那层关系,回到了之前的那个公司的怀抱~
从节点和主节点之间的数据同步,不是瞬间完成的,并且在复制数据的同时,主节点上也会 “源源不断” 的收到其他 “修改数据” 的请求,那么从节点怎么知道数据已经同步到哪里了呢?
在 psync 命令中,offset 有两种写法:
打个比方
这就像是一个学习的过程,老师在课堂上讲课是一个进度,你下来自己巩固老师讲课的内容,是另一个进度,当你完善巩固赶上的老师进度以后,你的知识储备也就差不多和老师讲的大差不差了~
那么什么时候进行全量复制,什么时候进行部分复制呢?
Ps:除了上述讲到的全量复制,主节点进行全量复制的时候,也支持 “无硬盘模式”(diskless). 主节点生成的 rdb 文件不会直接保存到文件中了,而是直接进行网络传输,接着从节点也将收到的数据直接进行加载了,这样主节点和从节点省下来一系列读写硬盘的操作.
即使引入了无硬盘模式,整个操作还是比较重量的,比骄耗时的,因为网络传输是没法省的,相比于网络传输,读写硬盘就是小头,因为涉及到网络传输,就离不开封装和分用的过程...
从节点和主节点数据同步完成了(也就是说这一刻,从节点和主节点数据一致了),但是之后,主节点这边也会 “源源不断” 的收到新的 “写请求” ,主节点上的数据就会随之改变,这种改变也需要能够同步给从节点.
此时,从节点和主节点之间会建立 TCP 长连接,然后主节点把自己收到的 “写请求” 修改的数据,发给从节点,从节点再修改自己内存中的数据.
Ps:这个过程也是需要时间的,正常来说,延时是比较短的,但是如果是多级从节点的树形结构,延时就会上升了.
进行实时复制的时候,需要保证连接处于可用状态,因此引入了心跳包机制.
主节点:默认,每隔 10s 给从节点发送一个 ping 命令,从节点收到就会返回 pong.
从节点:默认,每隔 1s 就给主节点发起一个特定的请求,就会上报当前从节点的复制数据的进度(offset).
如果主节点发现从节点通信延迟超过 repl-timeout 配置的值(默认 60 秒),则判定从节点下线,断 开复制客⼾端连接。从节点恢复连接后,⼼跳机制继续进⾏。
Ps:这里的 10s,1s,60s 数值都不要去背,因为都是可以修改的,需要我们去结合实际场景合理分配.
网上有很多资料都会将 run id 和 replication id 混着说,实际上,一个 redis 服务器上 ,replication id 和 run id 都是存在的, runid 主要是用来支撑实现 redis 哨兵功能的,和主从复制没有什么关系.
replid 和 offset 共同标识了一个数据集合.
刚刚所讲的主从配置实际上是有问题的,因为最开始创建从节点的配置文件没有改 appendfilename 属性,导致生成的 aof 文件路径/文件名 都是同一个, 如下图
-rw- 就表示 root 用户可读可写,而 r--r-- 就表示这个文件除了 root 意外的用户,只有读权限,又因为 service redis-server start 启动 redis 服务器是通过 redis 这样的用户来启动的(防止权限过高,redis 被黑客攻破),所以其他节点使用 service redis-server start 启动 redis 服务器无法打开这个文件,就启动失败了,如何解决呢?
解决方案:把三个 redis 服务器生成的文件,也区分开,最靠谱的办法就是,直接把三个 redis 服务器的 工作目录 分开(修改 配置文件 中的 dir 选项)
步骤如下:
chown redis:redis appendonly.aof
码字不易~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。