面试必备Redis知识 -- Redis面试题(二)

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 面试必备Redis知识 -- Redis面试题(二)

1、Redis 事务

👨‍💻 :说一下你对 redis 事务的了解呗。

Redis 可以通过 MULTI,EXEC,DISCARD 和 WATCH 等命令来实现事务功能。

  • 事务流程
  1. 开始事务(MULTI)。
  2. 命令入队(批量操作 Redis 的命令,先进先出(FIFO)的顺序执行)。
  3. 执行事务(EXEC)。

你也可以通过 DISCARD 命令取消一个事务,它会清空事务队列中保存的所有命令。

WATCH 命令用于监听指定的键,当调用 EXEC 命令执行事务时,如果一个被 WATCH 命令监视的键被修改的话,整个事务都不会执行,直接返回失败。

Redis 是不支持 roll back 的,因而不满足原子性的(而且不满足持久性)

2、如何实现分布式锁?

👨‍💻 :高并发下分布式系统中的数据线程安全怎么保障?

① 加锁

    /**
     * 加锁
     * @param key
     * @param value
     * @return
     */
    public boolean lock(String key,String value){
        if(redisTemplate.opsForValue().setIfAbsent(key,value)){
            // 加锁成功
            return true;
        }

        // 如果锁过期
        String currentValue = redisTemplate.opsForValue().get(key);
        if(!StringUtils.isEmpty(currentValue) &&
                Long.parseLong(currentValue) < System.currentTimeMillis()){

            String oldValue = redisTemplate.opsForValue().getAndSet(key,value);
            if(!StringUtils.isEmpty(oldValue) &&
                    oldValue.equals(oldValue)){
                return true;
            }
        }

        // 锁已经被其它线程获取
        return false;
    }
  • setIfAbsent:如果对应的 key 不存在的话,那么就进行相关设置,也就是加锁成功。同时我们设置进行的 value 是对应的 key 的过期时间。
  • 过期时间的判断:如果对应的锁被相关的其它进程获取,我们还要判断对应的锁是否过期。如果过期的话,那么其它的线程就可以进行争抢。
  • getAndSet:获取旧值设置新值,该操作是原子性的。
  • oldValue.equals(oldValue):该判断尤其重要,因为我们此时是高并发状态下,那么就有可能出现对应的线程争抢情况,但是我们只能允许一个线程获取锁,那么我们就要对其进行 oldValue 的判断,如果是相同的话,那么就获取锁成功,否则就是被其它线程争抢过去了。

② 解锁

  • 查询当前“锁”是否还是我们持有,因为存在过期时间,所以可能等你想解锁的时候,“锁”已经到期,然后被其他线程获取了,所以我们在解锁前需要先判断自己是否还持有“锁”
  • 如果“锁”还是我们持有,则执行解锁操作,也就是删除该键值对,并返回成功;否则,直接返回失败。
    /**
     * 解锁
     * @param key
     * @param value
     */
    public void unlock(String key,String value){
        try{
            String currentValue = redisTemplate.opsForValue().get(key);
            if(!StringUtils.isEmpty(currentValue) &&
                    currentValue.equals(value)){
                redisTemplate.opsForValue().getOperations().delete(key);
            }
        }catch (Exception e){
            log.error("【redis 分布式锁】 解锁异常,{}",e);
        }
    }

3、缓存穿透

👨‍💻 :简要说一下缓存穿透现象和怎样应对 ?
  • 描述:访问一个缓存和数据库都不存在的 key,此时请求会直接打到数据库上,并且数据库查不到数据,也没办法写入缓存,所以下一次请求同样会打到数据库上。
解决方案
  1. 接口校验:后端接口增加数据合理性校验,例如商品查询中,商品的ID是正整数,则可以直接对非正整数直接过滤。
  2. 缓存空值:当访问缓存和DB都没有查询到值时,可以将空值写进缓存,为其设置短点的过期时间,防止同一个 key 被一直攻击。
  3. 布隆过滤器:使用布隆过滤器存储所有可能访问的 key,不存在的 key 直接被过滤,存在的 key 则再进一步查询缓存和数据库。

4、缓存击穿

👨‍💻 :简要说一下缓存击穿现象和怎样应对 ?
  • 描述:某一个热点 key,在缓存过期的一瞬间,同时有大量的请求打进来,由于此时缓存过期了,所以请求最终都会走到数据库,造成瞬时数据库请求量大、压力骤增,甚至可能打垮数据库。
解决方案
  1. 设置热点数据不过期,或者定时任务定时更新缓存。
  2. 设置互斥锁,在并发的多个请求中,只有第一个请求线程能拿到锁并执行数据库查询操作,其他的线程拿不到锁就阻塞等着,等到第一个线程将数据写入缓存后,直接走缓存。(可以使用 Redis 分布式锁

5、缓存雪崩

👨‍💻 :简要说一下缓存雪崩现象和怎样应对 ?
  • 描述:大量的热点 key 设置了相同的过期时间,导在缓存在同一时刻全部失效,造成瞬时数据库请求量大、压力骤增,引起雪崩,甚至导致数据库被打挂。
解决方案
  1. 加互斥锁: 该方式和缓存击穿一样,按 key 维度加锁,对于同一个 key,只允许一个线程去计算,其他线程原地阻塞等待第一个线程的计算结果,然后直接走缓存即可。
  2. 热点数据不过期:该方式和缓存击穿一样。
  3. 过期时间打散:既然是大量缓存集中失效,那最容易想到就是让他们不集中生效。可以给缓存的过期时间时加上一个随机值时间,使得每个 key 的过期时间分布开来,不会集中在同一时刻失效。

6、Redis 常见性能问题和解决方案

👨‍💻 :你了解redis 常见性能问题和解决方案吗?
  1. Master 最好不要写内存快照,如果 Master 写内存快照,save 命令调度rdbSave 函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务
  2. 如果数据比较重要,某个 Slave 开启 AOF 备份数据,策略设置为每秒同步一次
  3. 为了主从复制的速度和连接的稳定性,Master 和 Slave 最好在同一个局域网
  4. 尽量避免在压力很大的主库上增加从库
  5. 主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <-Slave1<- Slave2 <- Slave3…这样的结构方便解决单点故障问题,实现 Slave对 Master 的替换。如果 Master 挂了,可以立刻启用 Slave1 做 Master,其他不变。

7、Redis 如何做内存优化?

👨‍💻 :redis 如何做内存优化?

尽可能使用散列表,散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。比如你的 web 系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的 key,而是应该把这个用户的所有信息存储到一张散列表里面

8、如何保证 redis 中的数据都是热点数据?

👨‍💻 :MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据?
  • Redis 提供 6 种数据淘汰策略:
  1. volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
  2. volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
  3. volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
  4. allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 key(这个是最常用的)
  5. allkeys-random:从数据集中任意选择数据淘汰
  6. no-eviction:禁止驱逐数据,也就是说当内存不足以容纳新写入数据时,新写入操作会报错。这个应该没人使用吧!
  • 4.0 版本后增加以下两种:
  1. volatile-lfu:从已设置过期时间的数据集中挑选最不经常使用的数据淘汰
  2. allkeys-lfu:当内存不足以容纳新写入数据时,在键空间中,移除最不经常使用的 key

9、Redis 中如何将指定模式的 key 查找出来?

👨‍💻 :假如 Redis 里面有 1 亿个 key,其中有 10w 个 key 是以某个固定的已知的前缀开头的,如果将它们全部找出来?
  • 使用 keys 指令可以扫出指定模式的 key 列表。
👨‍💻 :如果这个 redis 正在给线上的业务提供服务,那使用 keys 指令会有什么问题?
  1. redis 的单线程的。keys 指令会导致线程阻塞一段时间,**线上服务会停顿,直到指令执行完毕,服务才能恢

复**。

  1. 这个时候可以使用 scan 指令,scan 指令可以无阻塞的提取出指定模式的key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用 keys 指令长。
相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
14天前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
1月前
|
NoSQL Java API
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
在40岁老架构师尼恩的读者交流群中,近期有小伙伴在面试一线互联网企业时遇到了关于Redis分布式锁过期及自动续期的问题。尼恩对此进行了系统化的梳理,介绍了两种核心解决方案:一是通过增加版本号实现乐观锁,二是利用watch dog自动续期机制。后者通过后台线程定期检查锁的状态并在必要时延长锁的过期时间,确保锁不会因超时而意外释放。尼恩还分享了详细的代码实现和原理分析,帮助读者深入理解并掌握这些技术点,以便在面试中自信应对相关问题。更多技术细节和面试准备资料可在尼恩的技术文章和《尼恩Java面试宝典》中获取。
美团面试:Redis锁如何续期?Redis锁超时,任务没完怎么办?
|
27天前
|
存储 NoSQL Redis
Redis常见面试题:ZSet底层数据结构,SDS、压缩列表ZipList、跳表SkipList
String类型底层数据结构,List类型全面解析,ZSet底层数据结构;简单动态字符串SDS、压缩列表ZipList、哈希表、跳表SkipList、整数数组IntSet
|
1月前
|
缓存 NoSQL 算法
面试题:Redis如何实现分布式锁!
面试题:Redis如何实现分布式锁!
|
3月前
|
存储 Java
【IO面试题 四】、介绍一下Java的序列化与反序列化
Java的序列化与反序列化允许对象通过实现Serializable接口转换成字节序列并存储或传输,之后可以通过ObjectInputStream和ObjectOutputStream的方法将这些字节序列恢复成对象。
|
16天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
18天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
41 4
|
1月前
|
算法 Java 数据中心
探讨面试常见问题雪花算法、时钟回拨问题,java中优雅的实现方式
【10月更文挑战第2天】在大数据量系统中,分布式ID生成是一个关键问题。为了保证在分布式环境下生成的ID唯一、有序且高效,业界提出了多种解决方案,其中雪花算法(Snowflake Algorithm)是一种广泛应用的分布式ID生成算法。本文将详细介绍雪花算法的原理、实现及其处理时钟回拨问题的方法,并提供Java代码示例。
74 2
|
1月前
|
JSON 安全 前端开发
第二次面试总结 - 宏汉科技 - Java后端开发
本文是作者对宏汉科技Java后端开发岗位的第二次面试总结,面试结果不理想,主要原因是Java基础知识掌握不牢固,文章详细列出了面试中被问到的技术问题及答案,包括字符串相关函数、抽象类与接口的区别、Java创建线程池的方式、回调函数、函数式接口、反射以及Java中的集合等。
31 0
|
3月前
|
XML 存储 JSON
【IO面试题 六】、 除了Java自带的序列化之外,你还了解哪些序列化工具?
除了Java自带的序列化,常见的序列化工具还包括JSON(如jackson、gson、fastjson)、Protobuf、Thrift和Avro,各具特点,适用于不同的应用场景和性能需求。

热门文章

最新文章

下一篇
无影云桌面