redis常见问题

1. Redis是什么?

       Redis是由C语言编写、基于内存、支持多种数据结构、高性能的Key-Value数据库。

       它支持string,list,set,sorted set,hash等数据结构;支持数据持久化,防止重启后数据清空;支持主从备份;事务等

2. 为什么使用Redis?

       项目中使用redis,主要考虑两个方面:并发和性能。redis也可以充当中间件,但是也有其他专门的中间件代替,而且它的特长并不体现在这里。

2.1 并发

       在大并发的情况下,所有的请求直接访问数据库,数据库的读写方式是磁盘读/写,速度相对比较慢,此时要求数据库短时间完成大量访问,很有可能造成数据库宕机,所以引入基于内存进行读写操作的redis。

逻辑:高并发情况下,请求到达服务器,只把业务数据在redis上进行读写,而不对数据库做操作,完成逻辑后将redis缓存数据一次性写入数据库,这样来提高性能。(在内存操作数据完成后,最后操作磁盘)

       注意:缓存中数据仍要落库持久化,所以一个请求在redis上完成读写操作后,判断业务逻辑是否完成,比如秒杀商品数目为0,红包金额为0,将redis缓存数据一次性写入数据库,完成持久化。否则不操作数据库

2.2 性能

       一般访问数据库,读操作要多于写操作,如果每次都访问数据库,会相对很慢,所以把数据放缓存里读写会快很多,并缓解数据库压力。

逻辑:当第一次访问数据库,读取redis数据肯定为空,此时就读取数据库,并放到redis(注意非空判断)。之后每次读取数据,都直接读取redis,这样来提高系统性能。(此时考虑写操作DB和redis数据一致的问题,见下文)

        注意:如果数据并不常用,写操作频率大于读操作,考虑成本如占存储很大的数据,这些就不需要放在redis缓存中。redis只存储业务常用的数据和主要的数据,比如用户登录信息。

3. 其他常见问题

1. 单线程的redis为什么这么快

参考:https://blog.csdn.net/xlgen157387/article/details/79470556

参考:https://redis.io/topics/benchmarks

  • 纯内存操作
  • 单线程操作,避免了频繁的上下文切换
  • 采用了异步非阻塞 IO
  • 高效的数据结构

      非阻塞 I/O 多路复用机制:按照我的理解,只有一个线程,根据每个I/O流的状态,来管理多个I/O流。如快递员送货,但只有一个快递员,送货地点有很多,需要标记每个送货点的地址,然后送一个快递再回到取货点拿下一个快递送到下一个地点。

2. redis的数据类型,以及每种数据类型的使用场景

参考:https://segmentfault.com/a/1190000012212663

  • String:缓存、计数器、分布式锁等。
  • List:链表、队列、微博关注人时间轴列表等。
  • Hash:用户信息、Hash 表等。
  • Set:去重、赞、踩、共同好友等。
  • Zset:访问量排行榜、点击量排行榜等。

3. redis的过期策略以及内存淘汰机制

参考:https://blog.csdn.net/qq_28018283/article/details/80764518

       如redis只能存5G数据,可是你写了10G,那会删5G的数据。redis是如何删除的?如果数据设置了过期时间,但是时间到了,内存占用率还是比较高,是什么原因?

       如果采用定时删除,定时器来监视key,过期定时删除,这样十分消耗CPU,所以redis未采用此方式(X)

 redis采用的是定期删除+惰性删除策略(✔)

  • 定期删除:redis默认每个100ms检查,是否有过期的key,有过期key则删除。但redis并不是对所有key进行检查,而是随机进行检查,所以很多key在过期后尚未被删除,所以需要惰性删除
  • 惰性删除:获取某个key的时候,redis先检查此key是否过期了,如果过期了此时再删除。

       此时如果并没有去获取此key(惰性删除未生效),redis的内存就会越来越高,此时采用内存淘汰机制。在redis.conf配置文件中,有一行配置

# maxmemory-policy volatile-lru

       即配置内存淘汰策略,推荐:allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key

4. 数据库和redis的数据如何保持同步

参考:https://www.cnblogs.com/rjzheng/p/9041659.html

       首先要配置缓存过期时间,在过期后再进行操作就会根据数据库操作,不存在同步问题。此时,讨论在未过期这段时间的同步问题。

     一般有三种策略,根据具体业务场景选择

  1. 先更新数据库,再更新缓存(不考虑)
  2. 先删除缓存,再更新数据库(不推荐)
  3. 先更新数据库,再删除缓存(推荐)
  • 第一种  先更新数据库,再更新缓存

       假设请求A和请求B进行更新操作,可能会出现
       (1)线程A更新了数据库
       (2)线程B更新了数据库
       (3)线程B更新了缓存
       (4)线程A更新了缓存
       此时应该A更新缓存应该比B更新缓存早才对,但由于网络等原因,B却比A更早更新了缓存。这就会产生脏数据。

       而且如果写操作比较多,读操作较少,这种方案会导致数据库和缓存会被频繁的更改,但很少读取,浪费性能

  • 第二种  先删除缓存,再更新数据库

       假设请求A进行更新,请求B进行读取,

       (1)请求A进行写操作,删除缓存
       (2)请求B查询发现缓存不存在
       (3)请求B去数据库查询得到旧值
       (4)请求B将旧值写入缓存
       (5)请求A将新值写入数据库

       即在线程A写操作的程序中,删除缓存和更新数据库的过程中,线程B又读取数据库原数据重新更新了缓存,出现了脏数据。此时,可以使用延时双删策略。

redis.delKey(key);    //删除缓存
db.updateData(data);    //更新数据库
Thread.sleep(1000);    //延时等待时间根据读操作的耗时时间加几百ms
redis.delKey(key);    //再次删除缓存

       但延时时间影响到吞吐量降低(第二次删除可以另开启一线程异步删除来解决),而且第二次删除失败怎么办?

  • 第三种  先更新数据库,再删缓存

先把数据落库更新,成功后再删除缓存。但仍存在很小概率的脏数据事件:

       假设请求A查询,请求B更新

       (1)缓存刚好失效
       (2)请求A查询数据库,得一个旧值
       (3)请求B将新值写入数据库
       (4)请求B删除缓存
       (5)请求A将查到的旧值写入缓存

       对于缓存过期的问题,可以进行缓存预热,即在过期时,异步线程读取数据库,更新缓存。

       此时仍可以异步延时删除策略,但第二种的二次删除失败问题仍可能存在。

       解决:

       (1)如果对一致性要求不太高,可以在程序中另起一线程每个一段时间重试删除

       (2)可以使用订阅binlog程序(如mysql的canal),如果删除失败,从订阅程序中提取所需的key,可以将信息发送至消息队列,判断消息队列有该数据,就进行删除。

5. redis持久化问题

参考:https://segmentfault.com/a/1190000002906345

参考:你的Redis怎么持久化的

持久化是为了解决进程退出(如重启,宕机,断电等原因),防止内存中数据清空,将其保存在磁盘上。

redis有两种持久化方式:快照(RDB,默认追加式文件(AOF(还有不常用的两种:虚拟内存方式和diskstore方式)

  • RDB 持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)
  • AOF 持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。
  • Redis 可以同时使用 AOF 持久化和 RDB 持久化。 此时,当 Redis 重启时优先使用 AOF 文件来还原数据集, 因为 AOF 文件保存的数据集通常比 RDB 文件所保存的数据集频率更高,更完整。但RDB性能较好

6. 缓存穿透,缓存击穿和缓存雪崩问题

参考:https://blog.csdn.net/zeb_perfect/article/details/54135506

  • 穿透:长时间请求缓存中不存在的数据,请求就会到达数据库,如果并发量很大,可能会导致数据库宕机或其他连接异常问题
  • 击穿:某个key设置了过期时间,此时在过期的这个时间点对Key有大量的并发请求过来,这些请求发现缓存过期一般都会从后端DB加载数据并回设到缓存,这时大并发的请求可能会瞬间把后端DB压垮
  • 雪崩:缓存突然集体失效(如对key设置了相同的过期时间),此时再次大量请求,也可能会数据库连接异常

7. Redis锁

参考:http://www.360doc.com/content/18/0528/08/36490684_757590223.shtml

参考文章:

深度学习redis系列:https://www.cnblogs.com/kismetv/p/8654978.html#t6

知乎:为什么我们做分布式使用 Redis ?

知乎:redis为什么这么快?

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值