redis面试

0.思维导图

redis面试_第1张图片

1. redis的数据类型♥♥♥

redis有五种数据类型,包括string,list,set,hash,zset;string就类似于java中的字符串,list就类似于Java中的列表,可以存放重复的元素,set就类似于java中的hashset,不能存放重复的元素,hash就类似于Java中的hashMap,存放键值对元素,zset是一个有序集合,每个元素都会有一个score,按照score来进行排序。

2. zset的底层实现♥♥

  • 它有两种实现方式:一个是压缩列表,还有一种是字典加上跳跃表
    • 压缩列表使用紧挨在一起的几点来保存元素和score,第一个节点保存元素,第二个节点保存score,压缩列表的元素按score从小到大排序。
      • 它的使用需要满足两个条件,否则就使用字典加跳跃表:元素个数小于128个,元素长度小于64字节
    • 跳跃表是一种可以进行二分查找的有序链表。原理就是在原有的有序链表上面增加了多级索引,通过索引来实现快速查找;

3. BitMaps

redis面试_第2张图片

4. HyperLogLog

redis面试_第3张图片
redis面试_第4张图片

5. redis的持久化方案♥♥♥

  • RDB(默认的持久化方式):定期保存数据快照至一个rdb文件中,并在启动时自动加载rdb文件,恢复之前保存的数据。

  • AOF:把每一个写请求都记录在一个aof文件中,并且在启动时,会把aof文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新。

  • 区别:RDD效率更高,因为它是直接将Redis的最新数据完整的保存下来,但如果Redis中存储的数据量比较大时,也会有一定的性能消耗,因为它需要创建额外的进程来进行数据的持久化,所以要制定合理的策略;而AOF效率相对RDB要低一些,因为它会将历史的写操作都执行一遍来进行恢复,同时在执行写操作的时候也会将每一个指令存储下来,当我们对数据的安全性要求较高的时候,可以考虑AOF

  • 扩展1:数据量较大时进行快照,用时相对会比较长。如果服务器这个期间收到写请求,那么就不能保证快照的完整性。那么Redis是如何做的?

    • Redis使用的是操作系统提供的写时复制技术,在执行快照的时候,正常处理写操作。【如果主线程要修改一块数据,这块数据就会被复制一份,生成该数据的副本,此时主线程在该副本上进行修改,fork的子线程继续把原来的数据写入RDB文件中】
  • 扩展2:在进行RDB快照的过程中,发生服务崩溃了怎么办?

    • 在快照操作过程中不能影响上一次备份的数据,将上一次完整的RDB快照文件作为恢复内存的参考

6. 缓存穿透,缓存击穿,缓存雪崩♥♥♥

  • 在应用程序和mysql数据块之间建立一个中间层:redis缓存,通过redis缓存可以有效减少查询数据库的时间消耗,但是引入redis又有可能出现缓存穿透,缓存击穿,缓存雪崩等问题
  • 缓存穿透:key在缓存和数据源都没有,那么所有的请求都会去查询数据源,压垮数据源
    • 解决:
      • 当查询不存在时,也就空保存在缓存中【key-null】
      • 采用布隆过滤器,将所有可能存在的数据hash到一个足够大的bitmap中,一个一定不存在的key会被这个bitmap拦截掉,从而避免了对数据源的查询压力。
  • 缓存击穿:key在数据源中有,在缓存中没有,通常时缓存过期了,这时候大量的并发就会全部去请求数据源,导致数据源瘫痪
    • 解决:使用互斥锁,利用setnx来实现该功能,因为当Key不存在的时候,它才会设置一个Key
  • 缓存雪崩:当缓存服务器重启或者大量key缓存集中在某一个时间失效,这时候给数据源的压力也非常大
    • 解决:为key设置不同的缓存失效时间。

7. redis实现分布式锁♥

  锁是一种常用的并发控制机制,用于保证一项资源在任何时候只能被一个线程使用,如果其他线程也要使用同样的资源,必须排队等待上一个线程用完。

  上面说的锁指的是程序级别的锁,例如java语言中的synchronized和ReentrantLock在但应用中使用不会有任何问题,但如果放到分布式环境下就不适用了,这个时候我们就要使用分布式锁。分布式锁比较好理解就是用于分布式环境下并发控制的一种机制,用于控制某个资源在同一时刻只能被一个应用所使用。

分布式锁比较常见的实现方式有三种:

  • Memcached实现的分布式锁:使用add命令,添加成功的情况下,表示创建分布式锁成功。
  • Zookeeper实现的分布式锁:使用Zookeeper顺序临时节点来实现分布式锁。
  • Redis实现的分布式锁
    • 使用setnx,如果创建成功则表名次锁创建成功,否则代表这个锁已经被占用,创建失败。
    • setnx lock true 创建锁
    • del lock 释放锁
    • setnx的问题:setnx虽然可以成功创建分布式锁,但存在一个问题,如果此程序在创建了锁之后,程序异常退出了,那么这个锁将永远不会被释放,就造成了死锁问题
      • 使用set命令来设置分布式锁,并设置超时时间,而且set命令可以保证原子性:set lock true ex 30 nx

你可能感兴趣的:(#,java基础,redis,面试,数据库)