redis学习路线

redis基础

redis 默认有16个数据库,默认使用第0个,可以切换数据库

select 3 //切换第四个数据库

查看当前数据库的大小

dbsize

查看所有的key

keys *

设置键值对

set key value

移动key到1库

move key 1    

判断某个key是否存在(返回1表示存在,返回0表示不存在)

exists key

为key设置过期时间

expire key 10  //10秒后过期

查看key剩余多长时间过期

ttl key

获取值

get key

查看key所存储value的类型

type key

清空当前库

flushdb

清空所有库

flushall

redis的默认端口号是6379(女明星名字的缩写)

redis是单线程的,因为redis是基于内存操作的,所以CPU不是redis性能瓶颈,Redis的性能瓶颈根据机器的内存和网络带宽有关,既然可以用单线程的化那么就用单线程了。

redis五大数据类型

String(字符串)

应用场景:value处了是string还可以是数字

​ 1、计数器(incr/decr)

​ 2、统计多单位数量(mset/mget+incr/decr)

​ 3、粉丝数,关注数(incr/decr)

​ 4、对象缓存存储(expire/setex)

set key1 v1
get key1
exists key1
keys *
append key1 "hello"  //如果key1不存在则创建一个key-value,如果存在,将value的值和hello拼接  返回 v1hello

strlen key1 //获取key1对应value的值的长度 返回7(v1hello)

自动加减一(一般用于浏览量的计算)

set views 0
incr views
get views //1 
decr views 
decr views
get views //-1

自动加减n(步长)

incrby views 10
get views //-1+10=9
decrby views 5
get views //9-5=4

获取value的一部分值

set key1 "hello,world"
getrange key1 0 3 //获取0-3[闭区间]的字符 hell
getrange key1 0 -1 //获取所有的字符 hello,world

替换value的一部分

set key1 "hello,world"
setrange key1 1 xx //将hello,world从第一个下标位置开始替换为xx
get key1 //返回 hxxlo,world

高级

setex (set with expire) #设置key-value的同时设置过期时间
setex key1 30 "hello"
setnx (set if not exits) #不存在时设置(分布式锁时常用)
setnx key2 "redis" //返回1成功
setnx key2 "mongo" //返回0失败

批量操作

mset k1 v1 k2 v2 k3 v3   //返回ok 同时设置多个值
keys *
	"k1"
	"k2"
	"k3"
mget k1 k2 k3	//同时获取多个值
	"v1"
	"v2"
	"v3"
msetnx k1 v1 k4 v4 //返回0,创建失败,虽然k4不存在但是k1已经存在,现在创建失败证明了msetnx是原子性操作

巧妙实战

set user:1 {name:"zhangsan",age:12}  //设置一个user:1对象的值为json字符串对象

//可以改成下面这种 user:{id}:{field}
mset user:1:username "zhangsan" user:1:age 12

先get后set

//getset key value   如果不存在key,则返回nil并将key对应的值改成value供下回返回;如果存在key,则返回当先key对应的值,将key-value保存供下次返回
getset db redis //(nil)
get db //"redis"
getset db "mongo" //"redis"
gitset db "kafka" //"mongo"
List

在redis里面,我们可以把list玩成栈、队列、阻塞队列。

所有list命令都是以l开头的

它实际上是一个链表 left和right都可以插入和删除值

如果key不存在,创建新的链表

如果key存在,新增内容

如果移除链表中所有的value,这时候就变成了空链表,也代表不存在

两边插入或者改动值时,效率最高,中间元素相对来说效率较低

用途:

​ 消息队列

​ 队列(两边操作相反)

​ 栈 (两边操作一致)

存取

//插入 每次都会插入头部
lpush list one //返回1 表示list集合的大小
lpush list two //2
lpush list three //3

//取 后进去的先出来(类似栈)
lrange list 0 -1 
	"three"
	"two"
	"one"
lrange list 0 1
	"three"
	"two"
	
rpush list four //插入尾部
lrange list 0 -1
	"three"
	"two"
	"one"
	"four"

移除

lpop和rpop
lrange list 0 -1
	"three"
	"two"
	"one"
	"four"
lpop list //"three" 返回移除的元素
rpop list //"four" 
lrange list 0 -1
	"two"
	"one"

规律:lpush和lpop或者 rpush和rpop相同方向的操作类似栈

​ lpush和rpop或者 rpush和lpop相反方向类似队列

获取指定下标的值(redis中list的下标从0开始)

lindex list 1 
	"one"
lindex list 0
	"two"

返回列表的长度

Llen list //2  里面就俩数据 "two" "one" 

移除列表中指定的值

flushdb
lpush list "one"
lpush list "two"
lpush list "three"
lpush list "three"
lrange list 0 -1 //
	"three"
	"three"
	"two"
	"one"
lrem list 1 one //移除list列表中从左面第一个one的值
lrem list 2 three //移除list列表中从左面两个three的值

截取list一部分(list被改变了,只剩下截取的部分)

ltrim list 0 2 //从左面截取list中0-2下标value
	"three"
	"three"
	"two"

移除列表最后一个元素并移动到新的列表中

flushdb
rpush mylist "hello"
rpush mylist "hello1"
rpush mylist "hello2"
rpoplpush mylist newlist
lrange mylist 0 -1
	"hello"
	"hello1"
lrange newlist 0 -1
	"hello2"

lset 将列表中指定下标的值替换另一个值(相当于更新操作)前提:列表和下标都存在

flushdb
exists list //返回0 表示不存在list
lset list 0 item //将list集合中0号下标存item,很显然会报错,因为list不存在,更别说下标的事了
lpush list values 将values存储到list集合中的0号下标
lrange list 0  0 //显示0号位置的值
lset list 0 item //将list集合中0号下标存item 返回ok
lset list 1 other //报错,因为1号下标没有创建

将某一个具体的value插入列表中某个元素的前面或者后面

flushdb
rpush list "hello"
rpush list "world"
linsert list before world hi //从左面在world之前插入一个hi 返回3代表插入后list的长度
lrange list 0 -1
	"hello"
	"hi"
	"world"
linsert list after world new
lrange list 0 -1
	"hello"
	"hi"
	"world"
	"new"
Set(集合)无序

set中的值是不能重复的

set命令都是以s开头的

添加和查询

sadd myset "hello"  //返回1表示插入成功,0表示插入失败(因为重复的值是不能插入的,可能会返回0)
sadd myset "world"
sadd myset "helloworld"
//查看
smembers myset
	"hello"
	"helloworld"
	"world"

判断某个值是否在set集合中

sismember myset hello //返回1表示存在,0表示不存在

判断set集合的长度

scard myset //返回3

移除set集合中某个元素的值

srem myset "hello" //返回1表示移除成功,0表示移除失败
scard myset //2  返回set集合的长度
smembers myset 
	"helloworld"
	"world"

随机从set中抽选出一个值

sadd myset "hello"
sadd myset "liu"
sadd myset "long"
smembers myset 
	"liu"
	"long"
	"hello"
	"helloworld"
	"world"
srandmember myset   //随机返回一个值
srandmember myset 2 //随机返回set集合中的两个值

随机删除一个set中的值

spop myset //返回移除的值

随机将set1中的值移动到set2中

sadd set1 "hello"
sadd set1 "world"
sadd set2 "xixi"
sadd set2 "hehe"
smove set1 set2 "hello"
smembers set1
	"world"
smembers set2
	"hello"
	"xixi"
	"hehe"

微博、B站中的共同关注(交集)

数字集合类

​ 差集

smembers myset
	"liu"
	"long"
	"hello"
	"helloworld"
	"world"
smembers set1
	"world"
sdiff myset set1 //以前面为基础减去公共的部分就是差集
	"liu"
	"long"
	"hello"
	"helloworld"

​ 交集

sinter myset set1
	"world"

​ 并集

sunion key1 key2
	"hello"
	"world"
    "xixi"
	"hehe"
Hash(哈希)

key-Map(集合)

hash操作都是以h开头的

存值和取值

hset myhash field1 "hello" //返回1表示成功 
hget myhash field1  //"hello" 返回查询的结果
//连续设置多个值
hmset myhash field1 "xixi" field2 "hehe"  //返回ok表示设置成功
//一次性获取所有的value
hmget myhash field1 field2
	"xixi"
	"hehe"
//一次性返回所有的field和value
hgetall myhash
	"field1"
	"xixi"
	"field2"
	"hehe"

删除hash中的一个key-value

hdel myhash field1  //ok表示删除成功
hgetall myhash
	"field2"
	"world"

查看hash中的键值对个数

hlen myhash  //1  返回的是key-value的个数

判断hash中是否有某个key

hexist myhash field2 //1表示有
hexist myhash field3 //0表示没有

查看当前所有的key

hkeys myhash
	"fiekd2"

查看当前所有的value

hvals myhash
	"world"

hash中某个字段加上/减去某个值

hset myhash field3 5 //1 表示插入成功
hincrby myhash field3 1 //6 返回插入后的结果值
hincrby myhash field3 -1 //5 ==》hdecrby myhash field3 1

hsetnx(如果不存在才可以创建)

hsetnx myhash field4 "hello" //1
hsetnx myhash field4 "world"  //0 不存在key时才添加key-value

hash变更的书库 user :1 (name,age)

一般用于用户信息之类的、经常变更的信息

hash更适合对象的存储,string更适合字符串的存储

Zset(有序集合)

在set的基础上增加了一个值,zset k1 score v1,score越小优先级越高

zset命令都是以z开头的

添加和查看

zadd myset 1 one //1 1表示添加一个值
zadd myset 2 two 3 three //2 添加多个值
zrange myset 0 -1
	"one"
	"two"
	"three"

用score排序

// 添加三个用户
zadd salary 2500 xiaohong
zadd salary 5000 zhangsan
zadd salary 500 kuangshen
// 按照薪水排序 zrangebyscore key min max
zrangebyscore salary -inf +inf // -∞到+∞里的所有值从小到大排序
	"kuangshen"
	"xiaohong"
	"zhangsan"
zrangebyscore salary -inf 2500 // -∞到2500里进行排序
	"kuangshen"
	"xiaohong"
zrangebyscore salary -inf +inf withscore // -∞到+∞里的所有值从小到大排序,并且附带成绩
	"kuangshen"
	"500"
	"xiaohong"
	"2500"
	"shangsan"
	"5000"
zrevrange salary 0 -1 //倒排,从大到小排序
	"shangsan"
	"xiaohong"
	"kuangshen"

移除元素

zrange salary 0 -1
	"kuangshen"
	"xiaohong"
	"zhangsan"
zrem salary "xiaohong" //1表示移除成功
zrange salary 0 -1
	"kuangshen"
	"zhangsan"

查看有序集合中的个数

zcard salary  //"kuangshen" "zhangsan"
	2

计算score范围内的有多少个元素

//zcount key min max  获取指定区间的成员数量
flush db
zadd myset 1 hello 2 world 3 kuangshen
srange myset 0 -1
	"hello"
	"world"
	"kaungshen"
zcount myset 1 2 //2 2表示符合区间的有两个元素
zcount myset 1 3 //3

用途:

​ 存储成绩表,工资表排序

​ 普通消息1表示,重要消息2表示 ,带权重判断

​ 排行耪排名应用实现 topN实现

三种特殊数据类型

geospatial(地理位置)

用途:朋友的定位,附近的人,打车距离计算

redis的geo在redis3.2版本就推出了,这个功能可以计算地理位置的信息,两地之间的距离,方圆几里的人

只有6个命令

geoadd
geodist
geohash
geopos
georadius
georadiusbymember

添加

//geoadd key 经度 纬度 名称   两级(南极、北极)无法添加  下面这么多数据一般都是用程序添加,而不是手动添加
geoadd china:city 116.40 39.90 beijing
geoadd china:city 121.47 31.23 shanghai
geoadd chine:city 106.50 29.53 chongqing 114.05 22.54 shenzhen   120.16 30.24 hangzhou 108.96 34.26 xian

从key里获取给定位置的经度和纬度

单位:

  • m 表示单位为米
  • km 表示单位为km
  • mi 表示单位为英里
  • ft 表示单位为英尺
geopos china:city beijing
	"116.399999896"
	"39.900000"
geopos china:city beijing chongqing

两人之间的距离

geodist china:city beijing shanghai km //(默认是米) 北京到上海的直线距离
	"1067.3788"

找附近的人

georadius key 经度 纬度 半径//以给定的经度纬度为中心,通过半径查询
georadius china:city 110 30 1000 km
	"chongqing"
	"xian"
	"shenzhen"
	"hangzhou"
georadius china:city 110 30 500 km withdist  //另外显示出距离
	"chongqing"
		"341.9374"
	"xian"
		"483.8340"
georadius china:city 110 30 500 km withcoord //另外显示经纬度
	"chongqing"
		"106.96001"
		"29.5299995"
	"xian"
		"108.960001"
		"34.2599999"

//获得指定数量的人
georadius china:city 110 30 500 km withcoord  count 1//另外显示经纬度
	"chongqing"
		"106.96001"
		"29.5299995"

上面是以坐标形式查找附近的人的,下面可以以元素的名称来查找

georadiusbymember china:city beijing 1000 km // 找出距离北京1000km的城市
	"beijing"
	"xian"

geohash命令:返回一个或者多个位置元素的Geohash表示(了解即可)

//将经纬度(二维)转换为(一维)11位的字符串 
geohash china:city beijing chongqing  //如果两个字符串越像,那么距离越近
	"wx4fbxxfke0"
	"wm5xzrybty0"

geo的底层其实就是zset,所以查看和删除可以用zset命令

zrange china:city 0 -1
	"chongqing"
	"xian"
	"shenzhen"
	"hangzhou"
	"shanghai"
	"beijing"
zrem china:city beijing
zrange china:city 0 -1
	"chongqing"
	"xian"
	"shenzhen"
	"hangzhou"
	"shanghai"
hyperloglog

A(1,3,5,7,8,7) B(1,3,5,7,8)

基数就是集合中不重复元素的个数 ,所以A、B两个集合的基数都是5 可接受误差为1

hyperloglog 在redis2.8.9更新了这个数据结构

redis hyperloglog 基数统计的算法

优点:占用内存是固定的,2^64不同的元素,只占用12kb的内存

用途:网站访问的次数

传统的做法,set保存用户访问的id,然后计算set集合的长度,这个方式如果保存大量用户的id时会比较麻烦,会浪费大量的内存,我们最终的目的为了计数,而不是保存这些id,在允许出错的0.81%的前提下,我们可以用hyperloglog来做,如果不允许出错就只能用set。

pfadd mykey a b c d e f g h i j //创建第一组元素
pfcount mykey  //统计第一组元素数量
	10
pfadd mykey2 i j z x c v b n m
pfcount mykey2
	9
pfmerge mykey3 mykey mykey2 //合并两组集合(并集)
pfcount mykey3
	15
bitmap(位存储)

统计用户信息(活跃/不活跃、登录/未登录、打卡/未打卡),两个状态都可以使用bitmap

bitmap 位图,是一种数据结构,操作都是以二进制记录的,只有0和1两个状态

365天=365bit 1字节=8bit 一个用户一年打卡的记录只占用46个字节左右

使用bitmap来记录周一到周日的打卡

setbit sign 0 1 //1代表打卡  0代表没打卡 周一打卡
setbit sign 1 0 //周二未打卡
setbit sign 2 0 //周三未打卡
setbit sign 3 1
setbit sign 4 1
setbit sign 5 0
setbit sign 6 0

查看周四是否打卡

getbit sign 3 //1 表示周四打卡了

统计打卡的天数

bitcount sign //3 表示全部数据中只有三天打卡了

事务

事务的本质:一组命令的集合

mysql中redis的特点:原子性、一致性、隔离性、持久性

redis中事务的特点:一次性、顺序性、排他性,redis的事务没有原子性和隔离级别的概念

所有的命令在事务中,并没有直接被执行,只有发起执行命令时才会执行!Exec

redis单条命令保证原子性的,但是事务不保证原子性

  • 开启事务(multi)
  • 命令入队(…)
  • 执行事务(exec)
multi //ok  开启事务
set k1 v1   //queue  命令入队
set k2 v2
get v2
set k3 v3
exec       //执行事务
	"ok"
	"ok"
	"v2"
	"ok"

放弃事务

multi 
set k1 v1
set k2 v2
set k4 v4
//取消事务
discard
get k4
	(nil)

编译时异常(代码有问题,命令出错),事务中的所有命令都不会被执行

multi //开启事务
set k1 v1 //命令入队
set k2 v2
getset k2  //(错误的命令)
(error) ERR wrong number of arguments for "getset" command
set  k3 v3
exec //执行事务
(error)EXECABORT Transaction discarded because of previous errors
get k3  //所有的命令都不会执行
	(nil)

运行时异常(1/0)如果事务队列中存在语法错误,那么执行命令的时候,其它命令可以正常执行,错误的命令排除异常

set k1 "v1"
multi
incr k1 //字符串不能自增
set k2 v2
set k3 v3
get v3
exec
	(error) ERR value is not an integer or out of range
	OK
	OK
	"v3"

redis实现乐观锁(监控 Watch)

​ 悲观锁:很悲观,认为什么时候都会有问题,无论做什么都加锁

​ 乐观锁:很乐观,认为什么时候都不会有问题,所以不会加锁,更新数据的时候去判断一下再次期间是否有人修改过这个数据。

  • 获取version
  • 更新的时候比较version

正常执行成功

set money 100 //设置金钱100
set out 0  //设置开销0
watch money  //监视money
multi //事务正常结束,数据期间没有发生任何变动,这个时候正常执行成功
decrby money 20
incrby out 20
exec

测试多线程修改值,使用watch可以充当redis的乐观锁操作

watch money //第一个线程监控money
multi
decrby money 10 //第一个线程消费10
incrby out 10
//这个时候没有执行事务,第二个线程修改了money
incrby money 1000 //第二个线程直接给money增加1000
exec //第一个线程执行事务
	(nil) 修改失败

怎么解决

//1、先放弃监控(先解锁)
unwatch
//2、获取最新的money(再次获取最新锁)
watch money
//3、开启事务,进入队列,执行事务。。。

说明:SpringBoot2.x之后,原来使用jedis被替换成lettuce了

jedis:采用的直连,多个线程操作的话是不安全的,如果想要避免不安全,可以使用jedis pool,更像BIO模式。

lettuce:采用netty,实例可以在多个线程中共享,不存在线程不安全的情况,可以减少线程数据了,更像NIO模式。

redis持久化

默认是rdb(Redis DataBase)持久化的,aof(Append Only File)默认不开启

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

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

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

  • 优点

    1、适合大规模的数据恢复

    2、对数据的完整性要求不是很高

  • 缺点

    1、需要一定的时间间隔进程操作,如果redis意外宕机了,这个最后一次修改的数据就没有了

    2、fork子进程的时候会占用一定的内存空间

aof:将我们所有的操作命令都记录下来,恢复的时候就把记录的命令都在执行一遍。

以日志的形式记录每个写操作,将redis执行过的所有指令记录下来(读操作不记录),换言之,redis重启之后就会根据日志文件的内容将写指令从前到后在执行一次,以恢复原理的数据。

aof的策略

​ 1、appendfsync always //每次修改都会sync,消耗性能

​ 2、appendfsync everysec //每秒执行一次sync,可能会丢失1s的数据

​ 3、sppendfsync no //不执行sync,这个时候操作系统自己同步数据,速度最快

  • 优点

    1、每一次修改都会同步,文件完整性会更加好

    2、每秒同步一次,可能会丢失一秒以内的数据,但是性能相对来说比较好

    3、从不同步,性能最好

  • 缺点

    1、相对于数据文件来说,aof文件远远大于rdb,修复的速度也比rdb慢

    2、aof运行速率也比rdb慢,所以redis默认就是rdb持久化

redis的发布订阅

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

消息订阅模型一定要有的三个角色

1、消息发送者 2、频道 3、消息订阅者

在这里插入图片描述

订阅端

subscribe kuangshenshuo //订阅一个频道kuangshenshuo
Reading messages... (predd Ctrl-C to quit)
1)"subscribe"
2)"kuangshenshuo"
3)(integer) 1
//等待读取信息
1)"message" //消息
2)"kuangshenshuo" //消息来自哪个频道
3)"hello,kuangshen" //消息的内容
1)"message"
2)"kuangshenshuo"
3)"hello,redis"

发布端

publish kuangshenshuo "hello,kuangshenshuo" //发布消息"hello,kuangshenshuo"到频道kuangshenshuo
(integer) 1
publish kuangshenshuo "hello,redis"
(integer) 1

使用场景

​ 1、实时消息系统

​ 2、实时聊天(频道当作聊天室,将信息回显给所有人即可)

​ 3、订阅,关注系统

复杂的场景一般使用mq来做,毕竟redis主要做缓存的。

主从复制

查看当前的连接信息

info replication

主从复制一般至少需要三台服务器,我们以6379为主机,6380和6381为从机来测试

选取主节点只需要在从节点输入下面命令即可

slaveof 127.0.0.1(master的ip) 6379(master的port)

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

测试:主机断开连接,从机依旧连接主机的,但是没有写操作了,这个时候如果主机回来了,从机依旧可以直接获取主机写的信息

如果只用的是命令行来配置的主从,这个时候如从机重启了就会重新变为主机,只要变回从机,立马就会从主机中同步数据

复制原理

Slave启动成功后连接到master后会发送一个sync命令,master接收到命令后启动后台的存盘进程,同时收集所有接收到的用于修改数据集的命令,在后台进程执行完毕后,master将传送整个数据文件到slave,完成一次全量同步。

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

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

但是只要是重新连接master,一次完全同步(全同步)将自动执行,我们在主机中修改的数据在从机中一定可以看到。

如果主机断开了连接,我们可以使用slave no one 让自己变成主机。

哨兵模式

主从复制技术的方法是:当主服务器宕机后,需要手动把一台服务器切换为主服务器,这就需要人工的干预,费时费力,还会造成一段时间内的服务不可用,这不是一种推荐的方式,更多时候,我们会考虑哨兵模式,redis从2.8的时候正式提出了sentinel(哨兵)来解决上面的问题

哨兵模式能够自动的监控后台主机是否出故障,如果出故障了要根据投票数自动将从机切换为主机

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

在这里插入图片描述

哨兵的配置文件sentinel.conf

sentinel monitor myredis 127.0.0.1 6379   //sentinel monitor 被监控的名称(随便起) 主节点的ip 主节点的port num(多少个哨兵认为master挂了,master才算真的挂了)

启动哨兵

redis-sentinel ./sentinel.conf

哨兵模式:如果master挂了,这个时候就会自动从slave节点中选择一个当作master,以后当master在恢复的时候也只能当这个master的slave了

  • 优点

    1、哨兵集群,基于主从复制模式,所有的主从配置优点,它全有

    2、主从可以切换,故障可以转移,系统的可用性会更好

    3、哨兵模式就是主从模式的升级,手动到自动,更加健壮

  • 缺点

    1、redis不好实现在线扩容,集群容量一旦到达上限,在线扩容就会十分麻烦

缓存穿透和雪崩

缓存穿透:(查询一个不存在的数据)用户想要查询一个数据,发现redis中没有,也就是缓存没有命中,于是就去持久层数据库中查询,发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,而这些请求都打到持久层数据库就会给数据库造成很大的压力,这就叫作缓存穿透。

解决:布隆过滤器、缓存空对象

缓存击穿:(一个热点key过期)是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就会穿破缓存直接请求数据库。

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

解决:1、从缓存层面来看,没有设置过期时间的话就不会出现热点key过期的问题。

2、使用分布式锁,保证对于每个key同时只有一个线程去访问后端服务,其它线程没有获得分布式锁的权限,因此,只需要等待即可。

缓存雪崩:(大量热点key过期)是指在某一个时间段缓存集中失效或者redis宕机

解决:1、数据预热,把可能的数据先访问一遍,这样部分可能大量访问就会增加到缓存中,在即将发生的大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间尽可能均匀。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值