四、Redis 扩展


一、Redis 配置


1. NETWORK 网络

# 绑定的ip
bind 127.0.0.1

#  保护模式
protected-mode yes

# 端口
port 6379
  • NETWORK.bind 限制访问的IP,注释后 所有IP 都可以访问。
  1. 输入 / 进入文件命令模式后。
  2. 输入 /bind 127.0.0.1 回车键查找关键字。
  3. 输入 n 查找下一个,N 查找上一个。
  4. 找到对应的行后,输入字母 i 进入编辑模式,在第一位字母前面加上 # 注释行。
  5. ESC 进入命令行模式输入 :wq 保存文件并退出,完成配置文件的编辑。
    在这里插入图片描述

2. GENERAL 总则

# 是否以守护进程方式运行(默认no)
daemonize yes
# 如果以后台的方式运行,需要指定一个`pid`文件
pidfile /var/run/redis.pid

# 日志级别(debug、verbose、notice、warning)
loglevel notice
# 日志文件名
logfile "server_log.txt"

# 数据库数量,默认`16`个数据库
databases 16

# 是否显示logo
always-show-logo yes 

  • GENERAL.daemonize 设置后台运行。
    在这里插入图片描述
  • GENERAL.databases 默认数据库个数。
    在这里插入图片描述
# 切换到`1号库`.
select 1
# 查看`DB大小`。
dbsize

# 清除当前数据库。
flushdb

# 清除全部数据库。
flushall

3. SNAPSHOTTING 快照

# 在`900s`内,至少有`1`个`key`进行了修改,再进行持久化操作
save 900 1
# 在`300s`内,至少有`10`个`key`进行了修改,再进行持久化操作
save 300 10
# 在`60s`内,至少`10000`个`key`进行了修改,再进行持久化操作
save 60 10000

# 如果持久化出错,是否还需要继续工作
stop-writes-on-bgsave-error yes
# 是否压缩`rdb`文件,需要消耗一些`cpu`资源
rdbcompression yes
# 保存`rdb`文件的时候,进行错误的检查校验
rdbchecksum yes
# `rdb`文件名(持久化文件`*.rdb`、`*.aof`)
dbfilename dump.rdb
# `.rdb`文件保存的目录
dir ./

# 查看 dir 目录
127.0.0.1:6379> config get dir
1) "dir"
2) "E:\\frame\\redis\\Redis-x64-3.2.100"

4. REPLICATION 复制


5. SECURITY 安全

requirepass 123456
127.0.0.1:6379> ping
PONG

# 获取`Redis`的密码
127.0.0.1:6379> config get requirepass 
1) "requirepass"
2) ""
# 设置`Redis`的密码
127.0.0.1:6379> config set requirepass "123456"
OK

# 使用密码登录
127.0.0.1:6379> auth 123456 
OK
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) "123456"
# 保存配置
127.0.0.1:6379> save
OK

6. LIMITS 限制

# 设置能连接上`Redis`的最大客户端数量
maxclients 10000

# `Redis`配置最大的内存容量
maxmemory <bytes>

# 内存到达上限之后的处理策略
maxmemory-policy noeviction 
  1. volatile-lru:默认值,对设置了过期时间的 key 进行 LRU(Least Recently Used 最近使用的最少)。
  2. allkeys-lru: 删除 LRU 算法的 key。
  3. volatile-random:随机删除即将过期 key。
  4. allkeys-random:随机删除。
  5. volatile-ttl: 删除即将过期的 key。
  6. noeviction: 永不过期,返回错误。

7. APPEND ONLY MODE 追加模式(.aof 配置)

# 默认使用`rdb`方式持久化的,不开启`aof`模式,在大部分情况下,`rdb`完全够用
appendonly no 

# `aof`持久化的文件名字
appendfilename "appendonly.aof"

# 每次修改都会同步(消耗性能)
# appendfsync always
# 每秒执行一次同步,可能会丢失这一秒的数据
appendfsync everysec 
# 不执行同步,这个时候操作系统自己同步数据,速度最快
# appendfsync no 

  • 重写规则。
# `aof`默认是文件的无限追加,文件会越来越大
no-appendfsync-on-rewrite no
# 上面`yes`的话,当`aof`文件大于`64mb`,`fork`一个新的进程来将文件进行重写。
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

二、Redis 持久化

  • Redis 是内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出,服务器中的数据库状态也会消失。
  • 所以 Redis 提供了持久化功能。

1. RDB(Redis DataBase)【默认】

在这里插入图片描述


  • 在指定的时间间隔内,将内存中的数据集快照写入磁盘。
    也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里。

  • Redis 会单独创建一个子进程(Fork)来进行持久化,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个 临时文件 替换 上次持久化好的文件。
  • 整个过程中,主进程是不进行任何 IO操作 的。
  • 这就确保了极高的性能。
  • 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感。
    那 RDB 方式要比 AOF 方式更加的高效。
  • RDB 的缺点是最后一次持久化后的数据可能丢失。
  • 我们默认的就是 RDB,一般情况下不需要修改这个配置!

1.1 触发配置
################################ SNAPSHOTTING  ################################
# 测试下 60 秒内,修改 5 次,进行 rdb 持久化
save 60 5

# rdb 文件名
dbfilename dump.rdb
# .rdb 文件保存的目录
dir ./

1.2 触发机制
  1. save 的规则满足的情况下,会自动触发 Rdb 持久化。
  2. 执行 flushall 命令,也会触发 Rdb 持久化。
  3. 退出 Redis,也会产生 Rdb 文件。

1.3 RDB 文件恢复
# 查看`dir`目录
127.0.0.1:6379> config get dir
1) "dir"
2) "E:\\frame\\redis\\Redis-x64-3.2.100"
# 在这个目录下存在`dump.rdb`文件,启动就会自动恢复其中的数据

2. AOF(Append Only File)

  • 将所有的写命令都记录下来,类似 history
  • 恢复的时候,就把这个文件的命令全部再执行一遍。
    在这里插入图片描述
  • 以日志的形式来记录每个写操作,将 Redis 执行过的所有指令记录下来(读操作不记录),只许追加文件,但不可以改写文件。
  • Redis 启动之初会读取该文件重新构建数据,换言之,Redis 重启的话就根据日志文件的内容将写指令从前到后执行一次,以完成数据的恢复工作。

2.1 触发配置
  • 默认是不开启的,需要手动进行配置。
  • appendonly 改为 yes 就开启了 aof,重启 Redis 可以生效。
# 默认使用`rdb`方式持久化的,不开启`aof`模式,在大部分情况下,`rdb`完全够用
appendonly yes 
# `aof`持久化的文件名字
appendfilename "appendonly.aof"

# 每次修改都会同步(消耗性能)
# appendfsync always
# 每秒执行一次同步,可能会丢失这一秒的数据
appendfsync everysec 
# 不执行同步,这个时候操作系统自己同步数据,速度最快
# appendfsync no 
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "no"
127.0.0.1:6379> config set appendonly "yes"
OK
127.0.0.1:6379> config get appendonly
1) "appendonly"
2) "yes"
# 保存配置
127.0.0.1:6379> save
OK

2.2 重写规则
# `aof`默认是文件的无限追加,文件会越来越大
no-appendfsync-on-rewrite no

# 上面`yes`的话,当`aof`文件大于`64mb`,`fork`一个新的进程来将文件进行重写
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

2.3 AOF 文件修复
  • 如果 Aof 文件有错误,这时候 Redis 是启动不起来的,需要修复 Aof 文件。
  • Redis 提供了一个工具 redis-check-aof --fix appendonly.aof
E:\frame\redis\Redis-x64-3.2.100>redis-check-aof --fix appendonly.aof
0x             125: Expected \r\n, got: ffffffe6ffffff9d
AOF analyzed: size=337, ok_up_to=272, diff=65
This will shrink the AOF from 337 bytes, with 65 bytes, to 272 bytes
Continue? [y/N]: y
Successfully truncated AOF

3. RDB 和 AOF 优缺点

持久化机制优点缺点
RDB1. 适合大规模的数据恢复
2. 对数据的完整性要不高
1. 需要一定的时间间隔进程操作。如果 Redis 意外宕机了,这个最后一次修改数据就没有了
2. Fork 进程的时候,会占用一定的内容空间
AOF1. 每一次修改都同步,文件的完整会更好
2. 每秒同步一次,可能会丢失一秒的数据
3. 从不同步,效率最高的
1. 相对于数据文件来说,Aof 远远大于 Rdb,修复的速度也比 Rdb 慢
2. Aof 运行效率也要比 Rdb 慢,所以 Redis 默认的配置就是 Rdb 持久化

  1. RDB 持久化方式,能够在指定的时间间隔内,对数据进行快照存储。
  2. AOF 持久化方式,记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令 以 Redis 协议追加保存每次写的操作到文件末尾。
    Redis 还能对 AOF文件 进行后台重写,使得 AOF文件 的体积不至于过大。

  • 只做缓存,如果只希望数据在服务器运行的时候存在,也可以不使用任何持久化。

  • 同时开启两种持久化方式。
  1. 在这种情况下,当 Redis 重启的时候会优先载入 AOF文件 来恢复原始的数据。
    因为在通常情况下 AOF文件 保存的数据集 要比 RDB文件 保存的数据集要完整。
  2. RDB 的数据不实时,同时使用两者时,服务器重启也只会找 AOF文件。
  • 那要不要只使用 AOF 呢?
    建议不要。
  1. 因为 RDB 更适合用于 备份数据库(AOF 在不断变化不好备份),快速重启。
  2. 而且不会有 AOF 可能潜在的 BUG,留着作为一个万一的手段。

  • 性能建议。
  1. 因为 RDB文件 只用作后备用途,建议只在 Slave 上持久化 RDB文件。
    而且15分钟 备份一次就够了,只保留 save 900 1 这条规则。
  2. 如果 Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据。
    启动脚本较简单,只 Load 自己的 AOF文件 就可以了。
  1. 代价一是 带来了持续的IO。
  2. 代价二是 AOF Rewrite 的最后将 Rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。
  3. 只要硬盘许可,应该尽量减少 AOF Rewrite 的频率。
    AOF重写 的基础大小默认值 64M 太小了,可以设到 5G 以上。
    默认超过原大小 100% 大小重写,可以改到适当的数值。
  1. 如果不 Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也可以。
  1. 能省掉一大笔 IO,也减少了 Rewrite 时带来的系统波动。
  2. 代价是如果 Master/Slave 同时挂掉,会丢失十几分钟的数据。
  3. 启动脚本也要比较两个 Master/Slave 中的 RDB 文件。
    载入较新的那个,微博就是这种架构。

三、Redis 发布订阅

  • Redis 发布订阅(pub/sub)是一种 消息通信模式。
    发送者(pub)发送消息,订阅者(sub)接收消息。
    在这里插入图片描述

  • 下图展示了频道 Channel1,以及订阅这个频道的三个客户端 Client2、Client5 和 Client1 之间的关系。
    在这里插入图片描述

  • 当有新消息通过 PUBLISH 命令发送给频道 Channel1 时, 这个消息就会被发送给订阅它的三个客户端。
    在这里插入图片描述

在这里插入图片描述


1. 订阅

127.0.0.1:6379> subscribe qs-home
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "qs-home"
3) (integer) 1
# 等待接收消息...

1) "message"		# 消息类型
2) "qs-home"		# 频道
3) "hello consumer"	# 消息内容

2. 发布

127.0.0.1:6379> publish qs-home "hello consumer"
(integer) 2		# 订阅者个数

3. 原理

  • Redis 是使用 C 实现的,通过分析 Redis 源码里的 pubsub.c 文件。
    了解 发布 和 订阅 机制的底层实现,加深对 Redis 的理解。

  • Redis 通过 PUBLISH、SUBSCRIBE 和 PSUBSCRIBE 等命令,实现 发布 和 订阅 功能。
  1. 通过 SUBSCRIBE 命令 订阅某频道后,Redis Server 里维护了一个字典。
    字典的键就是一个个 Channel。
    而字典的值则是一个链表,链表中保存了 所有订阅这个 Channel 的客户端。
    SUBSCRIBE 命令的关键,就是将 客户端 添加到给定 Channel 的订阅链表中。
  2. 通过 PUBLISH 命令 向 订阅者 发送消息,Redis Server 会使用 给定的频道 作为键。
    在它所维护的 Channel 字典中,查找记录了订阅这个频道的所有客户端的链表。
    遍历这个链表,将消息发布给所有订阅者。
    在这里插入图片描述

  • Pub/Sub 从字面上理解就是 发布(Publish)与 订阅(Subscribe)。
  • 在 Redis 中,你可以设定对某一个 key值 进行 消息发布 及 消息订阅。
    当一个 key值 上进行了 消息发布 后,所有 订阅它的客户端 都会收到相应的消息。
  • 这一功能最明显的用法就是用作 实时消息系统。
    比如:即时聊天,群聊 等功能。

四、缓存穿透、缓存击穿 和 缓存雪崩


1. 缓存穿透(非法查询、目标不存在)

  • 缓存穿透 的概念很简单,用户想要查询一个数据。
    发现 Redis 内存数据库没有,也就是缓存没有命中。
    于是向持久层数据库查询,发现也没有,于是本次查询失败。
  • 当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。
  • 这会给 持久层数据库 造成很大的压力,这时候就相当于出现了 缓存穿透(缓存失效)

1.1 解决方案一 > 布隆过滤器
  • 布隆过滤器 是一种数据结构。
    对所有可能 查询的参数 以 Hash 形式存储
  • 在控制层先进行校验,不符合则丢弃,从而避免了对 底层存储系统 的查询压力。
    在这里插入图片描述

1.2 解决方案二 > 缓存空对象
  • 当存储层不命中后,即使返回的 空对象 也将其缓存起来,同时会设置一个 过期时间。
  • 之后再访问这个数据将会从缓存中获取,保护了后端数据源。
    在这里插入图片描述

  • 这种方法会存在两个问题。
  1. 如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键。
    因为这当中可能 会有很多的空值的键
  2. 即使对空值设置了过期时间。
    还是 会存在 缓存层 和 存储层 的数据 会有一段时间窗口的不一致
    这对于需要保持一致性的业务会有影响。

2. 缓存击穿(热点缓存过期)

  • 需要注意和 缓存穿透 的区别。
    缓存击穿 是指一个 key 非常热点,在不停的扛着大并发。
    大并发集中对这一个点进行访问。
  • 当这个 key 在失效的瞬间,持续的大并发就击穿缓存。
    直接请求数据库,就像在屏障上凿开了一个洞。

  • 当某个 key 在过期的瞬间,有大量的请求并发访问,这类数据一般是 热点数据。
  • 由于缓存过期,会同时访问数据库来查询最新数据,并且回写缓存。
    会导使数据库瞬间压力过大。

2.1 解决方案一 > 设置热点数据永不过期
  • 从缓存层面来看,没有设置过期时间,所以不会出现热点 key 过期后产生的问题。

2.2 解决方案二 > 加互斥锁
  • 分布式锁。
    使用 分布式锁,保证对于每个 key 同一时间只能一个线程去查询后端服务。
    其他线程没有获得 分布式锁 的权限,因此只需要等待即可。
  • 这种方式将 高并发 的压力转移到了 分布式锁,因此对 分布式锁 的考验很大。
    在这里插入图片描述

3. 缓存雪崩(大量缓存过期)

  • 缓存雪崩,是指在某一个时间段,缓存集中过期失效。
  • Redis 宕机。

  • 产生雪崩的原因之一,比如在双十一 零点 会迎来一波抢购。
    这波 商品时间 比较集中的放入了 缓存,假设缓存一个小时。
  • 那么到了 凌晨一点钟 的时候,这批商品的缓存就 都过期了。
  • 而对这批商品的访问查询,都落到了数据库上。
    对于数据库而言,就会产生周期性的压力波峰。
  • 于是所有的请求都会到达 存储层,存储层 的调用量会暴增。
    造成存储层也会挂掉的情况。
    在这里插入图片描述

  • 其实集中过期,倒不是非常致命。
    比较致命的 缓存雪崩,是 缓存服务器 某个 节点宕机 或 断网。
  • 因为自然形成的 缓存雪崩,一定是在某个时间段集中创建缓存。
    这个时候,数据库也是可以顶住压力的。
  • 无非就是对 数据库 产生周期性的压力而已。
  • 而缓存 服务节点 的宕机,对 数据库服务器 造成的压力是不可预知的。
    很有可能瞬间就把数据库压垮。

3.1 解决方案一 > Redis 高可用
  • 这个思想是,既然 Redis 有可能挂掉,那多增设几台 Redis。
    这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群(异地多活)。

3.2 解决方案二 > 限流降级
  • 这个解决方案的思想是,在缓存失效后。
    通过 加锁 或者 队列 来控制 读数据库写缓存 的线程数量。
  • 比如对 某个key 只允许一个线程 查询数据 和 写缓存,其他线程等待。

3.3 解决方案三 > 数据预热
  • 数据预热 的含义就是在正式部署之前,先把可能的数据先预先访问一遍。
    这样部分可能大量访问的数据,就会预先加载到缓存中。
  • 在即将发生大并发访问前,手动触发加载缓存不同的 key。
    设置不同的过期时间,让缓存失效的时间点尽量均匀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

骑士梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值