当前位置: 首页 > news >正文

Redis精简总结|一主二从哨兵模式(工作机制)|集群模式|缓存的穿透雪崩击穿

目录

Redis精简总结

一、redis的作用和使用场景

二、redis支持的数据类型有哪些?

三、redis的常用命令

四、redis的持久化机制

五、数据的删除策略

六、数据的淘汰策略

七、事务机制

八、锁机制

九、发布订阅机制

十、一主二从(高可用)

主从切换

手动切换: slaveof no one   /     slaveof ip port

自动切换: 哨兵模式

哨兵

哨兵工作机制(背会重点)

十一、集群模式(高可用)

创建集群的过程

redis-cluster集群状态检查

redis-cluster连接测试

十二、面试题(背会)

redis雪崩、穿透、击穿

1. redis缓存使用流程

2. 缓存穿透

2.1. 概念

2.2. 解决方案

3. 缓存雪崩

3.1. 概念

3.2. 解决方案

4. 缓存击穿

4.1. 概念

4.2. 解决方案

十三、springboot项目和redis的整合


Redis精简总结

一、redis的作用和使用场景

redis是一个内存级的高速缓存数据库。(对比磁盘IO)

使用场景:1、并发访问量大的 2、数据量小 3、修改不频繁

项目中:1、验证码 2、登录成功用户信息 3、首页(模块数据 轮播图,商品分类,热点模块,推荐模块) 4、购物车(商品信息)

二、redis支持的数据类型有哪些?

目前支持10种,常用的有5种:String、list、set、zset、hash(map)、stream

三、redis的常用命令

通用命令

每种数据类型各自的命令

string类型

 设置过期时间1、set k1 v1 ex 100     --设置键k1的值为v1并设置100秒过期时间2、setex k1 100 v2      --专用命令设置k1=v2且100秒后过期3、set k1 v1 expire k1 100   --先设值再单独设置过期时间

list类型 (有序,可以重复)

主机号:端口号> lpush addressList hangzhou zhengzhou guangzhou   --从左侧插入3个城市到addressList列表
(integer) 3
1.94.230.82:6381> llen addressList   --获取addressList列表的当前元素数量
(integer) 3
1.94.230.82:6381> lrange addressList 0 -1    -- 获取列表全部元素,显示顺序为[guangzhou, zhengzhou, hangzhou](后插入的在前)
1) "guangzhou"
2) "zhengzhou"
3) "hangzhou"

set类型(无序、不可重复)

1.94.230.82:6381> sadd subjects java c java  --向集合subjects中添加元素"java"和"c"(自动去重),返回成功添加2个元素
(integer) 2
1.94.230.82:6381> sadd subjects c  --尝试再次添加已存在的元素"c",返回0表示未添加新元素
(integer) 0
1.94.230.82:6381> sadd subjects mysql  --成功添加新元素"mysql",返回1
(integer) 1
1.94.230.82:6381> smembers subjects --查看集合所有元素,显示当前集合内容:mysql、java、c,集合无序
1) "mysql"
2) "java"
3) "c"
1.94.230.82:6381> sadd subjects py  -- 成功添加新元素"py",返回1
(integer) 1
1.94.230.82:6381> smembers subjects  --再次查看集合,现在包含4个元素,集合元素的显示顺序不固定
1) "mysql"
2) "java"
3) "py"
4) "c"

hash类型(map类型 : 存储map名 key value 存储对象:对象名 属性名 属性值)

1.94.230.82:6381> hset user id 111  --创建Hash键"user",并设置字段"id"的值为111,返回1表示新增1个字段
(integer) 1
1.94.230.82:6381> hset user name zhangsan --向"user"Hash中添加字段"name",值为"zhangsan",返回1表示新增1个字段
(integer) 1
1.94.230.82:6381> hset user age 20 --向"user"Hash中添加字段"age",值为20,返回1表示新增1个字段
(integer) 1
1.94.230.82:6381> hset user age 22 -- 更新"age"字段值为22,返回0表示修改已有字段(非新增)
(integer) 0
1.94.230.82:6381> hget user id --获取"user"Hash中"id"字段的值
"111"
1.94.230.82:6381> hget user name
"zhangsan"
1.94.230.82:6381> hget user age
"22"
1.94.230.82:6381> hdel user name  --删除"name"字段,返回1表示成功删除1个字段
(integer) 1
1.94.230.82:6381> hkeys user  -获取"user"Hash中所有字段名
1) "id"
2) "age"
1.94.230.82:6381> hvals user  --获取"user"Hash中所有字段值
1) "111"
2) "22"

zset 有序的set集合 有序,不能重复 (给每一个value值,添加一个数值,通过数值保持有序)

1.94.230.82:6381> zadd sbs 1  java  2  c  3 py  --向有序集合"sbs"添加三个元素:java(1分)、c(2分)、py(3分),返回成功添加3个元素
(integer) 3
1.94.230.82:6381> zrange sbs 0 -1  -- 按分数升序显示集合所有元素:java(1分)→c(2分)→py(3分)
1) "java"
2) "c"
3) "py"
1.94.230.82:6381> zadd sbs 10 html  --添加新元素html(10分),返回成功添加1个元素
(integer) 1
1.94.230.82:6381> zrange sbs 0 -1   --当前集合元素顺序:java→c→py→html(10分)
1) "java"
2) "c"
3) "py"
4) "html"
1.94.230.82:6381> zadd sbs 5 c#   --插入c#(5分),返回成功添加1个元素
(integer) 1
1.94.230.82:6381> zrange sbs 0 -1   --最终排序结果:java(1)→c(2)→py(3)→c#(5)→html(10)
1) "java"
2) "c"
3) "py"
4) "c#"
5) "html"

四、redis的持久化机制

rdb:默认 快照模式

定时同步(1min 10000、5min 10、15min 1)

可能造成最后一次同步之后的数据丢失

性能高(新建一个进程 执行数据同步操作,不影响主进程)

dump.rdb 本地磁盘文件(实时数据)

恢复速度快

aof:日志追加模式 日志文件大

rdb文件 全量

追加命令 到 aof日志文件

恢复慢 rdb+aof 逐个命令执行,恢复

更安全,丢失的数据更少

同步机制(no(30s) always everySec)

五、数据的删除策略

定时删除 定时器删除(根据设置的过期时间)

定期删除 根据配置文件参数hz值,60/hz 循环检测各个仓库删除(抽取w个值进行检测,根据过期key的百分比 25% 循环删除)

惰性删除 过期后不立即删除。(使用时判断,过期删除)

六、数据的淘汰策略

volatile- lru lfu ttl random

allkeys- lru lfu random

no 放弃驱逐

七、事务机制

multi exec discard watch unwatch

事务的特点:

是否满足原子性: 不满足

八、锁机制

乐观锁: watch unwatch

悲观锁:setnx 分布式锁 setnx(key,value) 1 执行代码 ---- del key

九、发布订阅机制

publish 频道 message

subscribe 频道

十、一主二从(高可用)

实现读写分离、主从复制、主机执行读写,从机执行读取。

主从切换

手动切换: slaveof no one   /     slaveof ip port

自动切换: 哨兵模式

哨兵

哨兵的作用是监控 redis系统的运行状况,他的功能如下:

监控主从数据库是否正常运行

master出现故障时,自动将slave转化为master

多哨兵配置的时候,哨兵之间也会自动监控

多个哨兵可以监控同一个redis

哨兵工作机制(背会重点)

./redis-sentinel sentinel.conf

哨兵进程启动时会读取配置文件的内容,通过sentinel monitor master-name ip port quorum查找到master的ip端口。一个哨兵可以监控多个master数据库,只需要提供多个该配置项即可。

配置文件还定义了与监控相关的参数,比如master多长时间无响应即即判定位为下线。

哨兵启动后,会与要监控的master建立俩条连接:

  • 一条连接用来订阅master的sentinel:hello频道与获取其他监控该master的哨兵节点信息
  • 另一条连接定期向master发送INFO等命令获取master本身的信息

与master建立连接后,哨兵会执行三个操作,这三个操作的发送频率都可以在配置文件中配置:

  • 定期向master和slave发送INFO命令
  • 定期向master和slave的sentinel:hello频道发送自己的信息
  • 定期向master、slave和其他哨兵发送PING命令

这三个操作的意义非常重大,发送INFO命令可以获取当前数据库的相关信息从而实现新节点的自动发现。所以说哨兵只需要配置master数据库信息就可以自动发现其slave信息。获取到slave信息后,哨兵也会与slave建立俩条连接执行监控。通过INFO命令,哨兵可以获取主从数据库的最新信息,并进行相应的操作,比如角色变更等。

接下来哨兵向主从数据库的sentinel:hello频道发送信息与同样监控这些数据库的哨兵共享自己的信息,发送内容为哨兵的ip端口、运行id、配置版本、master名字、master的ip端口还有master的配置版本。这些信息有以下用处:

  • 其他哨兵可以通过该信息判断发送者是否是新发现的哨兵,如果是的话会创建一个到该哨兵的连接用于发送PING命令。
  • 其他哨兵通过该信息可以判断master的版本,如果该版本高于直接记录的版本,将会更新。

当实现了自动发现slave和其他哨兵节点后,哨兵就可以通过定期发送PING命令定时监控这些数据库和节点有没有停止服务。发送频率可以配置,但是最长间隔时间为1s,可以通过sentinel down-after-milliseconds mymaster 600设置。

如果被ping的数据库或者节点超时未回复,哨兵认为其主观下线。如果下线的是master,哨兵会向其他哨兵点发送命令询问他们是否也认为该master主观下线,如果达到一定数目(即配置文件中的quorum)投票,哨兵会认为该master已经客观下线,并选举领头的哨兵节点对主从系统发起故障恢复。

如上文所说,哨兵认为master客观下线后,故障恢复的操作需要由选举的领头哨兵执行,选举采用Raft算法:

  • 发现master下线的哨兵节点(我们称他为A)向每个哨兵发送命令,要求对方选自己为领头哨兵
  • 如果目标哨兵节点没有选过其他人,则会同意选举A为领头哨兵
  • 如果有超过一半的哨兵同意选举A为领头,则A当选
  • 如果有多个哨兵节点同时参选领头,此时有可能存在一轮投票无竞选者胜出,此时每个参选的节点等待一个随机时间后再次发起参选请求,进行下一轮投票精选,直至选举出领头哨兵

选出领头哨兵后,领头者开始对进行故障恢复,从出现故障的master的从(slave)数据库中挑选一个来当选新的master,选择规则如下:

  • 所有在线的slave中选择优先级最高的,优先级可以通过slave-priority配置
  • 如果有多个最高优先级的slave,则选取复制偏移量最大(即复制越完整)的当选
  • 如果以上条件都一样,选取id最小的slave

挑选出需要继任的slave后,领头哨兵向该数据库发送命令使其升格为master,然后再向其他slave发送命令接受新的master,最后更新数据。将已经停止的旧的master更新为新的master的从(slave)数据库,使其恢复服务后以slave的身份继续运行。

十一、集群模式(高可用)

3主6从,此处以3主3从为例

创建集群的过程

创建redis目录和配置文件

由于这里需要配置6个redis实例的配置文件,所以在这里,可以先创建一个模板配置文件,之后使用代码批量替换的方式来创建每个redis的配置文件。

创建模板文件

创建目录

mkdir -p /data/docker_redis/
​
编写redis_cluster.conf.template文件
​
vi redis_cluster.conf.template
port ${PORT}
requirepass 1234
masterauth 1234
protected-mode no
daemonize no
appendonly yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
cluster-announce-ip 192.144.150.164
cluster-announce-port ${PORT}
cluster-announce-bus-port 1${PORT}

在这里需要讲解2个参数

cluster-announce-port:此端口为redis提供服务端口,用于应用客户端连接 cluster-announce-bus-port:此端口用于redis集群进行故障检测、配置更新、故障转移授权和内部通讯使用,不用于应用客户端连接使用。

创建6个redis实例的数据目录,配置文件目录和配置文件

for port in `seq 8001 8006`; do \mkdir -p /data/redis_data/${port}/conf \&& PORT=${port} envsubst < /data/docker_redis/redis_cluster.conf.template > /data/redis_data/${port}/conf/redis.conf \&& mkdir -p /data/redis_data/${port}/data;\
done

使用tree命令检查创建的目录和文件

[root@mysql data]$ tree redis_data/
redis_data/
|-- 8001
|   |-- conf
|   |   `-- redis.conf
|   `-- data
|-- 8002
|   |-- conf
|   |   `-- redis.conf
|   `-- data
|-- 8003
|   |-- conf
|   |   `-- redis.conf
|   `-- data
|-- 8004
|   |-- conf
|   |   `-- redis.conf
|   `-- data
|-- 8005
|   |-- conf
|   |   `-- redis.conf
|   `-- data
`-- 8006|-- conf|   `-- redis.conf`-- data
​
18 directories, 6 files

批量创建容器 在这里使用for循环批量创建redis容器,代码如下所示

for port in $(seq 8001 8006); do \docker run -id -p ${port}:${port} -p 1${port}:1${port} --restart always --name redis-${port} \-v /data/redis_data/${port}/conf/redis.conf:/usr/local/etc/redis/redis.conf \-v /data/redis_data/${port}/data:/data \redis:7.0.2 redis-server /usr/local/etc/redis/redis.conf; \
done
​

在这里使用-v参数,让容器的redis配置参数和数据全部使用宿主机的文件目录。这样做的好处是,保证redis的数据不丢失。
开放防火墙端口
1)查看防火墙状态

systemctl start firewalled

2)启动端口8001-8006

sudo firewall-cmd --permanent --add-port=8001-8006/tcp

3)启动端口18001-18006

sudo firewall-cmd --permanent --add-port=18001-18006/tcp

4)开放云服务器的端口8001-8006、18001-18006


for port in $(seq 8001 8006); do \docker start redis-${port} ;\
done

查看刚刚创建的redis容器

[root@mysql data]# docker ps
CONTAINER ID        IMAGE                COMMAND                  CREATED             STATUS              PORTS                                                        NAMES
f4c971ce2d84        redis:7.0.2-buster   "docker-entrypoint.s鈥 6 seconds ago       Up 5 seconds        0.0.0.0:8006->8006/tcp, 6379/tcp, 0.0.0.0:18006->18006/tcp   redis-8006
1b5a8b0a1c93        redis:7.0.2-buster   "docker-entrypoint.s鈥 7 seconds ago       Up 6 seconds        0.0.0.0:8005->8005/tcp, 6379/tcp, 0.0.0.0:18005->18005/tcp   redis-8005
35d8fe01fc71        redis:7.0.2-buster   "docker-entrypoint.s鈥 7 seconds ago       Up 6 seconds        0.0.0.0:8004->8004/tcp, 6379/tcp, 0.0.0.0:18004->18004/tcp   redis-8004
408e5302378a        redis:7.0.2-buster   "docker-entrypoint.s鈥 8 seconds ago       Up 7 seconds        0.0.0.0:8003->8003/tcp, 6379/tcp, 0.0.0.0:18003->18003/tcp   redis-8003
c1c23c543233        redis:7.0.2-buster   "docker-entrypoint.s鈥 8 seconds ago       Up 7 seconds        0.0.0.0:8002->8002/tcp, 6379/tcp, 0.0.0.0:18002->18002/tcp   redis-8002
c752fab6c6b8        redis:7.0.2-buster   "docker-entrypoint.s鈥 9 seconds ago       Up 8 seconds        0.0.0.0:8001->8001/tcp, 6379/tcp, 0.0.0.0:18001->18001/tcp   redis-8001

创建redis-cluster集群

6个redis容器创建好之后,选择其中的一个容器进入,进行redis-cluster集群创建

进入容器内部

docker exec -it redis-8001 /bin/bash

-a 1234:使用密码"1234"进行认证

--cluster create:创建Redis集群模式

指定了6个节点IP和端口(同一服务器192.144.150.164上的8001-8006端口)

--cluster-replicas 1:配置每个主节点有1个从节点(副本)

 redis-cli -a 1234 --cluster create 192.144.150.164:8001 192.144.150.164:8002 192.144.150.164:8003 192.144.150.164:8004 192.144.150.164:8005 192.144.150.164:8006 --cluster-replicas 1

 执行后显示如下结果,显示自动分配的主从关系,写yes即可创建集群

[root@mysql bin]# docker exec -it redis-8001 /bin/bash
root@f4c971ce2d84:~# redis-cli -a 1234 --cluster create 192.144.150.164:8001 192.144.150.164:8002 192.144.150.164:8003 192.144.150.164:8004 192.144.150.164:8005 192.144.150.164:8006 --cluster-replicas 1
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 5460
Master[1] -> Slots 5461 - 10922
Master[2] -> Slots 10923 - 16383
Adding replica 1.94.230.82:8005 to 1.94.230.82:8001
Adding replica 1.94.230.82:8006 to 1.94.230.82:8002
Adding replica 1.94.230.82:8004 to 1.94.230.82:8003
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: c9e549f4d04d4466d2550d1e027412304099b1f2 1.94.230.82:8001slots:[0-5460] (5461 slots) master
M: 0956927ee74737d5ff91a1885e77f94d531dab76 1.94.230.82:8002slots:[5461-10922] (5462 slots) master
M: d6321788b2717b4142390c158ba70ca758f70964 1.94.230.82:8003slots:[10923-16383] (5461 slots) master
S: 96d2cb55f163ecc13a714ba01d90348c1c3ad02f 1.94.230.82:8004replicates c9e549f4d04d4466d2550d1e027412304099b1f2
S: 8a771c26a95e82d9a6818e372d7c0226937670ac 1.94.230.82:8005replicates 0956927ee74737d5ff91a1885e77f94d531dab76
S: aa7c2f6173904973f041b35efc5200359188eb0f 1.94.230.82:8006replicates d6321788b2717b4142390c158ba70ca758f70964
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join
.
>>> Performing Cluster Check (using node 1.94.230.82:8001)
M: c9e549f4d04d4466d2550d1e027412304099b1f2 1.94.230.82:8001slots:[0-5460] (5461 slots) master1 additional replica(s)
M: 0956927ee74737d5ff91a1885e77f94d531dab76 1.94.230.82:8002slots:[5461-10922] (5462 slots) master1 additional replica(s)
S: 96d2cb55f163ecc13a714ba01d90348c1c3ad02f 1.94.230.82:8004slots: (0 slots) slavereplicates c9e549f4d04d4466d2550d1e027412304099b1f2
S: aa7c2f6173904973f041b35efc5200359188eb0f 1.94.230.82:8006slots: (0 slots) slavereplicates d6321788b2717b4142390c158ba70ca758f70964
S: 8a771c26a95e82d9a6818e372d7c0226937670ac 1.94.230.82:8005slots: (0 slots) slavereplicates 0956927ee74737d5ff91a1885e77f94d531dab76
M: d6321788b2717b4142390c158ba70ca758f70964 1.94.230.82:8003slots:[10923-16383] (5461 slots) master1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
​

上述命令执行之后,redis-cluster集群就搭建好了,下面是整个redis-cluster集群的架构图

redis-cluster集群状态检查

检查redis-cluster集群状态

root@f4c971ce2d84:~# redis-cli -a 1234 --cluster check 1.94.230.82:8001
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1.94.230.82:8001 (c9e549f4...) -> 0 keys | 5461 slots | 1 slaves.
1.94.230.82:8002 (0956927e...) -> 0 keys | 5462 slots | 1 slaves.
1.94.230.82:8003 (d6321788...) -> 0 keys | 5461 slots | 1 slaves.
[OK] 0 keys in 3 masters.
0.00 keys per slot on average.
>>> Performing Cluster Check (using node 1.94.230.82:8001)
M: c9e549f4d04d4466d2550d1e027412304099b1f2 1.94.230.82:8001slots:[0-5460] (5461 slots) master1 additional replica(s)
M: 0956927ee74737d5ff91a1885e77f94d531dab76 1.94.230.82:8002slots:[5461-10922] (5462 slots) master1 additional replica(s)
S: 96d2cb55f163ecc13a714ba01d90348c1c3ad02f 1.94.230.82:8004slots: (0 slots) slavereplicates c9e549f4d04d4466d2550d1e027412304099b1f2
S: aa7c2f6173904973f041b35efc5200359188eb0f 1.94.230.82:8006slots: (0 slots) slavereplicates d6321788b2717b4142390c158ba70ca758f70964
S: 8a771c26a95e82d9a6818e372d7c0226937670ac 1.94.230.82:8005slots: (0 slots) slavereplicates 0956927ee74737d5ff91a1885e77f94d531dab76
M: d6321788b2717b4142390c158ba70ca758f70964 1.94.230.82:8003slots:[10923-16383] (5461 slots) master1 additional replica(s)
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

检查redis集群节点信息

root@f4c971ce2d84:~# redis-cli -c -a 1234 -h 1.94.230.82 -p 8001
1.94.230.82:8001> cluster nodes
0956927ee74737d5ff91a1885e77f94d531dab76 1.94.230.82:8002@18002 master - 0 1603265855374 2 connected 5461-10922
96d2cb55f163ecc13a714ba01d90348c1c3ad02f 1.94.230.82:8004@18004 slave c9e549f4d04d4466d2550d1e027412304099b1f2 0 1603265856080 4 connected
aa7c2f6173904973f041b35efc5200359188eb0f 1.94.230.82:8006@18006 slave d6321788b2717b4142390c158ba70ca758f70964 0 1603265855575 6 connected
8a771c26a95e82d9a6818e372d7c0226937670ac 1.94.230.82:8005@18005 slave 0956927ee74737d5ff91a1885e77f94d531dab76 0 1603265855575 5 connected
d6321788b2717b4142390c158ba70ca758f70964 1.94.230.82:8003@18003 master - 0 1603265856382 3 connected 10923-16383
c9e549f4d04d4466d2550d1e027412304099b1f2 1.94.230.82:8001@18001 myself,master - 0 1603265855000 1 connected 0-5460
​

在这里可以很清晰明了的看到有3个master节点和3个slave节点的IP地址和端口信息。

redis-cluster连接测试

redis-cluster搭建好之后,随意连接一个redis节点,无论是主节点还是从节点都可以,在这里选择连接一个从节点。

1.94.230.82:8001> cluster nodes
0956927ee74737d5ff91a1885e77f94d531dab76 1.94.230.82:8002@18002 master - 0 1603265855374 2 connected 5461-10922
96d2cb55f163ecc13a714ba01d90348c1c3ad02f 1.94.230.82:8004@18004 slave c9e549f4d04d4466d2550d1e027412304099b1f2 0 1603265856080 4 connected
aa7c2f6173904973f041b35efc5200359188eb0f 1.94.230.82:8006@18006 slave d6321788b2717b4142390c158ba70ca758f70964 0 1603265855575 6 connected
8a771c26a95e82d9a6818e372d7c0226937670ac 1.94.230.82:8005@18005 slave 0956927ee74737d5ff91a1885e77f94d531dab76 0 1603265855575 5 connected
d6321788b2717b4142390c158ba70ca758f70964 1.94.230.82:8003@18003 master - 0 1603265856382 3 connected 10923-16383
c9e549f4d04d4466d2550d1e027412304099b1f2 1.94.230.82:8001@18001 myself,master - 0 1603265855000 1 connected 0-5460

通过redis命令行测试 

root@f4c971ce2d84:~# redis-cli -c -a 1234 -h 1.94.230.82 -p 8004
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1.94.230.82:8004> 
1.94.230.82:8004> set 5 test5
-> Redirected to slot [9974] located at 1.94.230.82:8002
1.94.230.82:8002> 
1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16.

当在slave节点写入数据时,redis-cluster将你的写请求重定向到另一个master节点了.

root@f4c971ce2d84:~# redis-cli -c -a 1234 -h 1.94.230.82 -p 8006
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
1.94.230.82:8006> 
1.94.230.82:8006> get 5
-> Redirected to slot [9974] located at 1.94.230.82:8002
"test5"
1.94.230.82:8002>

十二、面试题(背会)

redis和java结合

redis雪崩、穿透、击穿

1. redis缓存使用流程

使用Redis缓存数据的流程是:

  1. 数据查询首先进行缓存查询。

  2. 如果数据存在则直接返回缓存数据。

  3. 如果数据不存在,就对数据库进行查询,并把查询到的数据放进缓存。

  4. 如果数据库查询数据为空,则不放进缓存。

2. 缓存穿透

2.1. 概念

缓存穿透是指查询缓存和数据库中都不存在的数据。比如id为-1的数据。

2.2. 解决方案
  • 缓存空值:当第一次请求时,数据不存在 Redis 也不存在数据库的时候,设置一个缺省值(比如:None)。当后续再次进行查询则直接返回空值或者缺省值。

    //伪代码
    public object GetProductListNew(String key) {//首先查询redis数据String value = redis.get(key);//如果redis中没有数据if(value == null){//查询数据库中的数据String dbValue = db.get();//如果数据库中的数据为null,则设置默认值if (dbValue == null) {dbValue = "none";}//将数据存储到redisredis.set(key,dbValue,50000);//返回return dbvalue;}}else{//第二次查询数据时,redis有数据,就直接返回return value;}
    }

  • 布隆过滤器:在数据写入数据库的同时将这个 ID 同步到到布隆过滤器中,当请求的 id 不存在布隆过滤器中则说明该请求查询的数据一定没有在数据库中保存,就不要去数据库查询了。

    <dependencies>  <dependency>  <groupId>com.google.guava</groupId>  <artifactId>guava</artifactId>  <version>23.0</version>  </dependency>  
    </dependencies> 
    //伪代码
    public class BloomFilterTest {private static final int capacity = 1000000;private static final int key = 999998;private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), capacity);static {for (int i = 0; i < capacity; i++) {bloomFilter.put(i);}}public static void main(String[] args) {/*返回计算机最精确的时间,单位微妙*/long start = System.nanoTime();if (bloomFilter.mightContain(key)) {System.out.println("成功过滤到" + key);}long end = System.nanoTime();System.out.println("布隆过滤器消耗时间:" + (end - start));int sum = 0;for (int i = capacity + 20000; i < capacity + 30000; i++) {if (bloomFilter.mightContain(i)) {sum = sum + 1;}}System.out.println("错判率为:" + sum);}
    }

3. 缓存雪崩

3.1. 概念

是指在某一个时间段,redis服务器故障或者redis缓存的数据集中全部过期失效或者大量key过期失效,在缓存集中失效的这个时间段对数据的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力。

3.2. 解决方案

事前:

redis服务器设置高可用(一主二从或者集群3主3从)

  • 随机设置key失效时间,避免大量key集体失效。

  • 不设置过期时间(不推荐)。

  • 用加锁或者队列的方式保证来保证不会有大量的线程对数据库一次性进行读写。

  • 跑定时任务,在缓存失效前刷进新的缓存。

事中:

    可以考略多种缓存机制,比如redis缓存+其他缓存机制 spring cache +mysql

事后:

     redis崩溃、mysql崩溃,系统崩溃

     解决方案:快速恢复系统(重启mysql、重启redis服务 快速恢复数据到内存中 rdb aof机制 、重启java服务)

4. 缓存击穿

4.1. 概念

指一个Key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个Key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个完好无损的桶上凿开了一个洞。

4.2. 解决方案
  • 预先把热门数据提前存入 Redis 中,并设热门数据的过期时间超大值。

  • 使用分布式锁,当发现缓存失效的时候,不是立即从数据库加载数据。而是先获取分布式锁,获取锁成功才执行数据库查询和写数据到缓存的操作,获取锁失败,则说明有线程在执行数据库查询操作,让当前线程睡眠一段时间在重试。这样只让一个请求去数据库读取数据。

    //伪代码
    public String get(key) {String value = redis.get(key);if (value == null) { //代表缓存值过期//设置3min的超时,防止del操作失败的时候,下次缓存过期一直不能load dbif (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表设置成功value = db.get(key);redis.set(key, value, expire_secs);redis.del(key_mutex);} else {  //这个时候代表同时候的其他线程已经load db并回设到缓存了,这时候重试获取缓存值即可sleep(50);get(key);  //重试}} else {return value;      }}

十三、springboot项目和redis的整合

1、spring-boot-starter-data-redis

2、配置redis的连接信息(host、port、password、database

3、使用redisTemplate模版工具类

4、常见方法

redisTemplate.opsForValue.set(key,value);

redisTemplate.opsForValue.get(key)

http://www.lryc.cn/news/574418.html

相关文章:

  • NFS服务配置超详细版
  • 第一节 布局与盒模型-Flex与Grid布局对比
  • 考研408《计算机组成原理》复习笔记,第三章(2)——存储器的ROM、RAM(DRAM和SRAM)、磁盘硬盘
  • 鸿蒙容器组件 Row 全解析:水平布局技术与多端适配指南
  • 实现 “WebView2 获取word选中内容
  • Python-1-环境
  • SQLite3 在嵌入式系统中的应用指南
  • 华为云 Flexus+DeepSeek 征文|CCE 集群部署 Dify 平台:【工作流协同高质量知识库】搭建企业级教培行业 Agent 顾问
  • C3新增特性
  • springcloud/springmvc协调作用传递验证信息
  • 如何实现财务自由
  • qt常用控件--02
  • AI-Sphere-Butler之如何将豆包桌面版对接到AI全能管家~新玩法(一)
  • 功率器件的基本公式概念
  • React Native【实用教程】(含图标方案,常用第三库,动画,内置组件,内置Hooks,内置API,自定义组件,创建项目等)
  • 【机器学习1】线性回归与逻辑回归
  • iperf3使用方法
  • 实验九:RIPv2协议配置与分析
  • 【C语言】解决VScode中文乱码问题
  • 目标检测之YOLOv5到YOLOv11——从架构设计和损失函数的变化分析
  • Windows电脑数据恢复终极指南:从原理到实战
  • 【AI论文】扩展大型语言模型(LLM)智能体在测试时的计算量
  • K8S下http请求在ingress和nginx间无限循环的问题
  • 【第二章:机器学习与神经网络概述】03.类算法理论与实践-(1)逻辑回归(Logistic Regression)
  • Threejs实现 3D 看房效果
  • 基于java SSM的房屋租赁系统设计和实现
  • 操作系统 第九章 部分
  • 线程池 JMM 内存模型
  • MySQL 8.x配置MGR高可用+ProxySQL读写分离(二):ProxySQL配置MySQL代理及读写分离
  • Web中的会话控制