目录
RDB、AOF及混合持久化详解
Redis数据备份策略
Redis主从架构及原理详解
Redis哨兵高可用架构
重度依赖Redis缓存集群的架构(例如大型购物网站),当Redis集群出现事故,且没有做Redis持久化的时候,会引起“缓存雪崩”的问题。
持久化的实现:RDB、AOF及混合持久化
RDB快照(snapshot)
这种机制在redis内存比较大(例如好几个G)的情况,是很耗费时间的。且当在执行rdb的save持久化操作时,会阻塞正常的redis请求。
修改save配置(redis.conf):
dump文件无法直接阅读。
bgsave命令(后台执行持久化save操作),称为写时复制机制(COW, Copy-On-Write)
命令 | save | bgsave |
IO类型 | 同步 | 异步 |
是否阻塞redis其他命令 | 是 | 否(生成一个子进程进行调用fork函数时会有短暂阻塞) |
时间复杂度 | O(n) | O(n) |
优点 | 不会消耗额外内存 | 不阻塞客户端请求 |
缺点 | 阻塞客户端请求 | 需要fork子进程,消耗内存 |
AOF(append-only file)
将修改数据(Redis 执行一个改变数据集的命令时)的每一条指令记录进文件appendonly.aof中(先写入os cache,每隔一段时间 fsync到磁盘),这种持久化方式,在redis挂掉重启后,更有利于数据集恢复/重建(重新依次执行aof中记录的指令)。
配置redis.conf
AOF持久化策略配置:
AOF重写
在redis执行命令过程中有很多重复低效的命令,例如不断地INCR 同一条数据;因此产生了AOF重写优化机制,即定期根据内存的最新数据重新生成aof文件
手动重写aof文件命令:bgrewriteaof
RBD和AOF:生产环境rbd和aof同时开启的情况下,redis会优先使用aof进行数据集恢复,原因是aof更不容易丢失数据,虽然恢复数据集的执行速度上不如rdb文件快,但数据安全性更高。
Redis混合持久化
前提:已开启aof持久化方式(可以关掉rdb持久化方式关闭,即注释掉save 配置)
混合持久化AOF文件结构如下:每次执行aof重写时,会将重写那一刻的数据集以rdb文件格式存入到aof文件中,后续写入的数据集修改命令仍然以aof格式追加在appendonly.aof中。这种方式既能提升性能,又能保证数据安全性
混合持久化配置:
1. 写crontab定时调度脚本,每小时都copy一份rdb或aof的备份到一个目录中去,仅仅保留最近48 小时的备份
2. 每天都保留一份当日的数据备份到一个目录中去,可以保留最近1个月的备份
3. 每次copy备份的时候,都把太旧的备份给删了
4. 每天晚上将当前机器上的备份复制一份到其他机器上,以防机器损坏
主节点:写数据;
从节点:备份数据,读操作
主从复制全量复制流程图(slave第一次链接上master,并发的slave请求,master只会bgsave一次):
主从复制(部分复制、断点续传)流程图:
主从复制风暴:是指有很多slave并发发送复制命令,导致主节点压力过大
优化主从架构:
redis主从架构搭建,配置从节点操作:
1、复制一份redis.conf文件,命名为redis6380.conf
2、将相关配置修改为如下值:
port 6380
pidfile /var/run/redis_6380.pid # 把pid进程号写入pidfile配置的文件
logfile "6380.log"
dir ./redisdata/port6380 # 指定数据存放目录,启动从节点前,要保证这个文件夹已新建,否则启动会失败
3、配置主从复制
replicaof 192.168.1.4 6379 # 从本机6379的redis实例复制数据,Redis 5.0之前使用slaveof
replica‐read‐only yes # 配置从节点只读
4、启动从节点
src/redis‐server redis6380.conf
5、连接从节点
redis‐cli ‐p 6380
6、测试在6379实例上写数据,6380实例是否能及时同步新修改数据
主节点6379:
从节点6380:
Java项目中使用Jedis链接redis server
redis.clients jedis 2.9.0
普通链接访问:代码略。。。
管道执行:一次性发送多个请求而不用等待服务器的响应,待所有命令都发送完后再一次性读取服务的响应。目的是减少连接redis server的网络开销,其命令执行并不具有原子性,也就是当一组命令执行过程中,有命令执行失败,并不会中止后续命令的执行。(代码略)
管道执行的缺点是:当打包的命令太多时,消耗redis server的内存越多。
lua脚本执行:lua脚本执行具有原子性,且也能减少网络开销。(代码略)
哨兵服务不提供读写服务,仅仅用来监控主节点,当主节点不可用时,选举出新的主节点返回给客户端(redis的client端一般都实现了订阅功能,订阅sentinel发布的节点变动消息)
配置:
1、复制一份sentinel.conf文件
cp sentinel.conf sentinel‐26379.conf
2、将相关配置修改为如下值:
port 26379
daemonize yes
pidfile "/var/run/redis‐sentinel‐26379.pid"
logfile "sentinel-26379.log"
dir ./sentineldata #这个目录在启动sentinel之前须新建好,否则无法启动
# sentinel monitor master‐redis‐name master‐redis‐ip master‐redis‐port quorum。quorum是一个数字,指明当有多少个sentinel认为一个master失效时(值一般为:sentinel总数/2 + 1),master才算真正失效
sentinel monitor mymaster 192.168.0.60 6379 2
# mymaster这个名字随便取,客户端访问时会用到
3、启动sentinel哨兵实例
src/redis‐sentinel sentinel‐26379.conf
4、查看sentinel的info信息
src/redis‐cli ‐p 26379
127.0.0.1:26379>info
可以看到Sentinel的info里已经识别出了redis的主从
5、可以自己再配置两个sentinel,端口26380和26381,注意上述配置文件里的对应数字都要修改
查看sentinel-26379.conf文件:
哨兵模式验证:哨兵的spring-boot整合Redis链接代码
org.springframework.boot spring-boot-starter-data-redis org.apache.commons commons-pool2
配置
在demo(代码略)中,写一个while(true)接口,持续往redis中set数据,并get出来。
package com.redis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class IndexController {
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
@Autowired
private StringRedisTemplate stringRedisTemplate;
/**
* 测试节点挂了哨兵重新选举新的master节点,客户端是否能动态感知到
*
* @throws InterruptedException
*/
@RequestMapping("/test_sentinel")
public void testSentinel() throws InterruptedException {
int i = 1;
while (i<=300){
try {
stringRedisTemplate.opsForValue().set("sentinel666"+i, "sentinelTest"+i); //jedis.set(key,value);
System.out.println("设置key:"+ "sentinel666"+i);
i++;
Thread.sleep(1000);
}catch (Exception e){
logger.error("错误:", e);
}
}
}
}
程序运行起来后,关闭redis server主节点,此时程序报错time out 3seconds()
报错一段时间后,哨兵选举新的主节点,并发给client端重新链接。且可以看到,key并没有丢失
重新启动6379 redis server,查看哨兵conf文件,可以看到主节点已被替换成6380