【Redis】面试常问问题(一)

一、最基本问题

       1、在项目中缓存是如何使用的,为啥要用?用了以后可能会有什么不良后果。

       2、redis和memcached有什么区别?redis的单线程模型是什么?为什么单线程的redis比多线程的memcached效率要高的多。

       3、Redis都有哪些数据类型?分别在哪些场景下使用比较合适?

       4、Redis过期策略能介绍一下?要不你手写一个LRU。  

二、为啥要用

       1、缓存是如何实现高性能

                                  

       经典的场景电商:假设某个商品的信息,在1天之内都不会改变。但是这个商品每次查询一次要消耗2s。那这1天只能被浏览100万次。

     2、缓存是如何实现高并发

                                   

三、用了之后可能会有什么不良后果

       常见的缓存问题有三个。

       1、缓存与数据库双写不一致。

       2、缓存雪崩

       3、缓存穿透

四、redis和memcached有什么区别

       1、Redis支持更多的数据类型。String、hash、list、set、zset。而memcached只支持String。

       2、Redis支持持久化。可以通过aof或者rdb进行数据恢复。memcached不支持。

       3、Redis支持原生的集群模式redis cluster

五、Redis单线程模型

       Redis基于Reactor模式开发了文件事件处理器。这个文件事件处理器是单线程的。所以Redis才叫做单线程模型。它采用了IO多路复用机制,同时监听多个socket。

       1、客户端与Redis通信的一次流程

                                        

六、为什么Redis单线程还能支持高并发

       1、非阻塞IO多路复用

       2、纯内存操作

       3、单线程避免了多线程频繁的上下文切换

说明:

        上下文切换:CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再次加载这个任务的状态,从任务保存到再加载的过程就是一次上下文切换。  

七、Redis过期策略+内存淘汰机制

       先来看下可能有的疑问。

       1、疑问1:往redis写的数据怎么没了

                                          

       2、疑问2:数据命名过期了,怎么还占着内存

                                        

       我们在set key的时候,都可以给一个expire time,就是过期时间。指定这个key的expire time为1个小时, 则1个小时之后,缓存失效。

       假设设置了一批key只能存活1个小时。那么接下来1个小时后,是怎么对这批key进行删除的?

       答案是:定期删除+惰性删除

       ① 定期删除:指的是redis每隔100ms就随机抽取一些设置了过期时间的key,检查是否过期,如果过期就删除。假设redis里放了10万个key,都设置了过期时间。每隔几百ms检查10万个key。那redis基本上就死了。cpu负载会很高,都消耗在检查过期key上啦。实际上是,redis每隔100ms随机抽取一些key来检查和删除的。

       ② 惰性删除:定期删除可能会导致很多过期key到了时间并没有被删除掉。就只能依赖惰性删除啦。这就是说在你获取某个key的时候,redis会检查一下,这个key是否设置了过期时间。如果过期了,此时就删除。当你查询这个key的时候,redis在惰性检查一下。

       通过定期删除+惰性删除,保证过期的key一定会被干掉。

       但是实际上,这还是有问题的。如果定期删除漏掉了很多过期key,然后你也没及时去检查。也就是说没走惰性删除,此时会怎么样呢?如果大量的key堆积在内存里,导致redis内存快耗尽了,咋整?

       答案是:走内存淘汰机制

       noeviction:当内存不足以容纳新写入数据时,新写入操作会报错,这个一般没人用吧
       allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key(这个是最常用的)
       allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key,这个一般没人用吧
       volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key(这个一般不太合适)
       volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key
       volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除 

八、手写一个LRU算法

       使用LinkedHashMap来实现, LinkedHashMap底层就是用的HashMap+双链表实现的。而且本身已经实现了按照访问顺序的存储。此外,LinkedHashMap中本身就实现了1个方法,用于判断是否需要移除最不常读的数,方法默认是直接返回false。所以需要重新改方法。当缓存满后就移除最不常用的数。

import java.util.LinkedHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 利用LinkedHashMap实现简单的缓存, 必须实现removeEldestEntry方法,
 */
public class LRULinkedHashMap<K,V> extends LinkedHashMap<K,V> {
    //最多能缓存多少数据
    private final int maxCapacity;

    private static final float DEFAULT_LOAD_FACTOR = 0.75f;

    private final Lock lock = new ReentrantLock();

    public LRULinkedHashMap(int maxCapacity) {
        //设置1个hash的初始大小   accessOrder为true意思是让linkedHashMap按照顺序
        //访问来进行排序,最近访问的放在头,最老访问的放在尾
        super(maxCapacity, DEFAULT_LOAD_FACTOR, true);
        this.maxCapacity = maxCapacity;
    }

    @Override
    protected boolean removeEldestEntry(java.util.Map.Entry<K, V> eldest) {
        //当map中的数据量大于指定的缓存个数的时候,就自动删除最老的数据
        return size() > maxCapacity;
    }
}

        

       

  

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值