文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Java面试题冲刺第二天--Redis篇

2024-04-02 19:55

关注

面试题1:为什么要用 Redis ?业务在哪块儿用到的?

正经回答:

Redis是眼下最为人熟知的缓解高并发、提升高可用能力的手段之一,再提升服务器性能方面效果显著。

这里不得不提到高并发场景,我们知道,并发场景下核心点在数据库,引入缓存(以及引入任何负载均衡、集群等策略)的目的都是在减轻数据库压力,让更多原本打到DB上的请求,在中间被拦截处理掉。就像你请个假屁大点儿事还要大老板签字一样?

在这里插入图片描述

通俗易懂点儿说,高并发对服务器来说,就好比你被人锤一拳,这拳头可是硬的很,光着膀子的话一拳就给我干吐血。。那么我为了承受住这一拳?穿棉袄、穿护垫、穿…是吧,只要够厚,我都以为你在给我挠痒痒~同理,Redis就是一件又厚又弹的棉袄。

话说回来,它有多厚多弹呢?操作缓存就是直接操作内存,速度相当快,直接操作缓存能够承受的请求数是远远大于直接访问数据库的。

Redis优势:

假如用户第一次访问数据库中的某些数据。这个过程会比较慢,因为是从硬盘上读取的。将该用户访问的数据存在数Redis中,这样下一次再访问这些数据的时候就可以直接从缓存中获取了。同样,我们可以把数据库中的部分数据转移到缓存中去,这样用户的一部分请求会直接打到缓存而不是数据库(即半路拦截掉了)。如果数据库中的对应数据改变的之后,同步改变缓存中相应的数据即可!

在我们业务中,包括热点词查询、一些实时排行榜数据、访问量点赞量统计、Session共享等等都可以引入Redis来处理。

在这里插入图片描述

深入追问: 追问1:Redis里有哪些数据类型?

丰富的数据类型,Redis有8种数据类型,当然常用的主要是 String、Hash、List、Set、 SortSet 这5种类型,他们都是基于键值的方式组织数据。每一种数据类型提供了非常丰富的操作命令,可以满足绝大部分需求,如果有特殊需求还能自己通过 lua 脚本自己创建新的命令(具备原子性);

在这里插入图片描述

追问2:Redis与Memcached有哪些区别?

两者都是非关系型内存键值数据库,现在公司一般都是用 Redis 来实现缓存,为什么不用Memcached呢?

参数 Redis Memcached
类型 1. 支持内存 2. 非关系型数据库 1. 支持内存 2. 键值对形式 3. 缓存形式
数据存储类型 1. String 2. List 3. Set 4. Hash 5. Sort Set 1. 文本型 2. 二进制类型
附加功能 1. 发布/订阅模式 2. 主从分区 3. 序列化支持 4. 脚本支持【Lua脚本】 多线程服务支持
网络IO模型 单线程的多路 IO 复用模型 多线程,非阻塞IO模式
持久化支持 1. RDB 2. AOF 不支持
集群模式 原生支持 cluster 模式,可以实现主从复制,读写分离 没有原生的集群模式,需要依靠客户端来实现往集群中分片写入数据
内存管理机制 在 Redis 中,并不是所有数据都一直存储在内存中,可以将一些很久没用的 value 交换到磁盘 Memcached 的数据则会一直在内存中,Memcached 将内存分割成特定长度的块来存储数据,以完全解决内存碎片的问题。
适用场景 复杂数据结构,有持久化,高可用需求,value存储内容较大,最大512M 纯key-value,数据量非常大,并发量非常大的业务

追问3:那Redis怎样防止异常数据不丢失的?如何持久化?

RDB 持久化 (快照)

AOF 持久化(即时更新)

  有以下同步选项(同步频率): always 每个写命令都同步;everysec 每秒同步一次;no 让操作系统来决定何时同步。   everysec 选项比较合适,可以保证系统崩溃时只会丢失一秒左右的数据,并且 Redis 每秒执行一次同步对服务器性能几乎没有任何影响;

面试题2:Redis为啥是单线程的?

Redis is single threaded. How can I exploit multiple CPU / cores? It's not very frequent that CPU becomes your bottleneck with Redis, as usually Redis is either memory or network bound. For instance, using pipelining Redis running on an average Linux system can deliver even 1 million requests per second, so if your application mainly uses O(N) or O(log(N)) commands, it is hardly going to use too much CPU. However, to maximize CPU usage you can start multiple instances of Redis in the same box and treat them as different servers. At some point a single box may not be enough anyway, so if you want to use multiple CPUs you can start thinking of some way to shard earlier. You can find more information about using multiple Redis instances in the Partitioning page. However with Redis 4.0 we started to make Redis more threaded. For now this is limited to deleting objects in the background, and to blocking commands implemented via Redis modules. For future releases, the plan is to make Redis more and more threaded.

正经回答:

上面是Redis官网给的解释(官方文档链接),翻译后简单说,因为Redis的瓶颈不是CPU的运行速度,而往往是网络带宽和机器的内存大小。再说了,单线程切换开销小,容易实现。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案,当然了,也是为了避免多线程存在的很多坑。对了,一个节点是一个单线程。

深入追问:

追问1:单线程只使用了单核CPU,太浪费,有什么办法发挥多核CPU的性能嘛?

我们可以通过在单机开多个Redis 实例,我们一直在强调的单线程,只是在处理我们的网络请求的时候只有一个线程来处理。实际上,一个正式的Redis Server运行的时候肯定是不止一个线程的,都是集群形式,多少多少个节点,所以实际环境中大家不用担心这种问题。

面试题3:聊一下对缓存穿透、缓存击穿、缓存雪崩的理解吧

正经回答:

深入追问:

追问1:那你说一下针对缓存击穿的解决方法

在这里插入图片描述

  1. 根据实际业务情况,在Redis中维护一个热点数据表,批量设为永不过期(如top1000),并定时更新top1000数据。
  2. 加互斥锁(mutex key)

互斥锁 缓存击穿后,多个线程会同时去查询数据库的这条数据,那么我们可以在第一个查询数据的请求上使用一个互斥锁来锁住它。其他的线程走到这一步拿不到锁就等着,等第一个线程查询到了数据,然后做缓存。后面的线程进来发现已经有缓存了,就直接走缓存。


    static Lock reenLock = new ReentrantLock();
    public List<String> getData04() throws InterruptedException {
        List<String> result = new ArrayList<String>();
        // 从缓存读取数据
        result = getDataFromCache();
        if (result.isEmpty()) {
            if (reenLock.tryLock()) {
                try {
                    System.out.println("拿到锁了,从DB获取数据库后写入缓存");
                    // 从数据库查询数据
                    result = getDataFromDB();
                    // 将查询到的数据写入缓存
                    setDataToCache(result);
                } finally {
                    reenLock.unlock();// 释放锁
                }
            } else {
                result = getDataFromCache();// 先查一下缓存
                if (result.isEmpty()) {
                    System.out.println("我没拿到锁,缓存也没数据,先小憩一下");
                    Thread.sleep(100);// 小憩一会儿
                    return getData04();// 重试
                }
            }
        }
        return result;
    }

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注编程网的更多内容!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯