目录
一、单机部署
1、软件准备
2、安装配置
3、启动Redis
二、Redis集群
2.1、主从模式
2.1.1、作用
2.1.2、规划图
2.1.3、具体配置
准备工作
主从配置
启动测试
2.1.4、主从复制原理
主从全量复制
主从增量同步(slave重启或后期数据变化)
2.1.5、缺点
2.2、哨兵模式
2.2.1、作用
2.2.2、规划图
2.2.3、具体配置
修改配置
启动测试
演示自动故障切换
2.2.4、哨兵模式原理
服务状态监控
哨兵选主规则
2.2.5、优点
2.2.6、缺点
2.3、分片集群
2.3.1、作用
2.3.2、规划图
2.3.3、具体配置
启动所有节点
编辑 创建集群
测试
2.3.4、分片集群原理
集群的自动故障切换
集群的失败
2.3.5、优点
2.3.6、缺点
2.4、总结
三、RDB与AOF
1、数据的持久化是怎么实现的?
1.1、RDB
手动生成RDB文件
自动生成RDB文件
RDB的执行原理
优点
缺点
1.2、AOF
优点
缺点
RDB与AOF对比
一、单机部署
1、软件准备
Redis:redis-5.0.5
gcc-c++编译器(其他的C语言编译器也可以):直接使用yum拉取就可以了,最近能用的yum源不是很多,可以去替换一下yum:可用yum源
yum -y install gcc-c++
2、安装配置
cd /usr/redis/redis-5.0.5/
ls
发现没有configure 就需要⾃⼰指定安装⽬录
编译安装(从源⽂件中抽取指令过程)
make
ls /usr/redis
make install PREFIX=/usr/redis
#再次查看
ls /usr/redis
发现多了⼀个bin⽬录 说明安装成功
3、启动Redis
直接演示后台运行方式启动吧
#复制配置⽂件到bin下
cp /usr/redis/redis-5.0.5/redis.conf /usr/redis/bin/
#修改配置⽂件 :136行 daemonize yes
vim /usr/redis/bin/redis.conf
#使⽤配置⽂件启动服务(脚本+参数启动):
/usr/redis/bin/redis-server /usr/redis/bin/redis.conf
#回⻋启动,发现不再占⽤窗⼝
#检查是否启动成功:
ps -ef |grep redis |grep -v grep
#可以看到⼀个redis-server进程在运⾏,标识后台启动成功
#在本窗⼝就可以使⽤redis客户端连接
/usr/redis/bin/redis-cli
#退出客户端
quit
#停止redis-server服务,在客户端里输入
shutdown
就不会出现下面的情况了
二、Redis集群
2.1、主从模式
2.1.1、作用
- 防止单点故障(一台redis宕机,整个redis不能用)
- 可以进行读写分离(一台redis主机进行写操作,其它机子进行读操作),提高使用效率
2.1.2、规划图
2.1.3、具体配置
准备工作
利用之前单机部署的机子,再克隆两台虚拟机,克隆之后记住修改ip地址
主从配置
在redis-1上操作:
cp /usr/redis/redis-5.0.5/redis.conf /usr/redis/bin/master.conf
vim /usr/redis/bin/master.conf
修改master.conf配置文件
:69 bind 192.168.37.161 绑定IP
:92 port 6379 实例端口号
:136 daemonize yes 守护方式运行
在redis-2和redis-3上操作
cp /usr/redis/redis-5.0.5/redis.conf /usr/redis/bin/slave1.conf
vi /usr/redis/bin/slave1.conf
分别修改slave1.conf和slave2.conf
:69 bind 192.168.37.161 绑定IP
:92 port 6379 实例端口号
:136 daemonize yes 守护方式运行
#最后一行添加 slaveof 主节点ip 主节点redis端口号
slaveof 192.168.37.161 6379
启动测试
三台redis服务都启动
#redis-1上执行
/usr/redis/bin/redis-server /usr/redis/bin/master.conf
/usr/redis/bin/redis-cli -h 192.168.37.161 -p 6379
#redis-2上执行
/usr/redis/bin/redis-server /usr/redis/bin/slave1.conf
/usr/redis/bin/redis-cli -h 192.168.37.162 -p 6379
#redis-3上执行
/usr/redis/bin/redis-server /usr/redis/bin/slave2.conf
/usr/redis/bin/redis-cli -h 192.168.37.163 -p 6379
在mater主机(redis-1)上执行写命令。没问题,说明master节点可写,可读
在slave从机(redis-2和redis-3)上执行写命令。有问题,说明slave从节点不能写,只能读
2.1.4、主从复制原理
主从复制
单节点Redis的并发能力是有上限的,要进一步提高Redis的并发能力,就需要搭建主从集群,实现读写分离。
通过执⾏slaveof命令或设置slaveof选项(在Redis 5.0及以后的版本中改名为replicaof),让⼀个服务器去复制另⼀个服务器的数据。主数据库可以进行读写操作,当写操作导致数据变化时会⾃动将数据同步给从数据库。⽽从数据库⼀般是只读的,并接受主数据库同步过来的数据。⼀个主数据库可以拥有多个从数据库,而一个从数据库只能拥有⼀个主数据库。
主从全量复制
第8步之前都是正常的,但是还是不能确定数据是否同步成功,就不如master在生成RDB文件的时候,又接收到了客户端的其它请求,那么刚刚发送过去的RD文件就不是最新的了,其实master在记录RDB文件的过程中,会把新的请求记录在一个日志文件中(repl_baklog),然后再把这个日志文件发送个slave,slave执行完日志文件后,就实现了主从数据的完全同步了
有几个问题:master是怎么判断slave是不是第一次请求?另一个就是日志文件,假如我们后期再次同步的时候,基本上都是从日志文件中记录命令,然后发送给从节点去执行,那么他们是如何确保master和slave同步数据的时候每次都不多不少就是slave需要的那部分数据呐。再引申两个概念Replication Id(简称:replid;数据集的标记)和offset(偏移量),每一个master都会有一个唯一的replid,他的从节点会继承他的replid,当从节点发送数据同步请求的时候,会把自己的replid发送给master,master拿slave的replid和自己的replid进行比较,如果不一样的话,证明这个slave是第一次进行数据同步,然后master把自己的replid发送给slave,然后slave就把这个信息记录到了本地,这个时候他俩的replid就一致了,下面就去执行bgsave进行数据同步,这样我们就清楚slave是不是第一次同步数据了;;;;;;;;如果不是第一次进行数据同步,那么两者的replid是一样的,说明之前是同步过数据的,这个时候master就不会生成RDB文件了,就会根据日志文件去同步数据
那么第23456次去日志文件同步数据的时候,怎么知道同步多少数据呐这就需要第二个概念:offset(自增的整数值)了,,日志文件记录的数据越多,这个offset的值就越大,再主从进行数据同步的时候会携带上offset这个值,假如现在offset记录的值是50,主节点的offset的值是80,这就是这50-80的数据还没有完成同步,同步的时候,master就会把这50-80的部分数据同步给slave就可以了。
主从增量同步(slave重启或后期数据变化)
2.1.5、缺点
无法真正高可用(master一旦宕机,整个集群就无法进行写操作)
所有的写操作都是master进行,写操作无法负载均衡
2.2、哨兵模式
2.2.1、作用
监控:Sentinel会不断检查您的master和slave是否按预期工作
自动故障恢复:如果master故障,Sentinel会将一个slave提升为master。当故障实例恢复后也以新的master为主
通知:Sentinel充当Redis客户端的服务发现来源,当集群发生故障转移时,会将最新消息推给Redis的客户端
2.2.2、规划图
2.2.3、具体配置
修改配置
在三台redis上操作
cp /usr/redis/redis-5.0.5/sentinel.conf /usr/redis/bin/sentinel1.conf
cp /usr/redis/redis-5.0.5/sentinel.conf /usr/redis/bin/sentinel2.conf
cp /usr/redis/redis-5.0.5/sentinel.conf /usr/redis/bin/sentinel3.conf
#分别修改redis1,redis2,redis3哨兵配置文件
vim /usr/redis/bin/sentinel1.conf
vim /usr/redis/bin/sentinel2.conf
vim /usr/redis/bin/sentinel3.conf
#关闭保护模式 当开启保护模式的时候默认只能本机连
protected-mode no #17
#哨兵端口
port 26666 #21
#添加守护进程模式
daemonize yes #26
#添加指明日志文件名
logfile "./temp.log" #36
#修改工作目录
dir "/tmp" #65
#哨兵监控的master名称可以随便起,ip和端口固定 quorum 当哨兵是集群时,有多少个哨兵认为master失效(客观下线),master才算失效。 防止脑裂 配置计算最好是 哨兵总数量/2+1
sentinel monitor mymaster 192.168.37.162 6379 2 #84
#设置master和slaves验证密码
sentinel auth-pass mymaster 123456 #103
#master(默认30秒)不能使用后标记为主观down状态。
sentinel down-after-milliseconds mymaster 30000 #113
启动测试
/usr/redis/bin/redis-sentinel /usr/redis/bin/sentinel1.conf
/usr/redis/bin/redis-sentinel /usr/redis/bin/sentinel2.conf
/usr/redis/bin/redis-sentinel /usr/redis/bin/sentinel3.conf
ps -ef |grep redis|grep -v grep
演示自动故障切换
使用客户端连接3台服务器
/usr/redis/bin/redis-cli -h 192.168.37.161 -p 6379
/usr/redis/bin/redis-cli -h 192.168.37.162 -p 6379
/usr/redis/bin/redis-cli -h 192.168.37.163 -p 6379
显示3台主机的主从状态 ,发现redis1是master ,2和3是slave
info replication
让redis1(master)的实例宕机
等大约30秒 其中两个哨兵都在30连不上,分别认为是主观下线,当3个哨兵相互沟通后,就确定客观下线
shutdown 关闭服务器并保存数据
ps -ef |grep redis|grep -v grep
在redis2和redis3中执行
会发现redis3变成了master,redis2变成了redis3的slave了
info replication
让redis1恢复实例
redis1自动变成redis3的slave
/usr/redis/bin/redis-server /usr/redis/bin/master.conf
/usr/redis/bin/redis-cli -h 192.168.37.161 -p 6379
info replication
当你在redis1宕机期间,在redis3中执行写操作,当redis1实例恢复之后,发现redis1中有宕机期间redis3中写的数据
2.2.4、哨兵模式原理
哨兵发现节点未响应,标记为主观下线;哨兵系统继续监控该节点,等待更多的证据来确认节点的状态;如果多个哨兵也认为节点下线,达到预设的确认阈值,则节点被标记为客观下线;节点被标记为客观下线后,系统会采取进一步的故障处理措施,如故障转移或通知管理员等
服务状态监控
哨兵选主规则
2.2.5、优点
1、保证高可用(除了切换主从的一瞬间,集群是高可用)
2、哨兵监控各个节点
3、自动故障迁移
2.2.6、缺点
主从模式下切换需要时间,切换期间,不能对外提供服务
没有解决master写的压力
2.3、分片集群
2.3.1、作用
主从和哨兵可以解决高可用、高并发的问题。但是依然有两个问题没有解决:
- 海量数据存储问题
- 高并发写得问题
使用分片集群可以解决上述问题,分片集群特征
- 集群中有多个master,每个master保存不同数据
- 每个master都可以有多个slave节点
- master之间通过ping检测彼此健康状态
- 客户端请求可以访问集群任意节点,最终都会被转发到正确节点
2.3.2、规划图
2.3.3、具体配置
在3台redis服务器创建集群目录
mkdir /usr/redis/cluster
ls /usr/redis/
分别在redis1,redis2,redis3执行
mkdir /usr/redis/cluster/8001 /usr/redis/cluster/8002 #redis1执行
mkdir /usr/redis/cluster/8003 /usr/redis/cluster/8004 #redis2执行
mkdir /usr/redis/cluster/8005 /usr/redis/cluster/8006 #redis3执行
redis1上操作,redis2和redis3一样(2和3需要改ip和端口)
#复制配置文件到集群节点目录下
cp /usr/redis/redis-5.0.5/redis.conf /usr/redis/cluster/8001/
#修改配置文件,配置集群 8001和8002都需要修改
vim /usr/redis/cluster/8001/redis.conf
#需要改为其他节点机器可访问的ip 否则创建集群时无法访问对应的端口,无法创建集群 69行
bind 192.168.37.161
#92行
port 8001
#redis后台运行 136行
daemonize yes
#pidfile文件 158行
pidfile /var/run/redis_8001.pid
#aof日志开启 有需要就开启,它会每次写操作都记录一条日志 699行
appendonly yes
#AOF 持久化使用的文件名称 703行
appendfilename "appendonly-8001.aof"
#开启集群 把注释#去掉 832行
cluster-enabled yes
#集群的配置 配置文件首次启动自动生成 840行
cluster-config-file nodes_8001.conf
#请求超时 默认15秒,可自行设置 846行
cluster-node-timeout 15000
启动所有节点
redis1上执行
/usr/redis/bin/redis-server /usr/redis/cluster/8001/redis.conf
/usr/redis/bin/redis-server /usr/redis/cluster/8002/redis.conf
ps -ef |grep redis |grep -v grep #查看是否启动成功
redis2上执行
/usr/redis/bin/redis-server /usr/redis/cluster/8003/redis.conf
/usr/redis/bin/redis-server /usr/redis/cluster/8004/redis.conf
ps -ef |grep redis |grep -v grep #查看是否启动成功
redis3上执行
/usr/redis/bin/redis-server /usr/redis/cluster/8005/redis.conf
/usr/redis/bin/redis-server /usr/redis/cluster/8006/redis.conf
ps -ef |grep redis |grep -v grep #查看是否启动成功
创建集群
/usr/redis/bin/redis-cli --cluster create 192.168.37.161:8001 192.168.37.161:8002 192.168.37.162:8003 192.168.37.162.32:8004 192.168.37.163:8005 192.168.37.163:8006 --cluster-replicas 1
看到这个说明就成功了
测试
/usr/redis/bin/redis-cli -c -h 192.168.37.161 -p 8001
#提供当前集群节点状态信息
cluster info
#获取集群节点配置(显示主从配置信息)
cluster nodes
2.3.4、分片集群原理
Redis分片集群引入了哈希槽的概念,Redis集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽
槽的总数量是16384 在创建集群会按照配置的主节点数量,大概平均分配在不同的节点上
咱的例子是配置的一主一从,主从关系如下myself,master指的是当前登录的节点,咱当前是8001窗口下查看的
主节点 从节点 槽
8001 8004 0-5460
8003 8006 5461-10922
8005 8002 10923-16383
槽和值的关系:
redis中存放数据都是键值对方式进行存储,所有的数据类型存入redis时都有对应的key, 每次向redis写入数据时,redis会根据key的值使用CRC16算法进行计算得到一个数字,再使用该数字对16384取余,余数是几就会把该数据放入该槽中
比如:数据(key-value) 槽 节点
CRC16('aaa')%16384=10439 10439 8003[5461-10922]
CRC16('bbb')%16384=5287 5287 8001[ 0-5460 ]
CRC16('ddd')%16384=11367 5287 8005[ 10923-16383 ]
每次添加数据都会在节点间跳转
集群的自动故障切换
在创建集群时,为了保证集群的高可用,设置了1主1从,实际工作使用过程中,可以设置1主多从,让集群具有更高可用性。平时进行数据读写时都是主节点来执行,从节点使用主从同步,备份主节点数据,当主机点意外宕机,从节点就会自动转换为主节点,当前主节点保存的数据就可以正常的读写。如果主节点恢复,自动变为从节点。
集群的失败
当没有从节点的主节点宕机,集群状态会失败
当超过半数的主节点同时宕机,集群状态会失败
2.3.5、优点
1、无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。
2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
3、可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。 5461=1G
假如1000个节点 16384 一个节点上只放 16.3 槽 数据更均匀的存放不同的服务器,假如该服务器的内存全用来缓存,能缓存的数据会更多
4、高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本
5、实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master 的角色提升。
2.3.6、缺点
1、资源隔离性较差,容易出现相互影响的情况(多个应用同时使用一个redis集群时,可能会出现)。
2、数据通过异步复制,不保证数据的强一致性
3、自动故障切换时,集群状态fail 无法对外提供服务
2.4、总结
Redis提供了三种集群策略:
1. 主从模式:这种模式⽐较简单,主库可以读写,并且会和从库进⾏数据同步,这种模式下,客户端 直接连主库或某个从库,但是但主库或从库宕机后,客户端需要⼿动修改IP,另外,这种模式也⽐ 较难进⾏扩容,整个集群所能存储的数据受到某台机器的内存容量,所以不可能⽀持特⼤数据量
2. 哨兵模式:这种模式在主从的基础上新增了哨兵节点,但主库节点宕机后,哨兵会发现主库节点宕 机,然后在从库中选择⼀个库作为进的主库,另外哨兵也可以做集群,从⽽可以保证但某⼀个哨兵 节点宕机后,还有其他哨兵节点可以继续⼯作,这种模式可以⽐较好的保证Redis集群的⾼可⽤,但 是仍然不能很好的解决Redis的容量上限问题。
3. Cluster模式:Cluster模式是⽤得⽐较多的模式,它⽀持多主多从,这种模式会按照key进⾏槽位的 分配,可以使得不同的key分散到不同的主节点上,利⽤这种模式可以使得整个集群⽀持更⼤的数据容量,同时每个主节点可以拥有⾃⼰的多个从节点,如果该主节点宕机,会从它的从节点中选举⼀ 个新的主节点。
对于这三种模式,如果Redis要存的数据量不⼤,可以选择哨兵模式,如果Redis要存的数据量⼤,并且 需要持续的扩容,那么选择Cluster模式。
三、RDB与AOF
1、数据的持久化是怎么实现的?
1.1、RDB
RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据
手动生成RDB文件
save #由Redis主进程来执行RDB,会阻塞所有命令
bgsave #开启子进程执行RDB,避免主进程受到影响
简单说一下save为什么不好
立即将当前数据库的内容保存到磁盘,在主线程中同步执行。这意味着 Redis 在执行save 命令时,会暂停所有的其他操作,直到数据写入完成.由于save命令会阻塞主线程,这可能会导致 Redis 在保存期间无法处理其他请求,从而影响性能
自动生成RDB文件
Redis内部有触发RDB的机制,可以在redis.conf文件中找到
RDB的执行原理
bgsave开始时会fork主进程得到子进程,子进程共享主进程的内存数据。完成fork后读取内存数据并写入RDB文件。(是异步的,对主进程几乎是没有阻塞的,但是开启子进程的时候会产生阻塞,纳秒级的忽略不计)
fork采用的是copy-write技术:
- 当主进程执行读操作时,访问共享内存;
- 当主进程执行写操作时,则会拷贝一份数据,执行写操作。
首先有个物理内存,你可以理解为计算机的内存条,这个时候有个redis的主进程,要实现对数据的读写肯定是在内存中实现的,是吧!但是在Linux系统中,所有的进程都不能直接操作物理内存,但是操作系统给所有的进程都分配了一块虚拟内存,那主进程只能操作虚拟内存,当然操作系统会维护虚拟内存和物理内存之间的映射关系表,这个表被称为页表;这个时候主进程去操作虚拟内存,而虚拟内存基于页表的映射关联到物理内存真正的存储数据的位置,这样就可以实现对物理内存数据的读和写的操作了,现在我们就知道页表的作用了。
那现在我们重点来看一下主进程和子进程是如何进行数据同步的。首先我们知道,当我们执行bgsave的时候,它会开一个子进程去执行RDB对不对,其实内部啊,它会fork一个子进程(fork的话相当于克隆了一个子进程),当有了子进程之后,它并不是针对物理内存的数据做拷贝,仅仅是对页表数据进行拷贝,也就是说把映射关系拷贝给了子进程,这个时候子进程就有了和主进程一样的映射关系了,那子进程在操作自己的虚拟内存时,因为映射关系和主进程是一样的,是不是最终一定能映射到相同的物理内存区域,这样就是实现了子进程和主进程内存空间的共享,这样我们就不需要拷贝内存中的数据了,直接实现内存共享,这个速度是非常的快的,这样阻塞的时间就会尽可能的缩短了,因为它只需要拷贝页表的数据就可以了这个时间是非常的快的(纳秒级别,可以忽略不计);当子进程有了页表之后,就可以读取物理内存数据了,然后就可以把读到的数据写入磁盘中,这是一个新的RDB文件,写完之后,就会替换旧的RDB文件,其实到这里我们的异步持久化就完成了,但是要注意,子进程在写RDB文件的过程中,主进程是不是会接受用户的请求,去修改内存中的数据啊,当然可以啦,这个时候主进程在修改数据,而子进程在读和写数据,是不是会有冲突啊,甚至会有一些脏数据,该怎么办呐,所以为了避免这个问题的发生,在fork底层采用了copy-on-write的技术,什么意思呐,其实就是:当主进程要去写的时候,去做一次拷贝,现在我们的内存是没有拷贝的,是贡献的个,主进程和子进程都是可以操作这个数据的,在fork的时候,会把共享的这个内存标记为read-only(它是个只读模式),任何一个进程只能来读数据,不能写数据,假设现在用户真的接收了一个写的请求,主进程必须先拷贝一份数据出来,也就是把数据B完整拷贝一份出来,然后再去完成他的写操作,一旦完成拷贝之后,我们的主进程再去读操作的时候也会往这边去读了,页表的映射关系也会映射到新的数据来,这个就是copy-on-write技术,他只要每次有写操作都可以拷贝,这样就避免了脏写的问题,这个就是RDB使用bgsave命令执行的底层原理了
优点
1. 整个Redis数据库将只包含⼀个⽂件 dump.rdb,⽅便持久化。
2. 容灾性好,⽅便备份。
3. 性能最⼤化,fork ⼦进程来完成写操作,让主进程继续处理命令,所以是 IO 最⼤化。使⽤单独⼦
进程来进⾏持久化,主进程不会进⾏任何 IO 操作,保证了 redis 的⾼性能
4. 相对于数据集⼤时,⽐ AOF 的启动效率更⾼。
缺点
1. 数据安全性低。RDB 是间隔⼀段时间进⾏持久化,如果持久化之间 redis 发⽣故障,会发⽣数据丢
失。所以这种⽅式更适合数据要求不严谨的时候)
2. 由于RDB是通过fork⼦进程来协助完成数据持久化⼯作的,因此,如果当数据集较⼤时,可能会导
致整个服务器停⽌服务⼏百毫秒,甚⾄是1秒钟
1.2、AOF
AOF全称Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看作是命令日志文件。
优点
1. 数据安全,Redis中提供了3中同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也
是异步完成的,其效率也是⾮常⾼的,所差的是⼀旦系统出现宕机现象,那么这⼀秒钟之内修改的
数据将会丢失。⽽每修改同步,我们可以将其视为同步持久化,即每次发⽣的数据变化都会被⽴即
记录到磁盘中。。
2. 通过 append 模式写⽂件,即使中途服务器宕机也不会破坏已经存在的内容,可以通过 redis
check-aof ⼯具解决数据⼀致性问题。
3. AOF 机制的 rewrite 模式。定期对AOF⽂件进⾏重写,以达到压缩的⽬的
缺点
1、 因为是记录命令,AOF文件会比RDB文件大得多。而且AOF会记录对同一个key的多次写操作,单只有最后一次写操作才有意义。通过执行bgrewriteaof命令,可以让AOF文件执行重写功能,用最少的命令达到相同的效果。
2、 数据集⼤的时候,⽐ rdb 启动效率低。
3、运⾏效率没有RDB⾼
Redis也会在触发阈值时自动去重写AOF文件。阈值也可以在redis.conf中配置