网站建设投标,学校网站源码 带wap手机端,湛江建设企业网站,北京市轨道交通建设管理有限公司网站一、Redis面试题集锦
1.1、Redis到底是单线程还是多线程 Redis6.0版本之前的单线程指的是其网络IO和键值对读写是由一个线程完成的#xff1b; Redis6.0引入的多线程指的是网络请求过程采用了多线程#xff0c;而键值对读写命令仍然是单线程的#xff0c;所以多线程环境下 Redis6.0引入的多线程指的是网络请求过程采用了多线程而键值对读写命令仍然是单线程的所以多线程环境下redis依然是并发安全的也即只有网络请求模块和数组操作模块是单线程的而其他的持久化、集群数据同步等其实是由额外的线程执行的 1.2、Redis单线程为什么还能这么快 1命令执行基于内存操作一条命令在内存里操作的时间只有几十纳秒 2命令执行是单线程操作的这就省去了线程切换的开销 3基于IO多路复用机制提升了I/O的利用率 4高效的数据存储结构全局Hash表、跳表、压缩列表、链表等 1.3、Redis底层数据是如何用跳表来存储的 所谓跳表是指将有序链表改造为支持近似折半查找算法可以进行快速的插入、删除、查找操作 1.4、Redis key过期了为什么内存没释放 1原因一先设置了key的过期时间然后修改了key的值修改key的值时没有指定过期时间如下 2原因二跟redis过期key的删除策略有关 惰性删除当读/写一个已经过期的key时会触发惰性删除策略判断当前要操作的key是否过期了如果过期了则直接删除 定时删除由于惰性删除策略无法保证冷数据被及时删除所以redis会定期默认每100ms主动淘汰一批已经过期的key这里的一批只是一部分过期的key所以也会出现部分key即使过期了但是没有被及时清理掉的情况导致内存没有被实时释放 1.6、LRU vs LFU LRU 和 LFU是redis中基于key的淘汰策略中的两种不同算法。区别如下 LRU算法Least Recently Used最近最少使用淘汰很久没被访问过的数据以最近一次时间作为参考 LFU算法Least Frequently Used最不经常使用淘汰最近一段时间被访问次数最少的数据以次数作为参考绝大多数情况下我们都可以使用LRU策略当存在大量热点缓存数据时LFU可能会更好一些 1.7、删除key的指令会阻塞redis吗 分情况。如果删除的是单个字符串类型的key时间复杂度为o(1)不会阻塞redis如果删除的是单个列表、集合、有序集合或者哈希表的类型时间复杂度为o(M)M为数据结构内的元素的数量如果M的值很大的话将会导致redis阻塞 1.8、Redis主从、哨兵、集群大PK
1.8.1、主从模式 Redis主从复制架构是用来解决数据的冗余备份的主节点用来对外提供服务从节点仅仅用来同步数据。 1.8.2、哨兵模式 在redis3.0之前的版本要想实现集群一般是借助哨兵来监控master节点的状态如果master节点异常则会做主从切换将某一台slave切换为主节点哨兵的配置略微复杂并且性能和高可用性等各方面表现一般特别是在主从切换的瞬间而且哨兵模式只有一个主节点对外提供服务无法支持很高的并发且单个主节点的内存也不宜设置的过大否则会导致持久化文件过大影响数据恢复或者主从同步的效率。 1.8.3、集群模式 redis集群是一个由多个主从节点群组成的分布式服务器群具有复制、高可用和分片的特性。redis集群不需要sentinel哨兵也能完成节点移除和故障转移功能。需要将每个节点设置成集群模式这种集群模式没有中心节点可以水平扩展根据官方文档的数据可以扩展至上万个节点官方推荐不超过1000个节点redis集群的性能和高可用性均优于之前版本的哨兵模式且集群配置非常简单。 1.9、redis集群数据hash分片算法是怎么回事 redis集群将所有数据划分为16384个槽位slots每一个节点负责其中一部分槽位槽位的信息存储于每个节点中当redis集群的客户端来连接集群时它会得到一份集群的槽位配置信息并将其缓存在客户端本地这样当客户端要查找某个key时就可以根据槽位定位算法定位到目标点位。 槽位定位算法redis集群默认会对key的值使用crc16算法进行hash得到一个整数值然后用这个整数值对16384取模得到具体的槽位公式为CRC16(key) mod 16384. 接着再根据槽位值和redis节点的对应关系就可以定位到key具体落到哪个redis节点上。 1.10、Redis主从切换导致缓存雪崩可能的原因 我们假设slave机器的时钟比master快很多此时redis主节点里面设置了过期时间key站在slave的角度来看可能很多在master节点里面的数据其实已经过期了此时如果进行了主从切换把该slave节点提升为新的master节点了那么就会清理大量过期的key此时就可能会导致以下结果 1master大量清理过期的key主线程可能会发生阻塞无法及时处理客户端的请求 2系统中的缓存大量失效恰好在这一时刻涌入进来了大量的客户端请求导致缓存模块无法利用进而引起大量的请求直接打到数据库服务器上导致数据库阻塞甚至宕机。 当master节点和slave节点的机器时钟不一致时对业务的影响非常大所以我们一定要保证主从库的机器时钟一致性避免发生类似的问题。 1.11、 Redis线上数据如何备份 方式一写crontab定时调度脚本每小时都拷贝一份rdb或者aof文件到另一台机器中去保留最近48小时的备份 方式二每天都保留一份当日的数据备份到一个目录中去可以保留最近一个月的备份 方式三每次拷贝备份的时候都把太旧的备份删除了 1.12、Redis集群网络抖动导致频繁主从切换怎么处理 真实世界的机房网络往往不是风平浪静的它们经常会发生各种各样的小问题。例如网络抖动就是非常常见的一种现象突然之间部分连接变得不可访问然后很快又恢复正常。为了解决这种问题redis集群提供了一种选线 cluster-node-timeout ,表示当某个节点持续timeout的时间失联时才可以认定该节点出现故障需要进行主从切换如果没有这个选项网络抖动将会导致频繁的主从切换。 1.13、Redis集群为什么至少需要三个master节点 因为新的master节点的选举需要大于半数的集群master节点同意才能选举成功如果只有2个master节点当其中一个挂了是达不到新master节点的选举条件的。 1.14、Redis集群为什么推荐奇数个节点 因为新的master节点的选举需要大于半数的集群master节点同意才能选举成功奇数个master节点可以在满足选举的基础上节省一个节点节省节点就是节省钱3个节点和4个节点的master集群相比大家如果都挂了一个master节点的话都能选举出新的master节点如果挂了2个master节点的话就无法选举出新的节点了所以基数的节点更多的是从节省资源角度出发的。 1.15、Redis集群支持批量操作命令吗 对于类似mset、mget这样的多个key的原生批量操作指令redis集群只支持所有key落在同一slot的情况如果有多个key一定要用mset命令在redis集群上操作则可以在key的前面加上{xxx}这样参数数据分片hash计算的只会是大括号里面的值这样就能保证不同的key都能落到同一个slot里面去如下 mset {user1}:1:name zhangsan {user1}:1:age 18 假设name和age计算出的hash slot值不一样但是由于这条命令是在集群下执行的redis只会用大括号里面的user1作为hash slot计算所以计算出来的slot值肯定相同最终保证批量的数据都落在同一slot上。 1.16、Lua脚本能在Redis集群中执行吗 redis官方规定Lua脚本想在redis集群里面执行需要Luau脚本里操作的所有的key落在集群的同一个节点上这样的话我们可以给Lua脚本的key前面加上一个相同的hash tag即{xxx}这样就能保证Lua脚本里所有的key都落在相同的节点上了。 1.17、Redis的分布式锁的底层实现原理
1.1.8、Redis主从复制的核心原理
1.19、Redis和MySQL如何保证数据一致性 方案一先更新MySQL再更新redis如果redis更新失败将会导致redis中的数据和DB中的数据不一致 方案二先删除redis中的数据再更新mysql再次查询的时候在将数据添加到redis缓存中这种方案能解决方案一中出现的问题但是在高并发场景下性能较低而且仍然会出现数据不一致的问题比如线程一删除了redis缓存的数据正在更新MySQL此时线程二执行查询操作发现缓存没有于是查询数据库并将查询到的结果放进redis那么就会把MySQL中的老数据重新放回到redis中 方案三延时双删所谓延时双删指的是先删除redis中缓存的数据再更新MySQL中的数据延迟几百毫秒后再次删除redis中的数据这样就算在更新MySQL时其他线程读取了MySQL把老数据读取到了redis中那么存储进redis中的数据也会被删除掉从而保证Redis和MySQL的数据一致性 1.20、Redis的集群方案
1.21、布隆过滤器原理 优缺点
1.22、分布式系统中常用的缓存方案有哪些 1客户端缓存页面和浏览器缓存、APP缓存、H5缓存、localStorage缓存、sessionStorage缓存 2CSN缓存 内容存储数据的缓存 内容分发负载均衡 3Nginx缓存静态资源 4服务端缓存本地缓存、外部缓存 5数据库缓存持久层缓存MyBatis、Hibernate多级缓存、MySQL查询缓存 6操作系统缓存Page Cache、Buffer Cache 1.23、缓存穿透 vs 缓存击穿 vs 缓存雪崩
1.23.1、缓存穿透 概述执行的查询逻辑缓存中查询不到数据库中也查询不到。 解决方案 1业务逻辑层对参数进行合法性校验 2将数据库中没有查询到的数据也写入缓存注意事项为了防止redis被无用的key占满这一类型的key的有效期要尽可能的设置的短一点 3引入布隆过滤器在访问redis之前先判断数据是否存在注意事项使用布隆过滤器存在一定的误判率并且布隆过滤器只能加数据不能减数据 MyBatis是如何解决缓存穿透的 将数据库中没有查询到的结果也进行缓存 项目中有没有遇到 没有用到。项目中我们使用的是MyBatis框架作为持久层MyBatis已经解决了缓存穿透的问题。 1.23.2、缓存击穿 概述 执行的查询逻辑缓存中查询不到数据库中可以查询的到一般出现在数据初始化及key过期了的情况 存在的问题 写入缓存需要一定的时间如果是在高并发的场景下恰巧在数据还没有写入到redis缓存中时大量请求蜂拥而至那么一瞬间就会有大量请求访问DB给DB造成巨大的压力甚至宕机 解决方案 1设置热点key永不过期注意事项要在value中包含一个逻辑上的过期时间然后另起一个线程定期重建这些缓存 2加载DB的时候防止高并发也可以通过限流的方式来解决 1.23.3、缓存雪崩 概述 在系统运行的某一时刻突然系统中的缓存全部失效恰好在这一时刻涌来了大量的客户请求导致所有模块缓存无法利用进而引起大量请求涌向数据库查询的极端情况导致数据库阻塞或者挂起 解决方案 1缓存永久存储不推荐 2针对于不同的业务数据设置不同的超时时间 1.24、简述redis的事务实现原理 redis的事务实现主要包含如下三个步骤即事务开始、命令入队、事务执行。下面分别介绍 事务开始MULTI命令的执行标识着一个事务的开始。MULTI命令是在客户端状态的flags属性中打开REDIS_MULTI标识来完成的 命令入队当一个客户端切换到事务状态之后服务器会根据这个客户端发送过来的命令执行不同的操作。如果客户端发送的命令为MULTI、EXEC、WATCH、DISCARD指令中的任意一个那么服务器将会立即执行该命令否则将命令放入一个事务队列里面然后向客户端返回QUEUED回复详细流程如下 1如果客户端发送的命令为MULTI、EXEC、WATCH、DISCARD指令中的任意一个那么服务器将会立即执行该命令 2如果客户端发送的是上述四个命令之外的其他指令那么服务器并不立即执行这个命令 3检查命令的格式是否正确如果不正确服务端会在客户端状态的flags属性关闭REDIS_MULTI标识并返回错误信息给客户端如果正确则将这个命令放入一个事务队列里面然后返回QUEUED的响应给客户端 4事务队列是按照FIFO的方式保存入队的命令 事务执行客户端发送EXEC命令服务器执行EXEC命令逻辑 1如果客户端状态的flags属性不包含REDIS_MULTI标识、或者包含REDIS_DIRTY_CAS或者REDIS_DIRTY_EXEC标识那么将直接取消事务的执行 2服务器遍历客户端的事务队列然后执行事务队列中的所有命令最后将返回结果给客户端 注意事项 1redis不支持事务回滚机制但是它会检查每一个事务中的命令是否存在错误 2redis事务不支持检查那些程序员自己犯的错误 1.25、WATCH MULTI EXEC DISCARD UNWATCH
1.25.1、WATCH概述 WATCH指令是一个乐观锁可以为redis事务提供check-and-setCAS行为。可以监控一个或者多个键一旦其中一个键被修改或者删除之后的事务都将不会执行监控一直持续到EXEC命令。 1.25.2、MULTI概述 MULTI指令用于开启一个事务它总是返回OK。MULTI指令执行之后客户端可以继续向服务器发送任意多条命令这些命令不会立即执行而是被放到一个队列中当EXEC指令被调用时队列中的所有命令才会被立即执行 1.25.3、EXEC概述 EXEC指令用于执行队列中的所有指令返回队列中所有命令的返回值按照命令执行的先后顺序依次执行当操作被打断时返回空值nil 1.25.4、DISCARD概述 DISCARD指令用于清空事务队列中已经入队的指令并放弃事务的执行执行此命令后客户端还会从事务状态中退出 1.25.5、UNWATCH概述 UNWATCH指令用于取消watch对所有key的监控 1.26、生产上你们的redis内存设置多少 一般推荐Redis设置内存为最大物理内存的四分之三例如你的物理机的内存为32G则设置的Redis的物理内存为24G。 1.27、如何配置 修改redis的内存大小
1.27.1、查看redis的最大占用内存 配置文件查看 redis的最大占用内存是在redis.conf中配置的默认的配置信息如下 通过查看默认配置发现maxmemory被注释掉了说明其存在默认内存大小那么默认的规则又是什么呢规则如下如果不设置最大内存或者设置的最大内存大小为0那么在64位操作下不限制内存大小在32位操作系统下最多使用3G内存。 命令查看 1.27.2、修改redis的内存大小 配置文件中修改 修改maxmemory的值即可。注意事项maxmemory的单位为字节设置时注意单位的转换。 命令修改单位字节 1.28、如果内存满了你怎么办 redis的内存如果满了这时如果你还想往里边设值将会报OOM异常errorOOM command not allowed when used memory maxmemory。解决方法是调整redis的最大内存大小避免出现OOM。 1.29、redis的缓存淘汰策略你了解吗
1.29.1、概述 我们知道redis是基于内存的数据库当内存达到设定的maxmemory时将会触发redis的主动清理策略。主动清理策略在redis4.0之前一共实现了6种在4.0之后又增加了2种共计分为3类8种redis.conf中的详细配置如下 中文解释 第一类针对设置了过期时间key的处理 1volatile-ttl在筛选时会针对设置了过期时间的key根据过期时间的先后顺序进行删除越早过期的key越先被删除 2volatile-random就像它的名字一样在设置了过期时间的key随机删除 3volatile-lru使用LRU算法筛选设置了过期时间的key 4volatile-lfu使用LFU算法筛选设置了过期时间的key 第二类针对所有key的处理 1allkeys-random禁止使用对所有key随机删除 2allkeys-lru生产上建议使用对所有key使用LRU算法进行删除 3allkeys-lfu对所有key使用LFU算法进行删除 第三类不处理默认 noeviction默认,生产环境不建议用不会踢出任何数据拒绝所有写入操作并返回客户端信息OOM此时redis只响应读操作 小总结 3个维度过期键中筛选、所有键中筛选、不处理 4个方面LRU、LFU、random、ttl 8种选择 1.29.2、redis过期键的删除策略 思考如果一个键过期了那么到了过期时间它会立即从内存中被删除吗 答不会立即删除。 1.29.3、3种不同的删除策略思想 定时删除 Redis不可能时刻遍历所有被设置了生存时间的key来检测数据是否已经到达过期时间然后对它进行删除。立即删除的确能保证内存中数据的最大新鲜度因为它保证过期键会在过期后马山删除其所占用的内存也会随之释放。但是立即删除对cpu是最不友好的。因为删除操作会占用cpu的时间如果刚好碰上了cpu很忙的时候比如正在做交集或者排序等计算的时候就会给cpu造成额外的压力让cpu很累时时需要删除忙死并且还会产生大量的性能消耗同时也会影响数据的读取操作。 惰性删除 数据到达过期时间不做处理等下次访问该数据时判断该数据是否过期如果没有过期则返回如果过期了再删除返回不存在。很明显惰性删除策略对内存是最不友好的如果一个键已经过期而这个键又仍然存在redis数据库中那么只要这个过期的键没有被访问到其所占用的内存就不会被释放在使用过期策略时如果数据库中有非常多的过期键而这些键又恰巧没有被访问到的话那么它们永远也不会被删除了PS除非用户手动执行了flushdb指令我们甚至可以将这种情况看做是一种内存泄露大量无用的垃圾占用了大量的内存而服务器却不会自己去释放它们这对于运行状态非常依赖于内存的redis服务器来说肯定不是一个好消息。 定期删除策略 上边分析了定时删除和惰性删除存在的问题不管是定时删除还是惰性删除走的都是极端显然是不利于服务器发挥出最大性能。那么定期删除策略应运而生所谓定期策略可以看做是定时策略和惰性策略两者的折中。定期删除策略每隔一段时间执行一次删除过期键的操作并通过限制删除操作执行的时长和频率来减少删除操作对CPU时间的影响。 周期性轮询redis数据库中的时效性数据采用随机抽取的策略利用过期数据占比的方式控制删除频率。 特点1cpu性能占用设置有峰值检测频率可以自定义设置 特点2内存压力不是很大长期占用内存的冷数据会被持续清理 总结周期性检查存储空间随机抽查重点抽查 举例redis默认每100ms检查一次是否存在过期的key有过期key则删除。注意redis不是每隔100ms就将所有的key检查一次而是随机抽取进行检查如果redis中的缓存数据异常的庞大想要100ms就将所有的key检查一遍判断是否过期那cpu得直接干冒烟因此如果只是采用定期删除策略将会出现很多过期的key没有及时被删除的情况。 定期删除策略的难点再于如何确定删除操作的执行时长和频率如果删除操作执行的太频繁或者执行的时间太长就会退化为定时删除策略以至于将cpu的时间过多的浪费在查找过期键删除过期键上。而如果删除操作执行的频繁太少或者执行的时间太短则又会退化为惰性删除策略。因此如果采用定期删除策略的话服务器必须根据实际情况合理地设置删除操作的执行时长和执行频率。 1.29.4、如何设置redis的过期删除策略 方式一修改redis.conf的配置文件例如 方式二命令修改 1.30、Redis的LRU算法了解吗可否手写一个LRU算法
1.30.1、概述 LRU是Least Recently Used的单词缩写中文意思为最近最少使用是一种常用的页面置换算法根据此算法可以选择最近最久未使用的数据予以淘汰。 1.31、如何查看当前redis的内存使用情况
info memory