Redis进阶学习笔记
阅读Redis.conf配置文件
# 61, 绑定的 IP , 一般注释掉该命令,这个吗,命令表示仅接受本机的(IP为本机)客户端连接,
bind 127.0.0.1
# 80, yes: 保护模式 , 默认关闭, 允许外部客户端连接redis,no: 只能本机连接
protected-mode no
# 84, 端口号
port 6379
####### 整体配置 GENERAL #########
# 129, yes: 开启守护进程模式,重启机器, redis自启动,no: 机器重启需要手动启动redis
daemonize no
# 150, pid文件生成目录
pidfile /var/run/redis_6379.pid
# 158, 日志级别,
# Redis 总共支持四个级别:debug、verbose、notice、warning
# - debug:会打印生成大量信息,适用于开发/测试阶段
# - verbose:包含很多不太有用的信息,但是不像debug级别那么混乱
# - notice:适度冗长,适用于生产环境
# - warning:仅记录非常重要、关键的警告消息
loglevel notice
# 163 , 打印日志目录
logfile ""
# 177, 16哥数据库
databases 16
######## 快照 SNAPSHOTTING ###########
# 快照 , 持久化操作,保存 redis数据库中的一个状态,用于恢复数据库,将redis持久化到 .rdb .aof文件中
# - 900s,至少有 1 个key 发生了变化,才会持久化
# - 300,至少有 10 个key 发生了变化,才会持久化
# - 60s,至少有 10000 个key 发生了变化,才会持久化
save 900 1
save 300 10
save 60 10000
# 219 , 持久化错误之后是否要工作
stop-writes-on-bgsave-error yes
# 225 , 是否压缩 rdb 文件
rdbcompression yes
# 234, 保存rdb文件是否要进行错误检查校验
rdbchecksum yes
# 236,rdb 文件的文件名
dbfilename dump.rdb
# 247, rdb 文件保存路径
dir ./
################## 安全设置 SECURITY ###################
# 480 ,设置密码 , 也可使用命令配置
requirepass 123456
##### 命令配置密码
> config set requirepass 123
> config get requirepass
> auth 123
##### end
################ LIMITS #############
# 512 , redis的最大链接数
maxclients 10000
# 537, redis配置的最大内存
maxmemory <bytes>
# 内存达到上限之后的处理方法
# - volatile lru -> 设置了过期时间的key进行lru移除
# - allkeys lru -> 删除所有
# - volatile random -> 删除即将过期的key
# - allkeys random -> 随机删除
# - volatile ttl -> 删除即将过期的
# - noeviction -> 永远不过期,直接报错
maxmemory-policy noeviction
############# AOF持久化 ###############
# 593,yes开启AOF持久化,默认是不开启的,默认使用RDB持久化,大部分情况下RDB完全够用
appendonly no
# 597 ,aof持计划文件名
appendfilename "appendonly.aof"
# 623 , 每次修改都会synch 消耗性能
# - always , 每次修改都进行 aof持久化
# - everysec , 每秒进行aof持久化
# - no , 从不
appendfsync everysec
Redis持久化
Redis
是内存数据库,断电即失去,只要是内存数据库就一定会有持久化操作
RDB(Redis DataBase)
在指定的时间 间隔内将内存中的数据集快照写入到磁盘中,Snapshot
快照,恢复时将快照文件直接读到内存中
RDB流程
- 单独创建一个子进程,
fork
分支 - 将内存内容写入临时
RDB
文件 - 再用临时文件替换上次持久化完成的文件
整个过程主进程不进行任何io
操作,保证了性能,如果进行大规模数据恢复,RDB
和AOP
都可以进行数据恢复,AOF
数据恢复完整性不敏感,RDB
更加高效,缺点时最后一次持久化后的数据可能丢失,默认使用的就是RDB,一般情况不需要修改这个配置
RDB保存的文件是dump.rdb
AOF保存的文件是appendonly.aof
dump.rdb文件
触发机制
save
规则触发- 执行
flushall
命令- 关闭
redis
如何恢复备份文件
只要将rdb
文件放在redis
规定的目录,redis
启动时会自动检查dump.rdb
文件恢复数据,在生产环境中最好对dump.rdb
文件进行备份
RDB优缺点
优点:
- 父进程正常处理用户请求,
fork
分支一个子进程进行备份 - 适合大规模的数据恢复,如果服务器宕机了,只要不删除
RDB
文件,重启以后还可以恢复数据**(最后一次的数据无法恢复,因为还没有生成新的rdb文件,就宕机了)**
缺点:
- 需要一定的时间间隔,可以自行修改设置
- 如果redis意外宕机,最后一次的修改数据会丢失
fork
进程的时候,会占用一定的内存空间
AOF(Append Only File)
- 将所执行的所有命令都记录下来,处读操作以外,恢复时重新执行一次,如果是大数据就需要写很久
- aof默认是文件无限追加,大小会不断扩张
- 在主从复制中,rdb是备用的,在从机上使用,aof一般不使用
AOF的本质就是保存 所有执行了命令
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gtnk4kn9-1666273048108)(images/image-20211020092943332.png)]
AOF流程
fork
分支出子进程- 根据内存中的数据子进程创建临时
aof
文件 - 父进程执行的命令存放在缓存中,并且写入原
aof
文件 - 子进程完成新
aof
文件通知父进程 - 父进程将缓存中的命令写入临时文件
- 父进程用临时文件替换旧
aof
文件并重命名 - 后面的命令都追加到新的
aof
文件中
开启AOF
appendonly no
#默认关闭appendonly 手动设置yes开启
appendfilename "appendonly.aof"
#默认名字
# appendfsync always
appendfsync everysec
# appendfsync no
#每次都进行修改
#每秒钟都进行修改 ,
#不进行修改
no-appendfsync-on-rewrite no
#是否进行重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
#percentage重写百分比
#重写时文件最小的体积
#一般保持默认,一般只需要开启
一般采用 appendfsync everysec
每秒钟触发一次,这样就算是宕机,也最多丢失1
秒钟的数据。
测试开启aof
root@root:~# redis-cli -a 123456
127.0.0.1:6379> set name san
OK
127.0.0.1:6379> get name
"san"
127.0.0.1:6379> exit
root@root:~# cd /usr/local/redis/redis-3.2.10/
root@root:/usr/local/redis/redis-3.2.10# ls
00-RELEASENOTES COPYING Makefile runtest src
appendonly.aof deps MANIFESTO runtest-cluster tests
BUGS dump.rdb README.md runtest-sentinel utils
CONTRIBUTING INSTALL redis.conf sentinel.conf
redis
目录生成了appendonly.aof
文件
我们看到 AOF文件中存储的是我们的命令
破坏AOF文件以及修复aof文件
在appendonly.aof
文件中加入一串符号
重启Redis,发现redis重启失败
使用redis-check-rdb修护aof文件
root@root:/usr/local/redis/redis-3.2.10# vim appendonly.aof
root@root:/usr/local/redis/redis-3.2.10# redis-check-aof --fix /usr/local/redis/redis-3.2.10/appendonly.aof
0x 37: Expected prefix 'b', got: '*'
AOF analyzed: size=90, ok_up_to=55, diff=35
This will shrink the AOF from 90 bytes, with 35 bytes, to 55 bytes
Continue? [y/N]: y
Successfully truncated AOF
root@root:/usr/local/redis/redis-3.2.10# cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
set
$4
name
$3
san
root@root:/usr/local/redis/redis-3.2.10#
修复成功,删除了我添加的乱码
优缺点
优点:
- 可设置文件修改每次都同步备份,文件完整性更好,但是消耗性能
- 设置每秒同步一次可能会丢失一秒的数据
- 从不同步效率最高
缺点
- 对于数据文件,
aof
远远大于rdb
,修复速度也比rdb
慢 aof
是io
操作,所以默认是aof
aof
文件会无限扩大
所有我们一般不使用aof
,而是使用rdb
用作备份
Redis主从复制
一个Master
有多个slave
,将一台redis
服务器数据,复制到其他的redis
服务器,前者称为主节点(masterleader),后者称为从节点(slave、follower),数据是单向的,只能从主节点到从节点,Master以写为主,Slave以读为主
主从复制的特点
主从复制的特点
- 数据是单向的,只能从主节点到从节点
Master
以写为主,Slave
以读为主- 主节点和从节点的数据都是一样的,主节点数据发生变化是,会同步所有从节点的数据。
- 一个Master可以有多少Slave或没有从节点,一个从节点只能有一个主节点
默认情况下(非主从结构时),每台redis服务器都是主节点,一个Master可以有多少Slave或没有从节点,一个从节点只能有一个主节点
主从复制作用包括:
- 数据冗余,实现了数据的热备份,是持久化之外的一种数据冗余方式
- 故障恢复,主节点出现问题,从节点可以提供服务,实现快速的故障恢复,实际上是一种服务的冗余
- 负载均衡,在主从复制的基础上,配合读写分离,主节点提供写服务,从节点提供读服务,写redis数据时连接主节点,读redis数据连接从节点,分担服务器负载,尤其在写少读多的场景下通过,多个从节点分担负载,可以提高redis性能
- 高可用(集群)基石,哨兵、集群,能够实施的基础,主从复制时高可用的基础
不能只使用一台redis的原因:
- 从结构上讲,单个redis服务器会发生单点故障,一台服务器需要处理所有请求,压力大
- 从容量上讲,单个redis服务器内存容量有限,并且不能完全使用全部的内存,单台redis的最大内存不应该超过20g压力过大
通常的电商网站都是一次上传吗,无数次浏览,读多写少 ,主从复制,读写分离,80%的情况都在进行读操作,起码一主二从
搭建Redis主从复制伪集群
cp
三份redis.con
文件到新的目录
cp
三份redis.con
文件到新的目录以80、81、81重命名
root@iZ2ze3e3cxev6ehgdt3qpdZ:~/redis# ls
redis80.conf redis81.conf redis82.conf redis.conf
root@iZ2ze3e3cxev6ehgdt3qpdZ:~/redis#
修改三个配置文件的内容
# 1. 修改端口 6380、6381、6382
port 6380
# 2. 修改 pid 的文件名
pidfile /var/run/redis_6381.pid
# 3. 修改日志文件6380、6381、63812
logfile "6381.log"
# 4. 修改rdb文件名80、81、82
dbfilename dump81.rdb
分别启动三个redis
root@root:~/redis# redis-server redis80.conf
root@root:~/redis# redis-server redis81.conf
root@root:~/redis# redis-server redis82.conf
# 启动服务 redis-cli -p 6380 -a 123456
root@root:~/redis#
6380
6381
6382
建立主从结构
主机
master
:6380
从机
slave
:6381
、6382
slaveof 127.0.0.1 6379 # 设置 6380 为主机 info replication # 查看 配置信息
从机设置主机,在6381、6382分别设置6380为主机
127.0.0.1:6381> slaveof 127.0.0.1 6379 # 设置 6380 为主机
OK
127.0.0.1:6381> info replication # 查看 配置信息
# Replication
role:slave # 表示自己为从机
master_host:127.0.0.1
master_port:6380
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1634715585
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6381>
127.0.0.1:6382> slaveof 127.0.0.1 6380 # 设置 6380 为主机
OK
127.0.0.1:6382> info replication
# Replication
role:slave
master_host:127.0.0.1
master_port:6380
master_link_status:down
master_last_io_seconds_ago:-1
master_sync_in_progress:0
slave_repl_offset:1
master_link_down_since_seconds:1634715709
slave_priority:100
slave_read_only:1
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
127.0.0.1:6382>
查看的主机6380的配置信息
127.0.0.1:6380> info replication
# Replication
role:master
connected_slaves:2
slave0:ip=127.0.0.1,port=6381,state=online,offset=43,lag=1
slave1:ip=127.0.0.1,port=6382,state=online,offset=43,lag=0
master_repl_offset:43
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:2
repl_backlog_histlen:42
127.0.0.1:6380>
主从复制搭建成功
注意:
如果redis设置了密码,主从结构会失败,会出现主机找不到从机的问题
解决方法:
从机在添加主机时,加上密码参数
主节用于写数据,从节点用于读数据
127.0.0.1:6381> set name san
(error) READONLY You can't write against a read only slave.
127.0.0.1:6381>
如果我们对从节点写数据,就会失败,只有主节点才可以写数据
######## master
127.0.0.1:6380> set name san
OK
127.0.0.1:6380>
######## slave
127.0.0.1:6381> get name
"san"
127.0.0.1:6381>
无哨兵的主从结构存在的问题
-
主机宕机、从机依然还是从机,无法写只能读
-
从机宕机,主机继续写入数据,从机恢复,能否get到恢复时段主机读取的值?
- 没在
redis.conf
中设置的slave
,读取不到崩溃时master
set
的数据 - 在
redis.conf中
配置的slave
,能读取到 - 只要变为从机就会立马从主机中获取值
- 没在
=====================================>
由此可见,如果主机一直宕机,从机一直都会是从机,将会导致系统不可用。如果主机恢复,主从配置没有写入到redis.conf文件中,将读取不到主机设置的值。
<=====================================
主从复制的原理
slave
启动成功连接到master
后会发送一个sync
同步命令
master
接到命令,启动后台的存盘进程,同时收集所接收到的用于修改数据集命令,后台执行完毕之后,master
将传送整个数据文件到slave
,并完成一次同步,成为增量复制只要重新连接
master
,**一次完全同步(全量复制)**将被自动执行,数据一定能在从机中看到
全量复制和增量复制
- 全量复制,就是将主机的所有数据文件,全部同步。一般用在连接成功后,主机的一系列操作。
- 增量复制,就是将同步对主机自己没有的数据。一般用在连接成功时,需要同步主机的所有数据。
主从复制
的两种结构
星型结构,所有从节点都直接连接在主节点上。
链式结构,只有一个从节点直接到主节点,其他节点间接连接
# 实现方式 # 在 salve1:6380 设置主节点 slaveof 127.0.0.1 3679 # 在 salve2:6381 认 salve1 问主节点 slaveof 127.0.0.1 3680
这两种方法都一样,主机宕机,从节点都无法变成主节点
Master宕机解决方法
-
手动让
从机
变为主机
, 需要人工手动设置十分不方便slaveof on one # 让自己变为主机
-
使用哨兵根据投票自动选择从机变为主机 , 哨兵模式更加适用。
带哨兵模式的主从复制
哨兵模式是一种特殊模式,哨兵是一个独立的进程,作为进程独立运行,原理是哨兵通过发送命令,等待redis服务器响应,从而判断服务器是否存货
单机哨兵
哨兵向服务器发送信息,如果服务器没有一定时间内响应,就认为该服务器宕机。哨兵检测到master
服务器宕机后,会自动将slave切换成master,通过发布订阅模式通知其他的从服务器,修改配置文件,让他们切换主机
单机哨兵宕机也会存在一定的风险,创建多个哨兵构建集群才是正解!
哨兵集群模式
master
宕机,sentinel
检测到这个结果系统并不会马上进行failover
(故障切换、失效备援)这个现象称为主观下线, 也就是不会马上切换主机。- 等待其他哨兵也检测到主机不可用,
sentinel
之间会发起一次投票,(投票的结果由随机一个sentinel
发起,进行failover
操作)得到票数最多的从机就就切换成主机。 - 切换成主机后,通过发布订阅模式,让各个哨兵把自己监控的服务器实现切换主机,这个过程称为客观下线
单哨兵模式实现
创建哨兵配置文件 sentinel.conf
# sentinel.conf
sentinel monitor mymaster 127.0.0.1 6380 1
# sentinel monitor mymaster(主机的名称,随便写) 主机IP 端口
# 1 表示: (法定人数)至少需要 1 个哨兵同意的情况下,才可以让从机变为主机
有的redis目录下就有sentinel.conf文件只需要对其修改即可。
启动哨兵模式
redis-sentinel sentinel.con
- 启动
sentinel
成功之后看到,监控了6381、6382、6380的健康状态。 - 端口为
26379
- 如果哨兵检测到master宕机,则会打印检测信息
测试master宕机
稍微等待一会,sentinel
打出信息, 6380
宕机,6382
上位
连接6382查看主从信息,发现6382变为主机
如果6380恢复,那么6380是否还是主机呢?
很明显,6380就算恢复,也只能是从机,无法恢复成主机。
多哨兵集群配置
多哨兵集群的配置和单哨兵是一样的
复制三份
sentinel1.conf
、sentinel2.conf
、sentinel3.conf
即可修改
sentinel.conf
中的port
段口号即可,默认端口号26379
,三个不一样的端口号。监视主机的配置写法一样
sentinel monitor mymaster 127.0.0.1 6379 2
哨兵模式优缺点
优点
- 基于集群,基于
主从复制
,所有的主从配置的优点,它全有 - 主从可以切换,故障可以切换,系统的可用性提高
- 哨兵模式就是主从模式的升级,手动到自动,更加健壮
缺点
redis
不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦- 哨兵模式需要很多配置
- 多哨兵,多端口配置复杂,一般由运维来配置
Redis缓存穿透、击穿、雪崩
服务三高
- 高并发
- 高可用
- 高性能
Redis缓存
redis
缓存的使用极大的提升了应用程序的性能和效率,特别是数据查询方面,但是也带来了许多问题,如数据一致性问题,对一致性要求高的不推荐适用缓存。
缓存穿透
用户查询一个数据,redis
数据库中没有,也就是缓存没命中,于是向持久层数据库查询,发现也没有,于是查询失败,用户很多的时候,缓存都没有命中,都请求持久层数据库,给持久层数据库造成巨大压力,称为缓存穿透。(由于缓存没有命中,大量的请求冲击数据库,导致缓存穿透)
解决方法
- 布隆过滤器,在直达持久层的路径上加上过滤器
- 缓存空对象,缓存中专门增加一个为空的请求
布隆过滤器
布隆过滤器是一种数据结构,对所有可能的查询参数以hash
形式存储,在控制层进行校验,不符合则丢弃,从而避免了对底层存储系统查询压力
缓存空对象
当持久化层不命中后,将返回的空对象存储起来,同时设置一个过期时间,之后再访问这个数据就从缓存中获取,保护持久层数据源
设置空缓存的问题
- 存储空的
key
也需要空间 - 对空值设置了过期时间,还会存在缓存层和存储层的数据有一段时间窗口不一致,对于需要保持一致性的业务会有影响
缓存击穿
例子微博服务器热搜,巨大访问量访问同一个key
一个key
非常热点,不停扛着大并发,集中对一个点进行访问,当个key失效的瞬间,持续大并发导致穿破缓存,直接请求数据库
某个key在过期的瞬间,大量的访问会同时访问数据库来查询最新的数据,并且回写缓存,导致数据库瞬间压力过大
======================================
一句话说,就是某个热点key承受不住高压(或者突然过期),导致大量请求直接访问数据库,导致缓存穿透。
======================================
解决方案
- 设置热点数据不过期,但是一直缓存会导致浪费空间
- 加分布式锁:使用分布式锁,保证对于每个key同时只有一个线程查询后端服务,其他线程没有获得分布式锁的权限,只需要等待即可,这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大
缓存雪崩
在某一个时间段,缓存集中过期失效,redis宕机
产生雪崩的原因之一,设置缓存的存活时间较短,大并发访问时刚好都过期,直接访问了数据库,对数据库而言,会产生周期性压力波峰**,暴增时数据库可能会宕机**
==========================================
一句话:就是突然大量的缓存失效,大量数据访问数据库,数据库承受不住压力宕机了,导致其他所有服务不可用,就像雪崩一样。
==========================================
解决方法
- 异地多活、增加redis集群服务器的数量
- 加分布式锁、缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量,对某个key只允许一个线程查询数据和写缓存,其他线程等待
- 限流降级、控制访问流量,对高并发的流量进行限制,并使用降级策略。
- 数据预热,正式部署之前,把可能的数据提前访问一遍,可能大量访问的数据就会加载到缓存中,加载不同的key,设置不同的过期时间,让缓存时间尽量均匀