redis学习笔记

nosql概述

为什么要用nosql

用户的个人信息,社交网络,地理位置,用户生成的数据和用户操作日志已经成倍的增加。我们如果要对这些用户数据进行挖掘,那SQL数据库已经不适合这些应用了, NoSQL数据库的发展也却能很好的处理这些大的数据。

什么是nosql

NoSQL(NoSQL = Not Only SQL ),意即“不仅仅是SQL”,
泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在应付web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集和多重数据种类带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。

redis简介

redis是完全开源的、高性能的key-value数据库。

redis的特点
  1. redis支持数据持久化,将内存中的数据保存在硬盘中,重启后可以再次加载进行利用
  2. redis不仅仅支持简单的key-value类型数据,还支持list,set,zset,hash等数据结构的存储
  3. redis的核心模块是单线程的,基于内存操作,所以cpu不是它的瓶颈,它受到内存和网络带宽的影响

思考:既然redis是单线程,为什么速度还那么快?

  • redis是基于内存的,内存的读写速度非常快
  • 由于是单线程的,省去了上下文切换的时间
  • 使用多路复用技术,处理并发连接

redis安装

下载安装包redis-5.0.7.tar.gz

将安装包放到opt目录下

解压安装包
tar -zxvf redis-5.0.7.tar.gz
基本环境安装
[root@localhost redis-5.0.7]#yum insatll gcc-c++
[root@localhost redis-5.0.7]#make

在这里插入图片描述

[root@localhost redis-5.0.7]#make install

在这里插入图片描述

注:redis默认安装路径/usr/local/bin
在这里插入图片描述

拷贝配置文件

在usr/local/bin/目录下创建一个用来存放拷贝目录的文件

[root@localhost bin]# mkdir myconfig

进入/opt/redis-5.0.7redis.conf拷贝到usr/local/bin/myconfig以后就一直用redis.conf这个配置文件

[root@localhost redis-5.0.7]# cd /opt/redis-5.0.7
[root@localhost redis-5.0.7]# cp redis.conf /usr/local/bin/myconfig/
修改redis.conf配置文件

在这里插入图片描述

启动redis

在这里插入图片描述

使用客户端验证redis是否启动成功
[root@localhost bin]# ./redis-cli 

在这里插入图片描述

查看redis进程

在这里插入图片描述

关闭redis
127.0.0.1:6379> SHUTDOWN

在这里插入图片描述

redis基本知识和指令

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

#基本指令
select //切换数据库
DBSIZE //查看数据库的大小
keys * //查看所有的key
flushdb //清空当前数据库
FLUSHALL //清空所有数据库
EXISTS key //判断key是否存在
move key 1 //移除当前的key
EXPIRE 可以设置key的过期时间
ttl key 查看key的过期时间
type 查看key的数据类型

redis数据类型

String类型
#字符串指令
set key value //设置指令key的值
get key //获取指定可以的值
APPEND key “xxx" //在指定key后面追加xxx字符串
incr key //在指定的key加1
decr key //在指定的key减1
INCRBY key 10 //在指定的key加10
DECRBY key 10 //在指定的key减10
GETRANGE key 0 3 //截取字符串0为起始位置,若3的位置换位-1则是截取全部字符串
setex key 30 "hello" //设置key的值b并且30s后过期
getset key value //先get后set  如果可以不存在则返回nil 如果存在则返回原来的值,并设置新的值

list 类型
127.0.0.1:6379> lpush mylist one // 将一个值插入列表头部(双端队列)
(integer) 1
127.0.0.1:6379> lpush mylist two
(integer) 2
127.0.0.1:6379> lpush mylist three
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1 //获取mylist中所有的元素
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lpop mylist //从左端移除一个元素
"three"
127.0.0.1:6379> rpop mylist //从右端移除一个元素
"one"
127.0.0.1:6379> lindex mylist 0 根据mylist的下标获取指定元素
"two"
127.0.0.1:6379> llen mylist //返回mylist的长度
(integer) 1
127.0.0.1:6379> lset mylist1 0 hello //设置下mylist1中下标为0的值为hello 如果不存在,则报错
(error) ERR no such key
127.0.0.1:6379> lset mylist 0 hello
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
127.0.0.1:6379> linsert mylist before hello yinghuo  //在mylist集合的hello元素前面插入yinghuo元素
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "yinghuo"
2) "hello"
set类型
127.0.0.1:6379> sadd myset A //存放一个A元素
(integer) 1
127.0.0.1:6379> sadd myset B
(integer) 1
127.0.0.1:6379> sadd myset C
(integer) 1
127.0.0.1:6379> smembers myset //查看myset集合的所有元素
1) "C"
2) "B"
3) "A"
127.0.0.1:6379> scard myset //获取set集合元素的个数
(integer) 3
127.0.0.1:6379> srem myset B //移除set集合中指定元素
(integer) 1
127.0.0.1:6379> smembers myset 
1) "C"
2) "A"
127.0.0.1:6379> srandmember myset //随机获取set集合中的一个元素(抽奖)
"C"
127.0.0.1:6379> srandmember myset  
"C"
127.0.0.1:6379> srandmember myset
"A"
127.0.0.1:6379> spop myset // 随机删除set集合一个元素
"A"
127.0.0.1:6379> spop myset
"C"
127.0.0.1:6379> 

Hash类型(用于经常变动用户信息的存储)
127.0.0.1:6379> hset  myhash key1 value1 //放入一个key-value键值对
(integer) 1
127.0.0.1:6379> hmset myhash key2 value2 key3 value3 //放入多个key-value键值对
OK
127.0.0.1:6379> hgetall myhash //获得myhash集合所有的键值对
1) "key1"
2) "value1"
3) "key2"
4) "value2"
5) "key3"
6) "value3"
127.0.0.1:6379> hget myhash key2 // 获得myhash指定键的值
"value2"
127.0.0.1:6379> hexists myhash key3 //判断myhash中指定的字段是都存在
(integer) 1
127.0.0.1:6379> hexists myhash key4
(integer) 0
127.0.0.1:6379> hkeys myhash //获得myhash中所有的键
1) "key1"
2) "key2"
3) "key3"
127.0.0.1:6379> hvals myhash //获得myhash中所有的值
1) "value1"
2) "value2"
3) "value3"
127.0.0.1:6379> 

zset类型(有序集合)
127.0.0.1:6379> zadd salary 5000 zhangsan //设置键为salary 值为zhangsan 并且会按薪资升序排序
(integer) 1
127.0.0.1:6379> zadd salary 6000 lisi
(integer) 1
127.0.0.1:6379> zadd salary 4000 wangwu
(integer) 1
127.0.0.1:6379> zrange salary 0 -1 //查看salary所有的元素 默认按薪资升序
1) "wangwu"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> zrangebyscore salary -inf +inf  //查看salary所有的元素 默认按薪资升序
1) "wangwu"
2) "zhangsan"
3) "lisi"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores  //查看salary所有的元素并且显示薪资
1) "wangwu"
2) "4000"
3) "zhangsan"
4) "5000"
5) "lisi"
6) "6000"
127.0.0.1:6379> zrem salary wangwu //移除salary中指定的元素
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "zhangsan"
2) "lisi"
127.0.0.1:6379> zrevrange salary 0 -1 //查看salary中所有的元素,并按降序排序
1) "lisi"
2) "zhangsan"
127.0.0.1:6379> zcount salary 100 10000 //统计salary中薪资100~10000的个数
(integer) 2
127.0.0.1:6379> zcount salary 4500 5500
(integer) 1

zset应用 :班级成绩表,工资表,排行榜等

geospatial
127.0.0.1:6379> GEOADD china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> GEOADD china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> GEOADD china:city 114.05 22.52 shenzhen
(integer) 1
127.0.0.1:6379> geopos china:city beijing
1) 1) "116.39999896287918091"
   2) "39.90000009167092543"
127.0.0.1:6379> geodist china:city beijing shenzhen km
"1945.7881"
127.0.0.1:6379> georadius china:city 110 20 2000 km
1) "shenzhen"
2) "shanghai"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city  beijing 1500 km
1) "shanghai"
2) "beijing"
127.0.0.1:6379> geohash china:city beijing
1) "wx4fbxxfke0"
注:GEO底层原理是zset 可以使用zset命令操作GEO

Hyperloglog

思考:如何做到一个人访问一个网站多次,但还算一个人?
传统做法:使用set存储用户的id,统计set中元素的个数。但但用户量很多时我们需要保存很多的用户id,而我们的目只是为了统计个数

使用Hyperloglog的优点:占用内存固定,2^64的不同元素内容只需12kb的内存
缺点:在数据量比较大时会有0.81%的容错

测试:

127.0.0.1:6379> pfadd mykey a b c d e f g //在mykey集合里添加多个元素
(integer) 1
127.0.0.1:6379> pfcount mykey // 统计元素个数
(integer) 7
127.0.0.1:6379> pfadd mykey2 f g h i j k l m n //再mykey2里添加多个元素
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 9
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 //合并mykey和mykey2 => mykey3
OK
127.0.0.1:6379> pfcount mykey3
(integer) 14

Bitmap(使用二进制进行记录,只有0和1)

用途:统计用户信息,比如QQ上的登录和未登录,打卡和未打卡等等,一般只有两个状态的都可以使用bitmap来存储
在这里插入图片描述

redis事务

redis事务的本质: 一组命令的集合,一个事务中所有的命令都会被序列化,在执行过程中会按照顺序执行

  • redis单条命令是保证原子性的,但事务不保证原子性
  • redis没有隔离级别的概念
  • 所有命令在事务中并没有被直接执行,只有发起执行指令时才会被执行

redis事务操作命令:

  • 开启事务:multi
  • 命令队列(…)
  • 执行事务:exec
  • 放弃事务:discard

事务的异常:事务的异常分为编译型异常和运行时异常两类
编译时异常(代码问题,命令有错)
此时事务中的所有命令都不会被执行

127.0.0.1:6379> set key1 value1  
QUEUED
127.0.0.1:6379> set key2 value2
QUEUED
127.0.0.1:6379> getset key3  //此处命令错误,所有在执行exec后以上的两条命令都不会被执行
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> exec
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get key2
(nil)
127.0.0.1:6379> 

运行时异常
事务队列如果发生语法型错误,那么在编译时不会报错,在执行时报错的指令抛出异常,其他的指令可以继续成功执行

127.0.0.1:6379> set key1 value1
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> incr key1 //这里虽然命令没错,但语法错误,value1是无法加1的所以在执行时会报错
QUEUED
127.0.0.1:6379> set key2 value2 //但可以继续执行该条命令
QUEUED
127.0.0.1:6379> exec
1) (error) ERR value is not an integer or out of range
2) OK
127.0.0.1:6379> get key2
"value2"
127.0.0.1:6379> 

redis实现乐观锁

悲观锁

很悲观,什么时候都觉得会出问题,所以无论什么时候都加锁

乐观锁

很乐观,什么时候都觉得不会出问题,所以不会加锁,更新数据的时候去判断一下,在此期间是否有人修改过这个数据,如果修改过,则执行失败

测试:

127.0.0.1:6379> set money 1000
OK
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch money //监视money对象
OK
127.0.0.1:6379> multi  //开启事务
OK
127.0.0.1:6379> DECRBY money 100 //余额减100
QUEUED
127.0.0.1:6379> INCRBY out 100 //已经花出去的钱加100
QUEUED
127.0.0.1:6379> exec //判断money是否跟监视时的值一样(money有可能被多线程修改)
1) (integer) 900
2) (integer) 100
127.0.0.1:6379> 

如果在exec执行之前其他线程操作了money导致money与原来监视的值不一样就会执行失败

#这里再开一个客户端模仿多线程
27.0.0.1:6379> get money
"900"
127.0.0.1:6379> DECRBY money 100
(integer) 800
127.0.0.1:6379> 

127.0.0.1:6379> watch money
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> DECRBY money 200
QUEUED
127.0.0.1:6379> INCRBY OUT 200
QUEUED
127.0.0.1:6379> exec
(nil) //由于监视的money被其他线程修改了,所以会执行失败
127.0.0.1:6379> 

注:如果发现事务执行失败,先使用unwatch解锁

Jedis

jedis是redis官方推荐的java连接开发工具,是连接redis的中间件
测试:

导入相关依赖:

 <dependencies>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.2.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.58</version>
        </dependency>

    </dependencies>

编写测试类测试:

  public static void main(String[] args) {

        Jedis jedis = new Jedis("127.0.0.1", 6379); //连接数据库
        String ping = jedis.ping(); //测试连接是否成功
        System.out.println(ping);
    }

测试结果:
在这里插入图片描述
测试成功!

springboot集成redis

步骤:

  • 导入redis启动器
 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
 </dependency>
  • 在application.properties编写配置文件
spring.redis.host=127.0.0.1
spring.redis.port=6379
  • 编写测试类测试
  @Autowired
  private RedisTemplate redisTemplate;

 @Test
    void contextLoads() {

        redisTemplate.opsForValue().set("user","hello");

        System.out.println(redisTemplate.opsForValue().get("user"));
    }

运行结果:ok!
在这里插入图片描述

自定义RedisTemplate

由于默认的RedisTemplate默认使用的是jdk序列化,我们可以定义自己的RedisTemplate

@Configuration
public class RedisConfig {

  @Bean
  @SuppressWarnings("all")
  public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
      RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
      template.setConnectionFactory(factory);
      Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
      ObjectMapper om = new ObjectMapper();
      om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
      om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
      jackson2JsonRedisSerializer.setObjectMapper(om);
      StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();

      // key采用String的序列化方式
      template.setKeySerializer(stringRedisSerializer);
      // hash的key也采用String的序列化方式
      template.setHashKeySerializer(stringRedisSerializer);
      // value序列化方式采用jackson
      template.setValueSerializer(jackson2JsonRedisSerializer);
      // hash的value序列化方式采用jackson
      template.setHashValueSerializer(jackson2JsonRedisSerializer);
      template.afterPropertiesSet();

      return template;
  }


}

redis配置文件详解

  • 对单位大小写不敏感
    在这里插入图片描述

  • 包含(可以引入多个redis配置文件)
    在这里插入图片描述

  • 网络
    在这里插入图片描述

  • 通用
    在这里插入图片描述
    在这里插入图片描述

  • 快照

    数据的持久化,redis是内存数据库,如果没有持久化的话,断点后数据会丢失
    在这里插入图片描述

  • 主从复制(REPLICATION)

  • 安全(SECURITY)

    可以在这里设置redis密码,默认是没有密码
    在这里插入图片描述

#设置密码指令
config set requirepass 密码
#设置密码后认证密码指令
auth 密码
  • 限制(CLIENTS)
    在这里插入图片描述
    在这里插入图片描述

  • APPEND ONLY (aof配置)
    在这里插入图片描述

redis持久化

前面说了redis是内存数据库,内存在断电后数据会丢失,因此redis也提供了rdb和aof两种持久化

rdb持久化(redis默认,无需配置)

该机制是指在指定时间间隔内将内存中的数据写入磁盘

优点:

  • 相比于aof,在数据量比较大时,rdb的启动效率会比较高
  • 对于灾难恢复而言,rdb是个不错的选择,我们可以轻松的将一个独立的文件压缩后再转移到其他存储介质上
  • 性能最大化,对于redis服务器而言,他至于在持久化启动时fork出子进程,在由子进程完成持久化工作,极大避免了服务进程执行I/O操作

缺点:

  • 如果在定时持久化之前出现宕机,那么在此期间的数据来不及写入磁盘所以不会被持久化,即数据丢失,比如:每隔60s持久化一次,那么在最后一个60s内出现宕机的话,那么最后的这60内的数据将丢失。
aof持久化

该机制是指以日志的形式记录服务器上的每一个写操作,在redis服务器启动之初会读取该文件来重新构建数据库

优点:

  • 该机制可以带来更高的数据安全性
  • 由于该机制对日志文件的写入是采用append模式,在写入过程中出现宕机也不会破坏日志文件里面已经存在的内容

缺点:

  • 对于相同的数量的数据集而言,aof的文件会大于rdb
  • 根据同步策略不同,aof在运行策略上往往会慢与rdb

redis发布订阅

发布订阅是一种消息通信模式
在这里插入图片描述
原理:
redis-server里维护了一个字典,字典的键就一个个频道,而字典的值则是由一个个消息订阅者组成的链表。 通过subscribe订阅某频道后,就会将该订阅者添加到该频道的订阅链表中。通过publish向订阅者发布消息,redis-server会将给定的频道作为键,遍历该频道内由订阅者组成的链表,并将消息发送给他们

测试:
订阅者订阅消息

127.0.0.1:6379> subscribe yinghuo #订阅者客户端
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "yinghuo"
3) (integer) 1

发布者向订阅者发布消息

127.0.0.1:6379> publish yinghuo helloworld #发布者客户端
(integer) 1

#此时订阅者就会收到发布者发布的消息
127.0.0.1:6379> subscribe yinghuo  #订阅者客户端
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "yinghuo"
3) (integer) 1
1) "message" 
2) "yinghuo" #订阅的频道
3) "helloworld" #订阅消息的内容

使用场景:实时消息(比如在某个网站注册会员后,就相当于订阅了频道,而发布者就会向由会员组成的订阅链表实时发送消息)、微信公众号关注等

redis主从复制

主从复制是指将一台redis服务器上的数据复制到另一台redis服务器上,前者称为主节点(master/leader),后者称为从节点(slave/follower)。数据的复制是单向的,即只能从主节点复制到从节点,其中主节点以写为主,从节点以读为主。
在公司中redis一般是配置集群的,因为redis服务器存在宕机订单可能,需要丛机来备份,如果有用到哨兵模式,至少需要两台从机。
注意:默认每台redis服务都是主节点,一个主节点可以有多个从节点,但一个从节点只能有一个主节点。

redis集群搭建(一主二从)

由于redis默认情况下都是主机,所以我们只需要再配置从机即可

127.0.0.1:6379> info replication //查看当前库的信息
# Replication
role:master //主节点
connected_slaves:0  //拥有0个从节点
master_replid:00cb0978353a7f01564d0ea326ff41ac841142fc
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
127.0.0.1:6379> 

  • 拷贝3份redis.conf文件
    在这里插入图片描述
  • 分别修改3份配置文件
    1、 port 6379 //端口
    2、pidfile /var/run/redis_6379.pid //后台运行的pid
    3、logfile “6379.log” //日志文件名
    4、dump6379.rdb //名字
  • 启动3个redis服务
    在这里插入图片描述
  • 配置从机(这里以79为主机 80和81为从机)

操作指令:slaveof 主机的ip 主机的端口
配置80从机(81一样操作步骤):
在这里插入图片描述

此时查询主机的信息
在这里插入图片描述

注意:
1、这是使用的是命令才配置从机,而在真实环境中一般在配置文件中配置从机 如下:
在这里插入图片描述
2、主机如果宕机,从机可以继续使用,但从机只能读不能写;如果从机宕机,由于这里使用的是命令配置的从机,在从机重启后会变成主机(里面存储着宕机执之前的数据,但无法跟主机同步),需要重新配置,配置完后主机的数据自动同步(全量复制)到主机中

主从复制基本原理

slave启动成功后会向master发送同步指令
master接收到指令,启动后台的存储进程,同时收集所有修改数据集的命令,在后台进程执行结束后,将整个数据文件发送给slave,完成一次完全同步。

哨兵模式

在哨兵模式出来之前,如果出现主机宕机了,那么我们需要手动来设置一个新的主机(命令:slaveof no one),并重新配置从机。这样无疑增加了配置压力。

哨兵模式概述

哨兵模式是一种特特殊模式,它是独立的进程,作为独立的进程,它会向redis服务器发送命令并等待服务器响应,从而监控运行的redis实例。
在这里插入图片描述
哨兵模式的执行过程:通过向服务器发送命令,让master返回其监控的运行状态,包括master和从slave,当master出现宕机时,哨兵会通过选举(多个哨兵进行投票)自动选出新的主机,并通过发布订阅模式通知其他从服务器,修改配置,让他们切换主机

哨兵模式测试:以一主二从为例

在redis 启动目录下创建一个名为sentinel.conf的配置文件,在里面添加监控主机的配置(也可以在redis安装目录下直接copy一份sentinel.conf进行修改)

# sentinel monitor 被监控的名称 host port  1  1代表1个哨兵认为主机宕机时master就会失效
sentinel monitor mymaster 127.0.0.1 6379 1 

启动哨兵

[root@localhost bin]# redis-sentinel sentinel.conf

在这里插入图片描述

当主机(6379)宕机时
在这里插入图片描述
当主机恢复时:
在这里插入图片描述

哨兵模式的优缺点

哨兵模式的优点:

  1. 哨兵模式是基于主从复制的,继承了主从复制的所有优点
  2. 主从可以切换,故障可以转移,系统可用性会更好
  3. 哨兵模式就是主从模式的升级,由手动到自动,更加方便灵活

哨兵模式的缺点:

  1. redis不好在线扩容,集群达到上限时,扩容就会变得十分复杂
  2. 实际的哨兵集群配置其实是十分复杂的

缓存穿透和缓存雪崩

缓存穿透
概念

缓穿透是指用户想要查询一个数据,发现redis数据库里没有,也就是缓存没有被命中,于是向持久层去查询,发现持久层也没有,于是查询失败。当在同一时刻很多用户都出现缓存未命中时,于是都去请求持久层数据库,在这一瞬间会给数据库造成很大的压力,这时就相当于缓存穿透。

解决方案

1、布隆过滤器
布隆过滤器是一种数据结构,对所有可能查询的参数以hash的形式存储,在控制层进行校验,不符合则丢弃,从而避免了对数据存储系统的查询压力
2、缓存空对象
当存储层不命中后,即使返回空对象也要讲其缓存起来,同时设置过期时间,之后再访问这个数据就会从缓存中直接获取,保护了后端数据源。

缓存击穿
概念

缓存击穿是指当大量用户同时访问缓存上的一个key,比如微博的热搜、淘宝热热卖商品等等,在key过期的一瞬间,所有请求都打在了数据库上,给数据库造成很大的压力。

解决方案

1、设置热点数据永不过期
2、使用分布式锁
保证每个key同时只允许一个线程去后端数据库查询,其他线程因为没有获得分布式锁的权限,所以只能等待。

缓存雪崩
概念

缓存雪崩是指同一时间大量的缓存数据同时过期了,而此时查询的并发量巨大直接冲击数据库造成数据库压力过大或宕机的现象,和缓存击穿不同,缓存击穿是针对同一个数据的查询,而缓冲雪崩是各种数据都过期了,而导致不同请求全部打到数据库上。

解决方案

1、服务降级
2、设置热点数据永不过期
3、缓存的数据过期时间设置随机,防止同一时间大量数据同时过期

最后感谢狂神老师的教学视频:https://www.bilibili.com/video/BV1S54y1R7SB?p=36

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值