Redis
2.1 数据结构
2.1.1 简单动态字符串(Simple Dynamic String)-SDS
2.1.2 双端链表(LinkedList)
2.1.3 压缩列表(ZipList)
2.1.4 字典(哈希表Ht)
2.1.5 集合(IntSet)
2.1.6 跳跃表(SkipList)
2.2 持久化
Redis.config文件中修改RDB、AOF配置,进行持久化
2.2.1 RDB(SNAPSHOTTING配置)
(1) 在指定的时间间隔内,执行指定次数的写操作,则会将内存中的数据写入到磁盘中。在指定目录下生成一个dump.rdb文件,Redis 重启会通过加载dump.rdb文件恢复数据。
(2) 规则配置(自动触发,修改redis.conf配置文件)
* 保存指令
-> save <seconds> <changes> //save <指定时间间隔> <执行指定次数更新操作>
-> save 900 1 // 900秒内有1个更改,则将内存中的数据快照写入磁盘
* 快照文件命名,dump.rdb名称可自定义
-> dbfilename dump.rdb
* 路径,指定目录存放快照文件,默认当前目录
-> dir ./
* 数据压缩 ,默认开启数据压缩
-> rdbcompression yes
(3)触发RDB快照
* 在指定的时间间隔内,执行指定次数的写操作
* 手动执行save命令(阻塞, 只管保存快照,其他的等待) 或者是bgsave (异步)命令
(4) 场景选择
-
优点:
适合大规模的数据恢复。
如果业务对数据完整性和一致性要求不高,RDB是很好的选择。 -
缺点:
数据的完整性和一致性不高,因为RDB可能在最后一次备份时宕机了。
备份时占用内存,因为Redis 在备份时会独立创建一个子进程,将数据写入到一个临时文件(此时内存中的数据是原来的两倍哦),最后再将临时文件替换之前的备份文件。所以Redis 的持久化和数据的恢复要选择在夜深人静的时候执行是比较合理的。
2.2.2 AOF(APPEND ONLY MODE配置)
(1)本地生成持久化内容,文件名称默认值为 appendonly.aof, Redis默认不开启该模式
(2)配置规则
# 开关,redis 默认关闭,需要手动改为yes
-> appendonly yes
# 持久化文件别命名,默认值为 appendonly.aof
-> appendfilename "appendonly.aof"
# 持久化策略(以下三种情况,选择一个)
## 异步执行
-> appendfsync everysec
## 同步执行,每次发生数据变化会立刻写入到磁盘中。性能较差当数据完整性比较好(慢,安全)
-> appendfsync always
## 不同步
-> appendfsync no
(3)配置重写触发机制
# 当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发。一般都设置为3G,64M太小了。
## 表示当前AOF文件空间(aof_current_size) 和上一次重写后AOF文件空间(aof_base_size) 的比值。
-> auto-aof-rewrite-percentage 100
## 表示运行AOF重写时文件最小体积, 默认为64MB。
-> auto-aof-rewrite-min-size 64mb
(4)根据AOF文件恢复数据
- 正常重启即可
- 异常情况,可以通过命令
-> redis-check-aof --fix appendonly.aof
(5)场景选择
- 优点:数据的完整性和一致性更高
- 缺点:因为AOF记录的内容多,文件会越来越大,数据恢复也会越来越慢。
2.3 缓存穿透、缓存雪崩、缓存击穿
2.3.1 缓存穿透(访问数据不存在)
- 缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。
- 解决方案:
(1)设置相应的key值为null。
(2)布隆过滤器(集合)
\qquad ①二进制向量和一系列随机映射函数,长度为m比特的位数组(bit array)与k个哈希函数(hash function)组成的数据结构
\qquad ②Java层面的过滤器
2.3.2 缓存雪崩(散列访问)
同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。
2.3.3 缓存击穿(热key失效,集中访问导致)
2.4 哨兵机制(Sentinel)
在Redis主从复制模式中,因为系统不具备自动恢复的功能,所以当主服务器(master)宕机后,需要手动把一台从服务器(slave)切换为主服务器。在这个过程中,不仅需要人为干预,而且还会造成一段时间内服务器处于不可用状态,同时数据安全性也得不到保障,因此主从模式的可用性较低,不适用于线上生产环境。
Redis 官方推荐一种高可用方案,也就是 Redis Sentinel 哨兵模式,它弥补了主从模式的不足。Sentinel 通过监控的方式获取主机的工作状态是否正常,当主机发生故障时, Sentinel 会自动进行 Failover(即故障转移),并将其监控的从机提升主服务器(master),从而保证了系统的高可用性。
哨兵模式是一种特殊的模式,Redis 为其提供了专属的哨兵命令,它是一个独立的进程,能够独立运行。
2.4.1 Redis搭建主从
(1) redis.conf 修改端口以及配置信息
# 配置主节点
#redis-6380.conf
port 6380
daemonize yes //后台运行
logfile "6380.log"
dbfilename "dump-6380.rdb"
masterauth password //主节点密码
# 配置从节点①
#redis-6381.conf
port 6381
daemonize yes
logfile "6381.log"
dbfilename "dump-6381.rdb"
slaveof 192.168.92.128 6380
masterauth password //主节点密码
# 配置从节点②
#redis-6382.conf
port 6382
daemonize yes
logfile "6382.log"
dbfilename "dump-6382.rdb"
slaveof 6380
masterauth password //主节点密码
# 主节点通过命令查看节点状况
-> info replication
(2)主从复制
# 在 master 中配置 repl-diskless-sync yes 启用无磁盘复制,避免全量同步时的磁盘IO。
repl-diskless-sync yes //开启从内存中复制
# 强制读写分离,默认开启。
slave-read-only yes
-
主从复制的断点续传,依赖于复制时的backlog
如果主从复制过程中,网络连接断掉了,那么可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份。 -
限制一个 master 上的 slave 节点数量,如果实在是太多 slave,则可以采用主-从-从链式结构,减少 master 压力
-
复制流程
master 如何判断 slave 是不是第一次来同步数据?这里会用到两个很重要的概念:
a1. Replication Id:简称replid,是数据集的标记,id 一致则说明是同一数据集。每一个master 都有唯一的replid,slave 则会继承 master 节点的 replid
a2. offset:偏移量,随着记录在 repl_baklog 中的数据增多而逐渐增大。slave 完成同步时也会记录当前同步的 offset。如果 slave 的 offset 小于 master 的offset,说明 slave 数据落后于master,需要更新。
a3. 因此 slave 做数据同步,必须向 master 声明自己的 replication id 和 offset,master 才可以
a4. 过程如下
\qquad ①slave 节点请求增量同步
\qquad ②master 节点判断 replid,发现不一致,拒绝增量同步
\qquad ③master 将完整内存数据生成RDB,发送 RDB 到slave
\qquad ④slave清空本地数据,加载master的RDB
\qquad ⑤master 将 RDB 期间的命令记录在 repl_baklog,并持续将log中的命令发送给slave
\qquad ⑥slave 执行接收到的命令,保持与 master 之间的同步
2.4.2 哨兵搭建
- 需要从Redis官网或者源码中获取sentinel.conf配置文件并修改。
sentinel.conf配置文件详解
# 哨兵sentinel的工作目录
-> dir ./
# 是否开启保护模式,默认开启。
-> protected-mode:no
# 是否设置为后台启动。
-> daemonize:yes
# 哨兵sentinel监控的redis主节点的
## master-name:可以自己命名的主节点名字
## quorum:当这些quorum个数sentinel哨兵认为master主节点失联 那么这时客观上认为主节点失联了
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
-> sentinel monitor mymaster 127.0.0.1 6379 2
# 当在Redis实例中开启了requirepass,所有连接Redis实例的客户端都要提供密码。
# sentinel auth-pass <master-name> <password>
-> sentinel auth-pass mymaster 123456
# 指定主节点应答哨兵sentinel的最大时间间隔,超过这个时间,哨兵主观上认为主节点下线,
#默认30秒
# sentinel down-after-milliseconds <master-name> <milliseconds>
-> sentinel down-after-milliseconds mymaster 30000
# 指定了在发生failover主备切换时,最多可以有多少个slave同时对新的master进行同步。
#这个数字越小,完成failover所需的时间就越长;反之,但是如果这个数字越大,就意味着
#越多的slave因为replication而不可用。可以通过将这个值设为1,来保证每次只有一个slave,
#处于不能处理命令请求的状态。
# sentinel parallel-syncs <master-name> <numslaves>
-> sentinel parallel-syncs mymaster 1
# 故障转移的超时时间failover-timeout,默认三分钟,可以用在以下这些方面:
## 1. 同一个sentinel对同一个master两次failover之间的间隔时间。
## 2. 当一个slave从一个错误的master那里同步数据时开始,直到slave被纠正为从正确的master那里同步数据时结束。
## 3. 当想要取消一个正在进行的failover时所需要的时间。
## 4. 当进行failover时,配置所有slaves指向新的master所需的最大时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来同步数据了
# sentinel failover-timeout <master-name> <milliseconds>
-> sentinel failover-timeout mymaster 180000
# 当sentinel有任何警告级别的事件发生时(比如说redis实例的主观失效和客观失效等等),
#将会去调用这个脚本。一个脚本的最大执行时间为60s,如果超过这个时间,脚本将会被一个SIGKILL信号终止,之后重新执行。
# 对于脚本的运行结果有以下规则:
## 1. 若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10。
## 2. 若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。
## 3. 如果脚本在执行过程中由于收到系统中断信号被终止了,则同返回值为1时的行为相同。
# sentinel notification-script <master-name> <script-path>
-> sentinel notification-script mymaster /var/redis/notify.sh
# 这个脚本应该是通用的,能被多次调用,不是针对性的。
# sentinel client-reconfig-script <master-name> <script-path>
-> sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
- 启动哨兵时,与redis一致,读取配置文件不同。结尾需要添加 “–sentinel”
-> redis-server.ext sentinel.conf --sentinel - 并且搭建 一主二从三哨兵时,仅监听主节点即可。
- 主节点宕机时会自动选举从节点升级为主节点,后续原主节点好了之后会降级为从节点。