如果某个服务器或者程序,只有一个节点(服务器),就会有很大的问题。比如可用不高,并发量也比较低。引入分布式系统,也主要是为了解决上述的单点问题。
Redis,主要部署在分布式系统上。在分布式系统中,往往有多个服务器来部署Redis服务,从而构成一个Redis集群,此时就可以让这个集群给整个分布式系统中其他的服务提供更加稳定、更加高效的数据存储服务。
本文着重介绍:主从模式
目录
主从模式
具体配置
主从结构
拓补结构
数据同步
全量复制
无磁盘模式(diskless)
实时复制
主从模式
在若干个Redis节点中,有“主节点”,有“从节点”,现在假设有三个服务器(三个节点),我们就可以把其中的一个节点作为“主节点”,另外两个作为“从节点”。
主节点可以读数据和写数据,而从节点是主节点的备份,或者叫数据同步于主节点,仅仅支持读操作。用户往往读操作要比写操作更加频繁,所以读操作可以读取任意的节点,大大缓解了主节点的压力。
此时,前面提到的两个问题都一定程度解决了:
- 可用性:如果从节点挂掉了,完全不影响其他的节点,用户仍然能够正常读取数据。但是如果是挂掉了主节点,需要写数据的时候还是会写不了。
- 并发量:用户读操作不再依赖于主节点,可以让不同的用户读取不同的从节点,极大地提高并发量。
具体配置
正常来说,配置Redis主从结构需要启动多个Redis服务器,每个服务器都应该在一个单独的主机上。但是我们手中只有一台云服务器,所以我们就在这一台云主机上面,运行多个redis-server进程。
我们把主节点的端口设置成6379(默认),把另外两个从节点的端口设置成6380和6381。
先把redis.conf这个文件复制两份,分别改名为slave1.conf和slave2.conf,再分别进入配置文件,修改端口号和主从结构配置。
通过配置文件把redis客户端启动。
主节点和从节点之间,通过127.0.0.1连接起来了。
验证实际的效果,主节点的数据变化,可以在从节点上看到。
这样,在一个云服务器上启动多个redis服务器的操作就完成了。但是这种方式并不是实际工作中的方式,本意是为了在多个主机上部署,利用多个硬件资源。
服务器的配置文件修改完之后,需要重新启动才能生效。如果通过kill -9这样的方式,redis-server会自动重启;而如果使用service redis-server start这种方式启动的服务器,就必须使用service redis-server stop来停止。
服务器很多时候为了保证稳定性和高可用,很多时候通过一些手段可以自动重启进程,对于整体的服务不会产生严重的影响。
主从结构
当我们建立起了连接后,通过
slaveof no one
这个命令可以直接让从节点断开主从关系,并且里面的数据是不会清除的。但是后续主节点如果针对数据做出修改,这个从节点是不能自动同步的。
假设我们让6381这个节点断开主从关系了,再通过
slaveof 127.0.0.1 6380
可以让6380作为6381的主节点,原来的主从结构就被改变了。
此时6380看起来是一个主节点,但它仍然不能写数据,只能通过6379来获取数据,同步给6381。
此处的修改是临时性的,因为并没有修改配置文件。如果重启了redis服务器,仍然会按照配置文件里的内容建立主从关系。
拓补结构
指的是各个节点之间,按照什么样的方式来进行组织连接。
如果写数据太多,就会给主节点造成太多压力,可以通过关闭主节点的AOF,只在从节点上开启AOF。但是这种方式有一个严重的缺陷:主节点一旦出现故障,不能让它自动重启。因为没有AOF文件,会丢失很多数据,一旦进行主从同步会把从节点的数据也删了。
改进办法:当主节点挂了之后,就需要让从节点从主节点这里获取到AOF文件,再启动。
实际开发中,读请求是远远超过写的请求。
如果采用如下主从结构,会导致主节点一份数据要同步很多次,对网络的要求非常高:
采用如下的方式,主节点就不需要那么高的网络带宽了,但是一旦数据进行修改,同步的延迟是比刚才更大的。
复制的过程并不复杂,但是有很多细节,对于一个从节点来说:
- 保存主节点信息:保存主节点的ip和端口
- 主从建立连接:TCP的连接(三次握手)
- 发送ping命令:验证主节点是否工作
- 权限验证:主节点是否有密码等
- 同步数据集
- 命令持续复制
第五步和第六步就是最关键的操作了~
数据同步
Redis提供了psync命令,完成数据同步。并且这个命令不需要我们手动执行,redis服务器会在建立好主从关系之后,自动执行psync。
psync可以从主节点获取全量数据,也可以获取一部分数据。通过info rellication可以查询到很多的信息。
offset就是偏移量,主节点和从节点都会维护偏移量。对于主节点来说,主节点上会收到很多修改操作的命令,每个命令都要占用几个字节,主节点会统计这些命令,最终生成一个offset。
从节点的偏移量描述了,现在数据同步到哪里了,如果从节点偏移量和主节点一样了,就说明主从节点数据完成同步了。
psycn带有具体的replid和offset值,主节点会根据这些参数判断适合全量复制还是部分复制。
进行全量复制:
- 首次和主节点进行数据同步
- 主节点不方便进行部分复制的时候
进行部分复制:
- 之前进行过数据复制,但是因为网络抖动或者服务器重启了
- 从节点需要同步数据的时候,大部分数据都是一致的
全量复制
- 从节点发送psync命令给主节点进行数据同步,由于是第一次复制,从节点没有主节点的运行ID和数据偏移量,所以发送 psync ? -1
- 主节点根据命令,解析出要进行全量复制,回复 +FLUURESYNC响应
- 从节点接收主节点的运行信息进行保存
- 主节点执行bgsave进行RDB文件的保存
- 主节点发送RDB文件给从节点,从节点保存RDB数据到本地硬盘
- 主节点把从生成RDB文件到接受完成期间执行的写命令,写入缓冲区,等从节点保存完RDB文件后,主节点再将缓冲区里面的数据补发给从节点。补发的数据仍然按照RDB的二进制格式追加写入到RDB文件中,保持主从一致性
- 从节点清空自身原有数据
- 从节点加载RDB文件得到与主节点一样的数据
- 如果从节点加载完RDB之后,开启了AOF持久化功能,会进行 bgrewriteof 操作,得到最近的AOF文件
在主节点生成RDB文件和传输RDB文件的过程中,会受到很多新的操作,新修改的数据必须也要同步给从节点。当主节点把RDB文件发过去之后,主节点就会把这些新的操作也发给从节点。
无磁盘模式(diskless)
主节点生成的RDB二进制数据,直接进行网络传输发给从节点,就不需要保存到本地磁盘了,可以省下一系列的读写硬盘操作。
从节点也可以直接把接收到的RDB数据,直接进行加载,无需存储到硬盘中。
但是即使引入了无硬盘模式,整个操作的消耗资源量仍然是很大的,特别是网络带宽的压力仍然很大。
实时复制
从节点已经和主节点同步好了数据,但是主节点会源源不断的收到新的数据,也需要把这些新的数据同步给节点。于是主从节点之间就会建立TCP长连接,主节点通过这个连接发给从节点。
在进行实时复制的时候,需要保证连接时刻处于可用状态,于是引入了心跳包机制。主节点默认每隔10s就给从节点发送一个ping命令,从节点收到后就返回pong。从节点默认每隔1s就给主节点发起一个特定的请求,就会上报当前从节点复制数据的进度,也就是offset偏移量。
到此,很多问题都可以通过主从模式来解决,但是如果主服务器真的挂了,我们不可能时时刻刻都盯着他,然后自己手动重启。于是Redis有哨兵来解决这个问题,下一篇文章,我们来讲讲哨兵~