可以合理的查看,以及理解修改配置文件,能帮助咱们更好的使用 Redis,下面按照 Redis 配置文件的顺序依次往下讲redis
主从复制会在下面专门讲解,这里暂时略过算法
接下来的 SECURITY 部分,注释中有说起到关于密码的设置,这里多提一下在客户端中设置密码的方式shell
127.0.0.1:6379> ping PONG 127.0.0.1:6379> config get requirepass # 获取redis的密码 1) "requirepass" 2) "" 127.0.0.1:6379> config set requirepass "123456" # 设置redis的密码 OK 127.0.0.1:6379> config get requirepass # 发现全部的命令都没有权限 (error) NOAUTH Authentication required. 127.0.0.1:6379> ping (error) NOAUTH Authentication required. 127.0.0.1:6379> auth 123456 # 使用密码进行登陆 OK 127.0.0.1:6379> config get requirepass 1) "requirepass" 2) "123456"
CLIENTS 客户端链接部分,注释太多,这里很差截图,就简单说一说数据库
maxclients —— 最大客户端数量vim
maxmemory —— 最大内存限制centos
maxmemory-policy noeviction —— 内存达到限制值的处理策略缓存
redis 中的默认的过时策略是 volatile-lru ,设置方式以下:服务器
config set maxmemory-policy volatile-lru
maxmemory-policy 六种方式
volatile-lru:只对设置了过时时间的key进行LRU(默认值)网络
allkeys-lru : 删除lru算法的key架构
volatile-random:随机删除即将过时key
allkeys-random:随机删除volatile-ttl :删除即将过时的
noeviction: 永不过时,返回错误
前面已经讲过,Redis是一个内存数据库,也就是说,咱们的数据所有存储在内存中,而咱们常见的MySQL和Oracle等SQL数据库会将数据存储到硬盘中,凡事都是有利有弊,虽然内存数据库读写速度要比在硬盘中读写的数据库快的多,可是却出现了一个很麻烦的问题,也就是说,当 Redis 服务器重启或者宕机后,内存中的数据会所有丢失,为了解决这个问题,Redis提供了一种持久化的技术,也就是将内存中的数据存储到硬盘中去,往后方便咱们使用这些文件恢复数据库中的数据
在配置文件的解释中,提到了两种持久化方式 RDB、AOF ,下面咱们具体来说解一下:
在指定时间间隔后,将内存中的数据集快照写入数据库 ,在恢复时候,直接读取快照文件,进行数据的恢复
简单理解:必定的时间内,检测key的变化状况,而后持久化数据
默认状况下, Redis 将数据库快照保存在名字为 dump.rdb 的二进制文件中。
文件名能够在配置文件中进行自定义,例如:dbfilename dump.rdb
在进行 RDB
的时候,redis
的主线程是不会作 io
操做的,主线程会 fork
一个子线程来完成该操做(这也是保证了其极大性能的特色)
这种工做方式使得 Redis 能够从写时复制(copy-on-write)机制中获益(由于是使用子进程进行写操做,而父进程依然能够接收来自客户端的请求。)
咱们知道了一个进程如何采用请求调页,仅调入包括第一条指令的页面,从而可以很 快开始执行。然而,经过系统调用 fork() 的进程建立最初能够经过使用相似于页面共享的技术,绕过请求调页的须要。这种技术提供了快速的进程建立,并最小化必须分配给新建立进程的新页面的数量。
回想一下,系统调用 fork() 建立了父进程的一个复制,以做为子进程。传统上,fork() 为子进程建立一个父进程地址空间的副本,复制属于父进程的页面。然而,考虑到许多子进程在建立以后当即调用系统调用 exec(),父进程地址空间的复制可能没有必要。
所以,能够采用一种称为写时复制的技术,它经过容许父进程和子进程最初共享相同的页面来工做。这些共享页面标记为写时复制,这意味着若是任何一个进程写入共享页面,那么就建立共享页面的副本。
知足 save 条件会自动触发 rdb 原则
执行save / bgsave / flushall命令,也会触发 rdb 原则
退出 Redis,也会自动产生 rdb 文件(默认生成位置就是 redis 的启动目录)
只要将 rdb 文件,放在 Redis 的启动目录,Redis 会自动在这个目录下检查 dump.rdb 文件,而后恢复其中的数据
查询配置文件中位置的命令
127.0.0.1:6379> config get dir 1) "dir" 2) "/usr/local/bin"
优势:
缺点:
以日志的形式来记录每一个写的操做,将Redis执行过的全部指令记录下来(读操做不记录),只许追加文件但不能够改写文件,redis启动之初会读取该文件从新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工做。
若是你不深究其背后的操做,能够简单理解为:每个操做执行后,进行持久化操做
想要使用 AOF 方式,须要主动打开,由于默认使用的是 RDB
在配置文件中,咱们找到这两行,能够设置 aof 的启动,以及其持久化文件的名字
appendonly no
:no 表明关闭 aof,改成 yes 表明开启
appendfilename "appendonly.aof"
—— 持久化文件的名字
这里能够修改其持久化的一个方式
appendfsync always
—— 每次修改都会 sync(消耗性能 )
appendfsync everysec
—— 每秒执行一次 sync,可能会丢失这1s的数据
appendfsync no
—— 不执行 sync,操做系统本身同步数据,速度最快
其默认是无限追加模式的,若是 aof 文件大于 64m,就 fork一个新的进程来将咱们的文件进行重写
no-appendfsync-on-rewrite no aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
若是这个 aof 文件有错位,这时候redis是启动不起来的
Redis 给咱们提供了一个工具 redis-check-aof --fix
# 命令示例 redis-check-aof --fix appendonly.aof
优势
缺点
若是你只但愿你的数据在服务器运行的时候存在,你也能够不使用任何持久化,即只当作缓存使用
同时开启两种持久化方式
在这种状况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,由于在一般状况下AOF
文件保存的数据集要比RDB文件保存的数据集要完整。
RDB 的数据不实时,同时使用二者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?做者
建议不要,由于RDB更适合用于备份数据库(AOF在不断变化很差备份),快速重启,并且不会有
AOF可能潜在的Bug,留着做为一个万一的手段。
性能建议
由于RDB文件只用做后备用途,建议只在Slave上持久化RDB文件,并且只要15分钟备份一次就够
了,只保留 save 900 1 这条规则。
若是Enable AOF ,好处是在最恶劣状况下也只会丢失不超过两秒数据,启动脚本较简单只load自
己的AOF文件就能够了,代价以下:
一是带来了持续的IO,
二是AOF rewrite 的最后将 rewrite 过程当中产生的新数据写到新文件形成的阻塞几乎是不可避免的。
所以只要硬盘许可,应该尽可能减小AOF rewrite的频率,AOF重写的基础大小默认值64M过小了,能够设到5G以上,默认超过原大小100%大小重写能够改到适当的数值。
若是不Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也能够,能省掉一大笔IO,也
减小了rewrite时带来的系统波动。
这部分,用的不是特别多,做为一个补充。 下面是我在 菜鸟教程(runoob)贴过来的定义,重制了一下图
定义:Redis 发布订阅 (pub/sub) 是一种消息通讯模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。
Redis 客户端能够订阅任意数量的频道。
下图展现了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:
当有新消息经过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:
PSUBSCRIBE pattern [pattern..]
—— 订阅一个或多个符合给定模式的频道。PUNSUBSCRIBE pattern [pattern..]
—— 退订一个或多个符合给定模式的频道。PUBSUB subcommand [argument[argument]]
—— 查看订阅与发布系统状态。PUBLISH channel message
—— 向指定频道发布消息SUBSCRIBE channel [channel..]
—— 订阅给定的一个或多个频道。SUBSCRIBE channel [channel..]
—— 退订一个或多个频道演示
------------订阅端---------------------- 127.0.0.1:6379> SUBSCRIBE ideal-20 # 订阅ideal-20频道 Reading messages... (press Ctrl-C to quit) # 等待接收消息 1) "subscribe" # 订阅成功的消息 2) "ideal-20" 3) (integer) 1 1) "message" # 接收到来自 ideal-20 频道的消息 "hello ideal" 2) "ideal-20" 3) "hello ideal" 1) "message" # 接收到来自 ideal-20 频道的消息 "hello i am ideal-20" 2) "ideal-20" 3) "Hi,i am BWH_Steven" --------------消息发布端------------------- 127.0.0.1:6379> PUBLISH ideal-20 "hello ideal" # 发布消息到ideal-20频道 (integer) 1 127.0.0.1:6379> PUBLISH ideal-20 "Hi,i am BWH_Steven" # 发布消息 (integer) 1 -----------------查看活跃的频道------------ 127.0.0.1:6379> PUBSUB channels 1) "ideal-20"
说明:每一个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构,而结构的 pubsub_channels 属性是一个字典, 这个字典就用于保存订阅频道的信息
例子示意图:在下图展现的这个 pubsub_channels 示例中, client2 、 client5 和 client1 就订阅了 channel1(频道1) ,其余 channel (频道)同理
有了这个结构上的概念,订阅以及发布的动做就很好理解了:
订阅:当客户端调用 SUBSCRIBE 命令执行订阅频道操做时,程序就会把一个个客户端(client)和要订阅的频道(channel)在 pubsub_channels 中关联起来
发布: 程序首先根据 channel 定位到字典的键(例如找到 channel1), 而后将信息发送给字典值链表中的全部客户端(例如 client二、client五、client1)。
首先,在一个项目中,使用一台 Redis 服务器确定是有问题的:
一台服务器处理全部请求,压力过大,且容易出现故障,会致使整个相关服务出现问题
一台服务器的内存是有限的,不可能将全部内存用做 Redis 存储(推荐不该该超过 20g)
大部分场景下,大部分都是读的操做,写的操做会相对少一点,因此对读取的要求会大一些
而主从复制就能够将读写分离,下面来一块儿了解一下
主从复制,是指将一台Redis服务器的数据,复制到其余的Redis服务器
前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower)
数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)
简单理解一下就是:一台服务器做为主机器,其余服务器做为从机器,他们经过命令或配置进行了链接,这样从机就能获取到主机的数据了,从机能够帮主机分担不少读的请求等等
正常的状况,应该是多台不一样的服务器,为了演示方便,这里使用几个不一样的端口来模拟不一样的 Redis 服务器
首先,要使用不一样的端口,天然须要多个不一样的配置文件了,咱们先将原先的配置文件,复制三份(分别表明等会的一台主机和两台从机)
# 一段都是为了告诉你们个人配置文件的目录,即redis 启动目录下面的 myconfig 目录下 [root@centos7 ~]# cd /usr/local/bin [root@centos7 bin]# ls appendonly.aof dump.rdb myconfig redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-sentinel redis-server temp-2415.rdb [root@centos7 bin]# cd myconfig/ [root@centos7 myconfig]# ls redis.conf # 复制三份,分别按照等会的端口号起名 [root@centos7 myconfig]# cp redis.conf redis6379.conf [root@centos7 myconfig]# cp redis.conf redis6380.conf [root@centos7 myconfig]# cp redis.conf redis6381.conf # 这样三份就赋值好了 [root@centos7 myconfig]# ls redis6379.conf redis6380.conf redis6381.conf redis.conf
复制后,就须要分别经过 vim 修改每一个配置文件的 port 、daemonize、pid 、 logfile、dbfilename
例如:
port 6380 daemonize yes pidfile /var/run/redis_6380.pid logfile "6380.log" dbfilename dump6380.rdb
在 XShell 中再打开两个窗口,而后分别运行不一样端口号的 Redis
在第一个窗口运行 Redis 服务,使用 6379 这个配置文件
[root@centos7 bin]# redis-server myconfig/redis6379.conf
其余两个也是同理,分别启动 6380、6381
查看一下,三个端口的 Redis 都启动了
一主二从,就是表明一台主机,还有两台是从机,而 Redis 默认都是主机,也就是说,咱们上面模拟搭建出来的几台 Redis 服务器,如今还都是主机,并且相互之间并不存在什么关系
在客户端中经过 info replication
命令能够查看当前的一个信息
127.0.0.1:6379> info replication # Replication role:master # 当前是一个 master 主机 connected_slaves:0 master_replid:bfee90411a4ee99e80ace78ee587fdb7b564b4b4 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
说明:如下演示中主机端口号为 6379,两台从机分别为 6380、6381
配置一主二从,只须要配置从机,使用 SLAVEOF 127.0.0.1 6379
便可
分别在 6380 和 6381 的窗口中执行
而后查询从机自身的信息,例如查询 6380 这台
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:1 master_sync_in_progress:0 slave_repl_offset:364 slave_priority:100 slave_read_only:1 connected_slaves:0 master_replid:bd7b9c5f3bb1287211b23a3f62e41f24e009b77e master_replid2:0000000000000000000000000000000000000000 master_repl_offset:364 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:85 repl_backlog_histlen:280
一样在主机中查询,也能看到有两台从机已经链接
127.0.0.1:6379> info replication # Replication role:master connected_slaves:2 slave0:ip=127.0.0.1,port=6381,state=online,offset=84,lag=0 # 第一台 slave1:ip=127.0.0.1,port=6380,state=online,offset=84,lag=0 # 第二台 master_replid:bd7b9c5f3bb1287211b23a3f62e41f24e009b77e master_replid2:0000000000000000000000000000000000000000 master_repl_offset:84 second_repl_offset:-1 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:1 repl_backlog_histlen:84
上面使用命令的方式,须要每一次重启等都须要执行命令,而将其写到配置文件中的时候,就能够每次根据配置自动加载了,首先修改从机配置文件中的 replicaof 后面跟随主机的 ip 和 端口
若是主机的 Redis 设置了密码,别忘了在从机中的 masterauth 中加上主机的密码
从机只能读,不能写,主机可读可写可是多用于写。
主机断电/宕机后,默认角色不变,从机还是从机,集群只是失去了写操做,等待主机恢复,会从新回到原来的状态
slaveof no one
使其成为主机从机断电/宕机后,若以前使用的是命令的方式称为从机,则启动后没法获取主机,从新配置或者是使用配置文件的方式成为从机,重启后,能够从新获取到主机全部数据
Slave(从机) 启动成功链接到 Master(注解) 后会发送一个 sync(同步命令)
Master 接到命令,启动后台的存盘进程,同时收集全部接收到的用于修改数据集命令,在后台进程执行,完毕以后,master将传送整个数据文件到slave,并完成一次彻底同步。
全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master 继续将新的全部收集到的修改命令依次传给slave,完成同步
可是只要是从新链接master,一次彻底同步(全量复制)将被自动执行,从机中就能看到全部数据
在前面的主从复制的概念中,咱们知道,一旦主服务器宕机,就须要使用手动的方式,将一台从服务器切换为主服务器,这种方式很麻烦,还有一种方式就是哨兵模式,也是一种比较推荐的方式
定义:哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,做为进程,它会独立运行。其原理是哨兵经过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
其做用以下:
单哨兵与多哨兵模式:
单哨兵模式:以独立的进程监控3台 Redis 服务器是否正常运行
多哨兵模式:除了监控Redis 服务器,哨兵之间也会互相监控
Redis 启动目录下的 redis-sentinel 就是咱们要启动的哨兵,可是咱们须要为其指定配置文件,这样哨兵太知道要监控谁
我在个人 Redis 启动目录 /usr/local/bin/ 下的 myconfig 目录中,建立了一个名为 sentinel.conf 的配置文件
[root@centos7 bin]# vim myconfig/sentinel.conf
里面写入了其核心配置内容,即指定监控咱们本地 6379 端口的主机,后面的数字1,表明主机宕机后,会使用投票算法机制选择一台从机做为新的主机
# sentinel monitor 被监控的名称 host port 1 sentinel monitor myredis 127.0.0.1 6379 1
接着咱们回到 Redis 启动目录,以刚才那个配置文件启动哨兵
[root@centos7 bin]# redis-sentinel myconfig/sentinel.conf
启动成功以下图:
一旦将主机断开链接,等待一下,哨兵监测到,就会发起投票(这里只有一个哨兵,因此是 100%的),而后切换一台从机成为新的主机,而主机一旦从新上线后,也只能做为新主机的一台从机了
能够根据哨兵这边自动弹出来的日志看到,首先 6379 这台主机断开后,1 个哨兵认为其断开,而后下面的 switch 即选择了新的 6380 做为新的主机,6379 从新上线后,只能做为 6380 的从机了
查看一下 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=147896,lag=0 slave1:ip=127.0.0.1,port=6379,state=online,offset=147764,lag=0 master_replid:d32e400babb8bfdabfd8ea1d3fc559f714ef0d5a master_replid2:bd7b9c5f3bb1287211b23a3f62e41f24e009b77e master_repl_offset:147896 second_repl_offset:7221 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:85 repl_backlog_histlen:147812
实际上最核心的也就是咱们刚才演示中的那一句即下面的:sentinel monitor mymaster 127.0.0.1 6379 1
还有端口修改会用到,其余的能够根据状况设置
其配置文件仍是比较复杂的
# Example sentinel.conf # 哨兵sentinel实例运行的端口 默认26379 port 26379 # 哨兵sentinel的工做目录 dir /tmp # 哨兵sentinel监控的redis主节点的 ip port # master-name 能够本身命名的主节点名字 只能由字母A-z、数字0-9 、这三个字符".-_"组成。 # quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了 # sentinel monitor <master-name> <ip> <redis-port> <quorum> sentinel monitor mymaster 127.0.0.1 6379 1 # 当在Redis实例中开启了requirepass foobared 受权密码 这样全部链接Redis实例的客户端都要提供密码 # 设置哨兵sentinel 链接主从的密码 注意必须为主从设置同样的验证密码 # sentinel auth-pass <master-name> <password> sentinel auth-pass mymaster MySUPER--secret-0123passw0rd # 指定多少毫秒以后 主节点没有应答哨兵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 # SCRIPTS EXECUTION #配置当某一事件发生时所须要执行的脚本,能够经过脚原本通知管理员,例如当系统运行不正常时发邮件通知相关人员。 #对于脚本的运行结果有如下规则: #若脚本执行后返回1,那么该脚本稍后将会被再次执行,重复次数目前默认为10 #若脚本执行后返回2,或者比2更高的一个返回值,脚本将不会重复执行。 #若是脚本在执行过程当中因为收到系统中断信号被终止了,则同返回值为1时的行为相同。 #一个脚本的最大执行时间为60s,若是超过这个时间,脚本将会被一个SIGKILL信号终止,以后从新执行。 #通知型脚本:当sentinel有任何警告级别的事件发生时(好比说redis实例的主观失效和客观失效等等),将会去调用这个脚本, #这时这个脚本应该经过邮件,SMS等方式去通知系统管理员关于系统不正常运行的信息。调用该脚本时,将传给脚本两个参数, #一个是事件的类型, #一个是事件的描述。 #若是sentinel.conf配置文件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,而且是可执行的,不然sentinel没法正常启动成功。 #通知脚本 # sentinel notification-script <master-name> <script-path> sentinel notification-script mymaster /var/redis/notify.sh # 客户端从新配置主节点参数脚本 # 当一个master因为failover而发生改变时,这个脚本将会被调用,通知相关的客户端关于master地址已经发生改变的信息。 # 如下参数将会在调用脚本时传给脚本: # <master-name> <role> <state> <from-ip> <from-port> <to-ip> <to-port> # 目前<state>老是“failover”, # <role>是“leader”或者“observer”中的一个。 # 参数 from-ip, from-port, to-ip, to-port是用来和旧的master和新的master(即旧的slave)通讯的 # 这个脚本应该是通用的,能被屡次调用,不是针对性的。 # sentinel client-reconfig-script <master-name> <script-path> sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
此部分为一个补充知识点,本文重点仍是 Redis 的一个基本入门,而下面的这些知识点,更多的是在具体场景中产生的一些问题,并且其每个内容展开讲都是很是复杂的,因此这里只作一个基本概念的介绍,不作详细说明
用户查询数据,首先在 Redis 缓存中去查,若是没有,也就是缓存没有命中,就会去持久层数据库,例如 MySQL 中去查。
缓存穿透:大量缓存未命中的状况下,大量请求持久层数据库,持久层数据库承载很大的压力,出现问题。
常看法决方案有两种:
① 布隆过滤器:
对全部可能查询的参数以Hash的形式存储,以便快速肯定是否存在这个值,在控制层先进行拦截校验,校验不经过直接打回,减轻了存储系统的压力。
② 缓存空对象:
次请求若在缓存和数据库中都没找到,就在缓存中方一个空对象用于处理后续这个请求
不过此方法存在两种问题:
定义:缓存击穿,是指一个key很是热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞
解决方案:
设置热点数据永不过时
这样就不会出现热点数据过时的状况,可是当 Redis 内存空间满的时候也会清理部分数据,并且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。
加互斥锁(分布式锁)
在访问 key 以前,采用SETNX(set if not exists)来设置另外一个短时间key来锁住当前key的访问,访问结束再删除该短时间 key 。保证同时刻只有一个线程访问。这样对锁的要求就十分高。
大量的key设置了相同的过时时间,致使在缓存在同一时刻所有失效,形成瞬时DB请求量大、压力骤增,引发雪崩。
解决方案:
① redis高可用
② 限流降级
③ 数据预热