zoukankan      html  css  js  c++  java
  • Redis常见面试题

    在平时我们常常使用 Redis ,这里总结一下 Redis 的相关面试题和一些常见问题的解决方案。

    Redis 在互联网公司一般有已下应用:

    • String:缓存、限流、计数器、分布式锁、分布式 Session
    • Hash:存储用户信息、用户主页访问量、组合查询
    • List:微博关注人时间轴列表、简单队列
    • Set:踩、赞、标签、好友关系
    • Zset:排行榜

    Redis 为什么会这么快?

    • Redis 是纯内存操作,并且异步持久化到硬盘中。
    • Redis 是单线程,从而避免了多线程中上下文频繁切换的问题。
    • Redis 底层数据结构简单,对数据的操作也简单。
    • Redis 使用非阻塞多路 I/O 复用模型,效率高。

    Redis 缓存雪崩该如何避免?

    1.对缓存设置相同的过期时间,导致某段时间内缓存失效,请求全部走数据库

    在缓存的时候给过期时间加上一个随机值,这样就会大幅减少缓存再同一时间过期。

    2.Redis 挂掉了,请求全部走数据库

    事发前:实现 Redis 的高可用
    事发中:本地缓存(ehcache)+限流(hystrix),尽可能的减少数据库被干掉的可能
    事发后:使用 Redis 的持久化机制,重启后快速恢复缓存数据

    缓存击穿如何避免?

    缓存击穿是指查询一个一定不存在的数据,由于缓存不命中,并且从数据库查询不到的数据不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,失去了缓存的意义。

    1.对请求的参数使用布隆过滤器(BloomFilter)或者提前拦截这个请求,不让其请求到数据库。
    2.我们也可以对这个空值对象缓存到 Redis,当然我们必须设置一个较短的过期时间,以防止这空值对象对业务数据产生影响。

    缓存与数据库双写一致

    一般的我们队读操作都有一个套路:
    1.如果我们的数据在缓存中有,我们就直接取缓存中的。
    2.如果缓存中没有我们想要的数据,我们会先去查询数据库,然后将数据库查询出来的数据写到缓存中。
    3.最后将数据返回给用户请求。

    高并发情况下,无论是先操作数据库还是后操作数据库,再加上缓存更新,就更加容易导致数据库与缓存数据不一致的问题。如果每次更新了数据库都去更新缓存将是一个非常耗费性能的操作,不如将缓存直接删除掉。等下次读取的时候,缓存没有找到,再到数据库找,再将数据库中的数据缓存到 Redis 中。

    解决思路:
    先更新数据库,再删除缓存
    这样可以解决大部分的并发问题,但是也存在一定的概率(极小)导致缓存不一致的情况。

    • 缓存刚好失效
    • 线程 A 查询数据库,得到一个旧值
    • 线程 B 将新值写入数据库
    • 线程 B 删除缓存
    • 线程 A将插到的旧数据写入缓存

    先删除缓存,再删除数据库
    这样其实也可以解决并发问题,但是其实也会有一定概率导致缓存不一致的情况。

    • 线程 A 删除了缓存
    • 线程 B 查询,发现缓存已不存在
    • 线程 B 去数据库查询得到旧数据
    • 线程 B 将旧数据写入缓存
    • 线程 A 将新值写入数据库

    但是上面两种方式都是在很极端的情况下才会发生的情况,如果在需要缓存和数据强一致性的情况下可以将删除缓存、修改数据库放在一个队列中去执行,实现串行化,这样就可以保证缓存和数据库的一致性。

  • 相关阅读:
    Leetcode 92. Reverse Linked List II
    Leetcode 206. Reverse Linked List
    Leetcode 763. Partition Labels
    Leetcode 746. Min Cost Climbing Stairs
    Leetcode 759. Employee Free Time
    Leetcode 763. Partition Labels
    搭建数据仓库第09篇:物理建模
    Python进阶篇:Socket多线程
    Python进阶篇:文件系统的操作
    搭建数据仓库第08篇:逻辑建模–5–维度建模核心之一致性维度2
  • 原文地址:https://www.cnblogs.com/manastudent/p/12264367.html
Copyright © 2011-2022 走看看