Redis进阶

1、Redis.conf详解

这是Redis中的一个配置文件

image-20200914194156161

单位

image-20200914114813892

配置文件unit单位对大小写不敏感

包含

image-20200914114943886

例如学习java的import、include

网路

image-20200914115052707

bind 127.0.0.1    # 绑定的ip
protected-mode yes    # 保护模式
port 6379    # 端口的设置

通用GENERAL

image-20200914115322270

daemonize no    # 以守护进程的方式运行,默认为no,我们需要自己开启为yes!

pidfile /var/run/redis_6379.pid        # 如果上面那个设置为yes,那就需要指定一个pid进程文件

# 日志
# Specify the server verbosity level.
# This can be one of:
# debug (a lot of information, useful for development/testing)
# verbose (many rarely useful info, but not a mess like the debug level)
# notice (moderately verbose, what you want in production probably)
# warning (only very important / critical messages are logged)
loglevel notice
logfile ""    #日志文件名
databases 16    # 数据库的数量,默认为16个数据库
always-show-logo yes    # 是否在启动的时候显示Logo

快照

image-20200914120132745

持久化,在规定的时间内,执行了多少次操作,则会持久化到文件.rdb.aof

# 如果在900秒内进行了1 key修改,就会进行持久化操作
save 900 1
# 如果在300秒内进行了10 key修改,就会进行持久化操作
save 300 10
# 如果在60秒内进行了10000 key修改,就会进行持久化操作
save 60 10000

# 持久化如果出错了,是否还继续进行操作
stop-writes-on-bgsave-error yes

# 是否压缩rdb文件,需要消耗一些cpu资源
rdbcompression yes

# 保存rdb文件的时候是否进行错误的检查校验
rdbchecksum yes

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

REPLICATION 复制(在主从复制的部分讲解)

image-20200914120911975

SECURITY

image-20200914121137841

可以在这里设置密码,默认没有密码

# 测试连接
127.0.0.1:6379> ping
PONG
# 查看密码
127.0.0.1:6379> config get requirepass
1) "requirepass"
2) ""
# 设置密码
127.0.0.1:6379> config set requirepass "123456"
OK
# 此时所有命令会没有权限,需要设置密码
127.0.0.1:6379> auth 123456
OK

限制 CLIENTS

image-20200914123401931

maxclients 10000    # 最大客户端数量

maxmemory <bytes>    # 最大的内存容量

maxmemory-policy noeviction    # 内存到达上限之后的处理策略,可以移除过期的key、报错等
    1. volatile-lru:从已设置过期时间的内存数据集中挑选最近最少使用的数据 淘汰;
    2. volatile-ttl: 从已设置过期时间的内存数据集中挑选即将过期的数据 淘汰;
    3. volatile-random:从已设置过期时间的内存数据集中任意挑选数据 淘汰;
    4. allkeys-lru:从内存数据集中挑选最近最少使用的数据 淘汰;
    5. allkeys-random:从数据集中任意挑选数据 淘汰;
    6. noeviction(驱逐):禁止驱逐数据。(默认淘汰策略。当redis内存数据达到maxmemory,在该策略下,直接返回OOM错误);

APPEND ONLY 模式 aof配置

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

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

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

2、Redis持久化

Redis使内存数据库,如果不将内存中的数据库状态保存到磁盘,那么一旦服务器进程退出(执行shutdown命令),服务器中的数据库状态也会消失,所以Redis提供了持久化功能!

1、RDB(Redis DataBase)

什么是RDB

image-20200914190416226

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

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

RDB的缺点就是最后一次持久化后的数据可能丢失。

rdb保存的文件是dump.rdb,都是在配置文件中的快照中进行配置的!

image-20200914191216239

修改配置文件进行测试

image-20200914191353567

新创建一个窗口并在一分钟内进行5个 key 的操作,这时就会触发保存机制

image-20200914192123334

触发机制

  1. save的规则满足的情况下,会自动触发rdb规则
  2. 执行 flushall 命令,也会触发rdb规则
  3. 退出redis,也会产生rdb文件

备份就自动生成一个dump.rdb文件

恢复rdb文件

  1. 只需要将rdb文件放在redis启动目录就可以了,redis启动的时候会自动检查dump.rdb 恢复其中的数据!

  2. 查看需要存放的位置

    127.0.0.1:6379> config get dir
    1) "dir"
    2) "/usr/local/bin"        # 如果在这个目录下存放dump.rdb文件,启动就会自动恢复其中的数据

优缺点

优点:

  1. 适合大规模的数据恢复!
  2. 如果对数据完整性不高,就适合使用(因为save的规则不一定在宕机前满足保存规则)!

缺点:

  1. 需要一定的时间间隔进程操作!如果redis意外宕机,这个最后一次修改的数据就没有了!
  2. fork进程的时候,会占用一定的内存空间!

2、AOF(Append Only File)

将我们的所有命令都记录下来,恢复的时候就这个文件全部在执行一遍!

什么是AOF

image-20200914193912551

以日志的形式来记录每个写操作,将Redis执行过的所有指令记录下来(读操作不记录,因为对数据不影响),只许追加文件但不可以改写文件,redis启动之初会读取文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作!

AOF保存的是 appendonly.aof文件

append

进入配置文件vim myconfig/redis.conf,输入/append就可以直接搜索出这部分的内容

image-20200914194823973

默认是不开启的,需要自己手动配置,改为yes即可。修改了配置文件之后重启一下,redis就可以生效了!

image-20200914200152043

如果这个aof文件有错误,这时候redis是启动不起来的,我们需要修复这个aof文件

redis给我们提供了一个工具redis-check-aof --fix

redis-check-aof --fix appendonly.aof

image-20200914222154370

如果文件正常,重启就可以直接恢复了!

重写规则

image-20200914223659089

如果aof文件大于64m,将会fork一个新的进城来将我们的文件进行重写,aof默认就是文件的无限追加,文件就会越来越大!

Aof配置

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

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

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

优缺点

优点:

  1. appendfsync always:每一次修改都同步,文件的完整性会更加好
  2. appendfsync everysec:每秒同步一次,可能会丢失一秒的数据
  3. appendfsync no:从不同步,效率最高

缺点:

  1. 相对于数据文件来说,aof远远大于rdb,修复速度也比rdb慢
  2. aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化

总结

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

  2. 如果同时开启两种持久化方式:

    redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

  3. 性能建议:

    因为RDB文件只用作后备用途,建议只在slave上持久化文件,只要15分钟备份一次就够了,只保留save 900 1这条规则。

    如果使用Enable AOF,好处是最多只会丢失不超过两秒的数据。

    如果不使用Enable AOF,则可以省下一大笔IO,如果Master/Slava同时倒掉,会丢失十几分钟的数据。

3、Redis发布订阅

Redis发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息

Redis客户端可以订阅任意数量的频道

image-20201006130959155

命令

  • 订阅:SUBSCRIBE 频道名称
  • 发布:PUBLISH 频道名称 信息内容

image-20201010131246453

测试

  1. 使用客户端连接Redis,作为订阅者

    # 连接Redis
    [root@iz2ze2js0u6m077omgcbzmz bin]# redis-cli -p 6379
    
    # 进行订阅
    127.0.0.1:6379> SUBSCRIBE xiaojiang
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "xiaojiang"
    3) (integer) 1
    # 下面将会自动接收消息
  2. 新打开一个窗口连接Redis,作为发布者

    # 进入bin目录
    [root@iz2ze2js0u6m077omgcbzmz bin]# cd /usr/local/bin
    
    # 连接Redis
    [root@iz2ze2js0u6m077omgcbzmz bin]# redis-cli -p 6379
    
    # 发布消息
    127.0.0.1:6379> PUBLISH xiaojiang "hello world!"
    (integer) 1
  3. 查看接收结果

    image-20201010132413370

使用场景

  1. 实时消息系统
  2. 实时聊天(把频道当成聊天室,将信息回显给所有人即可)
  3. 订阅,关注系统

稍微复杂的场景就需要使用 消息中间件MQ

4、主从复制

概念

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器,前者称为主节点(master/leader),后者称为从节点(slave/follower),数据的复制是单向的,只能由主节点到从节点

  • master以写为主
  • slave以读为主

image-20201010143450266

主从复制,读写分离!80%的情况下都是在进行读操作!减缓服务器的压力!架构中经常使用!

主从复制的作用

  1. 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余方式。
  2. 故障恢复:当主节点出现问题时,可以由从节点提供服务,实现快速的故障恢复;实际上是一个服务的冗余。
  3. 负载均衡:在主从复制的基础上,配合读写分离,可以由主节点提供写服务,由从节点提供读服务。
  4. 高可用基石:主从复制还是哨兵和集群能够实施的基础。

一般来说,要将Redis运用于工程项目中,只使用一台Redis是不够的(可能会宕机),单台Redis的最大使用内存不应该超过20G

1、环境配置

只配置从库,不配置主库!

查看当前Redis的主从复制信息

# 获取单钱库的信息
127.0.0.1:6379> info replication
# Replication
role:master        # 角色 master
connected_slaves:0        # 没有从机
master_replid:dc9fc3998a4785d3f96ef406fe19fa44bd4031b2
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

测试

  1. 打开四个服务器连接,前三个做服务集群,第四个做测试

    image-20201010145159860

  2. 要启动多个redis服务,就必须配置多个redis配置文件

    [root@iz2ze2js0u6m077omgcbzmz bin]# cd myconfig
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# ls
    redis.conf
    
    # 复制三个redis配置文件
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# cp redis.conf redis79.conf
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# cp redis.conf redis80.conf
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# cp redis.conf redis81.conf
    
    # 查看是否创建成功
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# ls
    redis.conf  redis79.conf  redis80.conf  redis81.conf
  3. 将复制的配置文件改为对应的端口号

    # 依次修改文件
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# vim redis79.conf  
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# vim redis80.conf
    [root@iz2ze2js0u6m077omgcbzmz myconfig]# vim redis81.conf

    修改如下四处(对于redis79.conf只需要修改后面两处)

    1. 端口
    2. pid 名字
    3. log 文件名字
    4. dump.rdb 名字

    image-20201010145721122

    image-20201010145752720

    image-20201010145815432

    image-20201010150212743

  4. 启动服务

    # 在前三个端口中进行对应指令
    [root@iz2ze2js0u6m077omgcbzmz bin]# cd /usr/local/bin
    [root@iz2ze2js0u6m077omgcbzmz bin]# redis-server myconfig/redis79.conf 

    image-20201010150727364

  5. 查看服务是否启动成功

    # 查看产生的日志文件
    [root@iz2ze2js0u6m077omgcbzmz bin]# ls 
    
    # 查看Redis的后台进程
    [root@iz2ze2js0u6m077omgcbzmz bin]# ps -ef|grep redis

    image-20201010150828084

2、一主二从配置

默认情况下,每一台Redis都是主节点

image-20201010151405846

我们一般情况下只要配置从机就好了!

一主(79)二从(80、81)

  1. 在两台从机中执行如下指令

    # 认领ip地址为127.0.0.1的6379端口为主机
    127.0.0.1:6380> SLAVEOF 127.0.0.1 6379
    
    # 查看当前自己的信息
    127.0.0.1:6380> info replication
    # Replication
    role:slave        # 角色变为从机
    master_host:127.0.0.1        # 主机地址
    master_port:6379        # 主机端口
    master_link_status:up
    master_last_io_seconds_ago:6
    master_sync_in_progress:0
    slave_repl_offset:14
    slave_priority:100
    slave_read_only:1
    connected_slaves:0
    master_replid:df35ec1b9a90e6170861ab1a70e4849d2a8a57c8
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:14
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:14
  2. 此时再次查看主机的信息

    127.0.0.1:6379> info replication
    # Replication
    role:master        # 79已经成为了主机
    connected_slaves:2        # 下面拥有两台从机
    slave0:ip=127.0.0.1,port=6380,state=online,offset=140,lag=1
    slave1:ip=127.0.0.1,port=6381,state=online,offset=140,lag=1
    master_replid:df35ec1b9a90e6170861ab1a70e4849d2a8a57c8
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:140
    second_repl_offset:-1
    repl_backlog_active:1
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:1
    repl_backlog_histlen:140

真实的主从配置应该在配置文件中配置,这样的话才是永久的,我们这里使用的是命令,只是暂时的!

配置文件修改

# 进行配置文件修改
[root@iz2ze2js0u6m077omgcbzmz myconfig]# vim redis80.conf

配置主机信息

image-20201010152643314

重启Redis之后发现配置文件依然生效

image-20201010152919484

细节

主机可以写,从机不能写只能读!主机中的所有信息和数据都会被从机自动保存!

  1. 在主机中设置值

    image-20201010153213094

  2. 在从机中可以获取对应的值

    image-20201010153220476

  3. 而在从机中设置值会报错

    image-20201010153343247

主机宕机的情况

所以如果主机宕机了,从机的内容还存在(并且从机还是从机),此时已经没有主机了,这个时候没有了写操作。

而当主机重新连接上了之后,则会恢复到之前的状态,从机依然会自动保存主机的内容。

从机宕机的情况

情况一:使用命令行配置的从机

  1. 当该从机宕机之后,主机的从机就会减少一个
  2. 在从机宕机期间,主机新增数据
  3. 当从机恢复连接之后,会发现该从机已经自动变回了一台主机,所以获取不到在宕机期间主机设置的值
  4. 再次进行命令行的配置,将该服务设置为从机,此时发现可以获取到宕机期间主机设置的值

情况二:使用配置文件设置的从机

  1. 当该从机恢复连接之后,它依旧是一台从机,并且可以获取到宕机期间设置的值

复制原理

  1. Slave从机 启动成功连接到 Master主机 后会发送一个sync同步命令
  2. Master 接收到命令,启动后台的存盘进程,同时手机所有接收到的用于修改数据集命令
  3. 在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步

全量复制:slave服务在接收到数据库文件数据后,将其存盘并加载到内存中

增量复制:master继续将新的所有收集到的修改命令依次传给slave,完成同步

但是只要是重新连接master,一次完全同步(全量复制)将被自动执行

层层链路

一个从节点连接到上一个从节点!

image-20201010214839412

这个时候也可以完成主从复制,但80依旧是从节点!

主节点断开之后,自动选择下一个主节点

如果将主从复制在配置文件中修改的,那这一步将会比较麻烦

谋朝篡位

如果主机断开了连接,我们可以使用SLAVEOF no one使自己变成主机!其他节点就可以手动连接到最新的主节点(手动)!

这个时候如果主机重新连接上了,也没有效果了,需要重新连接!

3、哨兵模式

自动选举老大的模式

概述

主从切换技术的方法是:当主服务器宕机后,需要手动把一个从节点切换为主节点,这个需要人工干预,费时费力,还会造成一段时间内服务不可用。

谋朝篡位的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换未主库。

哨兵模式是一种特殊的模式,首先Redis提供哨兵的命令,哨兵是一个独立的进程,作为进程,他会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。

image-20201010220157178

哨兵的作用

  1. 通过发送命令,让Redis服务器返回将恐其运行状态,包括主服务器和从服务器
  2. 当哨兵检测到master宕机,会自动将slave切换到master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让他们却换主机。

多哨兵模式

当只有一个哨兵进行监控的时候可能会出现问题,因此需要进行多哨兵模式进行监控,各个哨兵之间也会进行相互监控!但该模式需要开启更多的进程!

image-20201010220510702

监控过程:

  1. 假设主服务器宕机了,哨兵1检测到这个结果,系统不会马上进行failover [故障转移]过程,仅仅是一个哨兵认为主服务器不可以用,这个现象称为主观下线
  2. 当后面的哨兵也检测到主服务器不可用了,并且数量达到了一定值时,那么哨兵就会进行一次投票
  3. 如果投票结果通过,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线,然后通过再次投票选出新的主服务器

测试:

  1. myconfig目录下新创建文件sentinel.conf

    cd /usr/local/bin/myconfig
    
    # 创建文件
    vim sentinel.conf
  2. 编写内容

    # sentinel monitor 被监控的名称 host port 1
    sentinel monitor myredis 127.0.0.1 6379 1

    后面的 1 表示,当主机挂了,slave投票看让谁接替为主机,票数最多的就会称为主机

  3. 启动哨兵

    redis-sentinel myconfig/sentinel.conf

    启动结果

    [root@iz2ze2js0u6m077omgcbzmz bin]# redis-sentinel myconfig/sentinel.conf
    10974:X 10 Oct 2020 22:23:08.927 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    10974:X 10 Oct 2020 22:23:08.927 # Redis version=6.0.6, bits=64, commit=00000000, modified=0, pid=10974, just started
    10974:X 10 Oct 2020 22:23:08.927 # Configuration loaded
                    _._                                                  
               _.-``__ ''-._                                             
          _.-``    `.  `_.  ''-._           Redis 6.0.6 (00000000/0) 64 bit
      .-`` .-```.  ```\/    _.,_ ''-._                                   
     (    '      ,       .-`  | `,    )     Running in sentinel mode
     |`-._`-...-` __...-.``-._|'` _.-'|     Port: 26379
     |    `-._   `._    /     _.-'    |     PID: 10974
      `-._    `-._  `-./  _.-'    _.-'                                   
     |`-._`-._    `-.__.-'    _.-'_.-'|                                  
     |    `-._`-._        _.-'_.-'    |           http://redis.io        
      `-._    `-._`-.__.-'_.-'    _.-'                                   
     |`-._`-._    `-.__.-'    _.-'_.-'|                                  
     |    `-._`-._        _.-'_.-'    |                                  
      `-._    `-._`-.__.-'_.-'    _.-'                                   
          `-._    `-.__.-'    _.-'                                       
              `-._        _.-'                                           
                  `-.__.-'                                               
    
    10974:X 10 Oct 2020 22:23:08.929 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
    10974:X 10 Oct 2020 22:23:08.930 # Sentinel ID is c59290b3611548bba760b2eda2111a686758aa96
    10974:X 10 Oct 2020 22:23:08.930 # +monitor master myredis 127.0.0.1 6379 quorum 1
    10974:X 10 Oct 2020 22:23:08.931 * +slave slave 127.0.0.1:6380 127.0.0.1 6380 @ myredis 127.0.0.1 6379
    10974:X 10 Oct 2020 22:23:08.933 * +slave slave 127.0.0.1:6381 127.0.0.1 6381 @ myredis 127.0.0.1 6379
  4. 启动三个redis服务

  5. 将主服务器断开连接

    image-20201010222655546

    此时哨兵不会立马进行处理,而是等待一点时间之后进行投票确定,并选举出新的主服务器(下方为哨兵日志)

    image-20201010222954574

  6. 此时可以看到80已经成为了主服务器,选举是根据自带的算法

    image-20201010223043270

主机重新连接

如果主机此时回来了,等待哨兵判断之后,原主机只能当作从机,这就是哨兵模式的规则!

即主机一旦断开之后,即使再次连接上,也只能充当从机了

哨兵模式

优点:

  1. 哨兵集群,基于主从复制模式,所有的主从配置有点都有
  2. 主从可以切换,故障可以转移,系统的可用性就会更好
  3. 哨兵模式就是主从模式的升级,手动到自动,更加健壮!

缺点:

  1. Redis不好在线扩容,集群容量一旦到达上限,在线扩容就十分麻烦
  2. 实现哨兵模式的配置其实是很麻烦,有很多配置选择

哨兵模式的配置

参考网站:https://www.cnblogs.com/xuliangxing/p/7149322.html

# 配置监听端口号,默认26379,可用于集群配置
port 26379

# 监听地址
sentinel monitor myredis 127.0.0.1 6379 1

# 设置连接master和slave时的密码
sentinel auth-pass <master-name> <password>

# 指定需要多少失效时间,一个master才会被这个sentinel主观地认为是不可用的。 单位是毫秒,默认为30秒
sentinel down-after-milliseconds mymaster 30000

# 指定在发生failover主备切换时最多可以有多少个slave同时对新的master进行同步。可以通过将这个值设为 1 来保证每次只有一个slave 处于不能处理命令请求的状态
sentinel parallel-syncs myredis 1

5、Redis缓存穿透和雪崩(重点)

Redis缓存的使用,极大的提升了应用程序的性能和效率,特别是数据查询方面,但同时,它带来了一些问题。其中,最要害的问题就是数据的一致性问题,从严格意义上讲,这个问题无解。如果对数据一致性要求很高,那么就不能使用缓存。

另外的一些典型的问题就是,缓存穿透、缓存雪崩和缓存击穿。目前,业界也都有比较流行的解决方案。

image-20201011170555271

1、缓存穿透(查不到导致)

概述

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

解决方案

布隆过滤器

布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层进行校验,不符合则丢失,从而避免了对底层存储系统的查询压力。

image-20201011171055323

缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源。

image-20201011171300066

但是这种方法会存在两个问题:

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

2、缓存击穿(量太大,缓存过期)

例如微博热搜会导致宕机

概述

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

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

解决方案

设置热点数据永不过期

从缓存层面来看,没有设置过期时间,所以不会出现热点key过期后产生的问题。

加互斥锁

分布式锁:使用分布式锁,保证对于每个key同时只有一个线程去查询后端服务,其他线程没有获得分布式锁的权限,因此只需要等待即可。这种方式将高并发的压力转移到了分布式锁,因此对分布式锁的考验很大。

image-20201011172517422

3、缓存雪崩

概述

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

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

image-20201011172704790

例如双十一:停掉一些服务器不可用(保证高可用性能)

解决方案

redis高可用

这个思想的含义是,既然redis有可能挂掉,那多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建集群。

限流降级(在SpringCloud讲解过)

这个解决方案的思想是,缓存失效后,通过加锁或者队列来控制都数据库写缓存的线程数量。比如对某个key只能一个线程查询数据和写缓存,其他线程等待。

数据预热

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