• 【面试高高手】—— Redis


    1.Redis的数据类型有哪些?

    • string(字符串):基本类型,与Memcached的类型相同,一个key对应一个value,且它是二进制安全的,可以包含任何数据,如jpg图片或序列化的对象。String类型的值最大能存储512MB。
    • hash(哈希):哈希是一个键值(key=>value)对集合,它特别适合用于存储对象。
    • list(列表):列表是简单的字符串列表,按照插入顺序排序。
    • set(集合):Set是string类型的无序集合。
    • zset(sorted set:有序集合):与Set相似,但每个元素都会关联一个分数,根据这个分数进行排序。

    2.使用Redis设计一个排行榜,你会如何设计,使用什么数据结构

    设计一个排行榜通常需要使用有序集合(Sorted Set)数据结构,而Redis中的有序集合(Sorted Set)正是用来处理这种场景的理想选择。以下是如何设计一个排行榜的一般步骤:

    • 创建有序集合: 在Redis中,可以使用ZADD命令创建一个有序集合,每个成员都有一个分数,表示该成员的排名。初始时,排行榜是空的。

    • 添加成员: 使用ZADD命令将用户及其分数添加到有序集合中。分数可以根据用户的某种指标,如分数、积分、得分等来设置。

    • 查询排名: 使用ZREVRANK命令或ZRANK命令可以查询指定成员在排行榜中的排名。排名通常从0开始,表示第一名。

    • 查询分数: 使用ZSCORE命令可以查询指定成员的分数,这个分数可以用来表示该成员的排名依据。

    • 获取排行榜: 使用ZRANGE或ZREVRANGE命令可以获取排行榜中的前N名或后N名成员,这可以用来展示排行榜的内容。

    • 更新成员分数: 使用ZINCRBY命令可以增加或减少指定成员的分数,用来更新成员在排行榜中的排名。

    • 移除成员: 使用ZREM命令可以从排行榜中移除指定的成员。

    • 设置过期时间: 可以使用EXPIRE命令来设置排行榜的过期时间,以便在一段时间后自动清除排行榜数据。

    # 创建排行榜
    ZADD leaderboard 1000 "UserA"
    ZADD leaderboard 950 "UserB"
    ZADD leaderboard 1100 "UserC"
    
    # 查询排名
    ZRANK leaderboard "UserA"  # 返回0,表示UserA排在第一名
    # 查询分数
    ZSCORE leaderboard "UserB"  # 返回950
    # 获取前N名
    ZREVRANGE leaderboard 0 2 WITHSCORES  # 返回前3名成员及其分数
    # 更新成员分数
    ZINCRBY leaderboard 50 "UserA"  # 将UserA的分数增加50
    # 移除成员
    ZREM leaderboard "UserB"  # 从排行榜中移除UserB
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.如何确定热点数据?

    使用淘汰策略:Redis 支持几种不同的淘汰策略,如 LRU (Least Recently Used) 或 LFU (Least Frequently Used)。这些策略可以自动删除最不常用的数据,以确保内存中始终保存最热的数据。
    设置过期时间:对于每个存储在 Redis 中的值,都可以设置一个过期时间。过期时间到达后,Redis 会自动删除该值。这种机制可以确保 Redis 中的数据始终是最新和最热的。
    优化查询:对于频繁执行的查询,可以通过使用 Redis 的查询缓存功能来提高效率。这个功能可以将查询结果缓存起来,这样在相同查询再次执行时,就可以直接从缓存中获取结果,而不需要重新执行查询。

    4.Redis的持久化策略有哪些?

    • RDB:RDB是在某个时间点将内存中的所有数据快照保存到硬盘上,在数据恢复时,可以恢复备份时间以前的所有数据,但无法恢复备份时间点后面的数据
      • 性能好启动速度更快 。
      • 会导致部分数据缺失。
    • AOF: AOF持久化方式则会记录每一个服务器收到的写操作。在服务启动时,这些记录的操作会逐条执行从而重建出原有的数据。写操作指令记录的格式跟redis协议
      • 基本可实现数据无丢失。
      • 速度较慢。

    一般在生产上的话,在Redis重启后,两个一起用的,因为两种持久化方式优缺点会互补,在应急情况下先使用RDB将大量数据读取出来,在使用AOF将数据补全。

    5.如何使用Redis实现分布式锁?

    使用setnx。
    setnx(“key“,”value“)的作用是当且仅当,在redis中key的值是不存在的时候,setnx(“key“,”value“)的操作会返回true,如果key语句存在,那么始终是返回false。根据setnx这样的特性, 我们可以使用setnx实现一个分布式锁,但多个线程进来的时候,当其中一个线程执行上述的第5行代码(上锁操作),其他线程在第一个线程没有执行完毕后,都是处于自旋的状态(拿不到锁),只有第一个线程执行完毕释放锁后(第17代码),其他的线程才有可能拿到。setIfAbsend是setnx的客户端用法。

    6.Redis的数据淘汰策略有哪些呢?

    (1)volatile-lru:在内存不足时,根据 LRU 算法删除设置了过期时间的键。
    (2)allkeys-lru:从所有key的哈希表(server.db[i].dict)中随机挑选多个key,然后再选到的key中利用LRU算法淘汰最近最少使用的数据。
    (3)volatile-random:在内存不足时,随机删除设置了过期时间的键。
    (4)allkeys-random:从所有key的哈希表中随机挑选多个key淘汰掉。
    (5)volatile-ttl:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中选择过期时间最小的数据淘汰掉。
    (6)no-enviction(驱逐):禁止驱逐数据。

    7.Redis为什么这么快?

    (1)redis是基于内存的,内存的读写速度非常快
    (2)redis是单线程的,省去了很多上下文切换线程的时间
    (3)redis使用多路复用技术,可以处理并发的连接,非阻塞IO内部实现epoll,使用了单线程来轮询描述符,将数据库的开、关、读、写都转换成了事件,减少了线程切换时上下文的切换和竞争。

    8.Redis单线程优势?

    • 优势:
      (1)代码更清晰,处理逻辑更简单
      (2)不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
      (3)不存在多进程或者多线程导致的切换而消耗CPU
    • 劣势:
      (1)无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善。

    9.Redis支持事务吗?

    支持
    (1)DISCARD 取消事务,放弃执行事务块内的所有命令
    (2)EXEC 执行所有事务块内的命令
    (3)MULTI 标记一个事务块的开始
    (4)UNWATCH 取消 WATCH 命令对所有 key 的监视
    (5)WATCH key [key…] 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命
    令所改动,那么事务将被打断

    10.redis和memcache区别

    (1)memcache把数据都放到了内存中,当服务宕机或者是断点时,数据会丢失,而且memcache存储的数据不能超过内存大小。redis支持数据持久化。
    (2)memcache支持的都是简单的字符串,redis有更为丰富的数据类型,提供了String、Hash、set、zeset、list五中数据类型
    (3)使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
    (4)value值大小不同,redis最大考验达到512m,而memcache只有1mb
    (5)redis的速度比memcache快很多
    (6)redis支持master-slave模式的数据备份。

    11.Redis如何保证数据一致

      1.使用MySQL的binlog向Redis推送增量数据
    
    • 1

    异步更新缓存(基于订阅binlog的同步机制),步骤如下:
    (1)当MySQL变更数据时,binlog中会存在更新的增量数据。
    (2)将这些增量数据推送给Redis
    (3)Redis根据binlong的记录,对缓存进行更新。
    这里消息的推送可以使用MQ来进行实现。
    2.延时双删
    步骤如下:
    (1)先删除缓存
    (2)再写数据库
    (3)休眠一段时间
    (4)再次删除缓存
    那么,这个500毫秒怎么确定的,具体该休眠多久呢?需要评估自己的项目的读数据业务逻辑的耗时。这么做的目的,就是确保读请求结束,写请求可以删除读请求造成的缓存脏数据。当然这种策略还要考虑redis和数据库主从同步的耗时。最后的的写数据的休眠时间:则在读数据业务逻辑的耗时基础上,加几百ms即可。比如:休眠1秒。
    这样做的弊端是:最差的情况是在休眠时间,用户读到的数据和DB不一致,增加了请求的耗时。

    12.什么是Redis的缓存雪崩?

    解释一:缓存雪崩,是指在某一时间段,缓存集中失效。 比如:在写文本的时候,马上就要到双十二零点了,产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。
    解释二:其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,那么那个时候数据库能顶住压力,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
    解决方案:
    (1)redis高可用
    我们设置多台redis,最好三主三从,这样一台宕机后,其它的还能正常工作,其实就是搭建集群
    (2)限流降级
    在缓存失效后,通过加锁或者队列来控制的°数据库的写缓存的数量。比如对某个key只允许一个线程查询数据和写缓存,其它线程等待。
    (3)数据预热
    数据预热就是在项目正式部署前,我们先把可能的数据提前访问一遍,这样部分大量访问的数据就会被加载到缓存中。在即将发生高并发前手动触发加载缓存中的不同的key,设置不同的失效时间,缓存失效的时间点尽量匀称。
    (4)分散Key的失效时间
    尽量让key的失效时间分散一些,设置不同的过期事件
    (5)做二级缓存
    A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期。

    13.什么是Redis的缓存击穿?

    redis缓存穿透就是,在客户端查询数据的时候,缓存中没有,缓存命中率为0,于是去持久层数据库中去查询,结果发现也没有。当用户很多时,因为缓存中没有都去了数据库中查询,导致数据库压力过大,这时候就出现了缓存穿透的问题。
    解决方案:
    (1)布隆过滤器
    布隆过滤器的工作原理是,现规定好,redis缓存中可能存入的数据(比如:商品信息,就规定商品信息可能被存入;身份证号码,就规定身份证号码可能会存入;如果两者都有可能,就两者都规定)规定完毕后, 寻找这些数据所对应的哈希值的所有可能(比如:面包m,所有的排列的可能性都列出来,就是:面包m、面m包、包面m等等…),把列出来的所有可能性的数据全部转化为哈希值, 再把这些所有可能出现的哈希值(非常大),存入一个很大的bitmap中,订单有一个不可能的查询数据过来的时候,bitmap会直接拦截,不会让他们去查询缓存。可以有效的避免redis缓存穿透。
    (2)设置缓存空对象
    当缓存不命中后,即使返回空的对象也将其缓存起来,同时会设置一个过期时间,之后在访问这个数据将会从缓存中获取,而不会再去访问持久层的数据库了。

  • 相关阅读:
    Mpeg-Niacin 甲氧基-聚乙二醇-烟酸,Mpeg-NOTA甲氧基聚乙二醇-NOTA
    ssm基于web图书租售管理系统的设计与实现毕业设计源码161609
    视觉系统设计实例(halcon-winform)-10.PLC通讯
    FLASH存储器又称闪存,主要有两种:NorFlash和NandFlash、linux系统flash分区注意事项及制作脚本
    Windows11 环境安装Gradle
    考虑可再生能源消纳的建筑综合能源系统日前经济调度模型(Matlab代码实现)
    在vscode如何利用快捷键选择一样的单词
    任正非:天空足够大,世界会越来越兴盛
    Qt事件传播机制 day8
    非关系型数据库NoSQL
  • 原文地址:https://blog.csdn.net/qq_42785250/article/details/133032091