redis常见面试题(2024)
redis为什么快?
纯内存访问。高性能键值对存储方式。
采用epoll作为IO多路复用实现。
redis命令的处理(工作线程)是单线程,避免上下文切换。
渐进式rehash(存在2张hash表,表扩容的时候慢慢的把hash下面的key挪到新的表),缓存时间戳(不用每次都去调用系统函数)。
redis数据类型有哪些?
string
hash
set
zset----排行
list
bitmap---C端用户签到活动
GEO---自动寻仓的时候查找收货地址附近仓库
hyperloglog---基数去重,使用场景如统计网站UV,有0.81%的误差
bitfield
stream---redis自带消息队列实现,支持广播、消费者、AKC等,原理跟主流消息队列差不多
redis事务原理?
是弱事务,只能检测语法错误不能检测运行时错误,应为执行mutli命令的时候,redis会把命令加入队列缓存起来等到执行exec命令的时候才会去真正执行,在执行期有命令出错了不会回滚,会继续往下执行。
watch监控数据是否被修复,使用乐观锁cas(check and set)
redis管道pipeline(适合大批量数据插入)
pipeline是一种批处理技术,用于提升大批量命令执行性能,减少服务器往返时间
pipeline执行过程中不会阻塞队列所以跟redis事务multi还是有区别的,不具备原子性
redis自带mset批处理命令也具备原子性,但是跟pipeline不一样的是只能执行一种命令
redis发布与订阅(pub/sub)
客户端订阅频道的时候,redis会以链表的形式保存客户端与频道的订阅关系,当生产者向某频道发送消息的时候,redis会去遍历链表向所有订阅了该频道的客户端发送消息。(观察者模式)
redis主从复制
在从机配置指向主机(密码也需要配置)
主机会维护从机复制偏移量offset,首次复制会生成一个快照RDB文件传给从机,然后从机加载到内存,后续同步通过blog日志增量同步
主机通过心跳机制检查从机状态(10s一次)
缺点:1、从机过多的时候主机同步压力大,数据有延迟 2、master挂了后,需要重新手动重启或者指定
redis哨兵模式
哨兵模式故障转移过程:哨兵监控master节点、slave节点,如果发现master节点挂了首先会标志为主观下线,然后进行投票(可以设置下线票数一半是超过一半),达到投票数后标志为客观下线,开始故障转移。
故障转移:首先哨兵会根据raft算法(简单理解就是A去询问B节点我做leader行不行)选出leader,然后有leader对健康的slave节点选举(选举流程:比对权限-->比对同步偏移量-->比对),选举出master几点后,leader发送slave of no ....等命令。后续旧主节点重新上线后会作为新的主节点的从节点运行。(哨兵会持久化节点关系的命令)
redis集群模式cluster
redis集群方案有:节点取模,一致性哈希(数据不均衡)
支持多主多从,官方建议不超过1000节点。cluster集群有16384个槽点,采用CRC16算法进行hash计算与16384取余决定数据落到哪个节点。主节点挂了后,从节点自动升级为主节点。
当集群扩容缩容节点数据迁移的时候,请求进来如果找不到数据会发送ask命令重定向。
redis生产使用注意事项
需要禁止flushall、flushdb、key*等命令,在配置文件加上rename-command key ""
使用SCAN cursor [MATCH pattern] [COUNT count] 命令遍历moreKey
Bigkey有什么危害,如何排查跟处理?
定义:String值超过10k、hash/set/list/zset值超过5000个定义为bigkey
危害:造成集群数据分配不均匀,读写性能差,会造成网络阻塞、删除比较耗时会阻塞工作线程
怎么查询bigkey:使用 --bigkey、scan
如何处理:业务分拆大key、使用unlink删除,开启 lazy-free(惰性删除/延迟释放)让程序异步删除过期的大key
redis与数据库双写一致性
先更新缓存再更新数据库---并发的时候可能会出现A线程后于B线程更新数据库,造成数据不一致,还有就是数据库更新失败
先更新数据库再更新缓存---并发的时候可能出现A线程后于B线程去更新缓存,造成数据不一致,还有就是更新缓存失败
先删除缓存再更新数据库---缓存删除后如果在更新数据库期间有新的线程执行了查询操作,也会造成数不一致,可以采用延迟双删策略(但是策略时间不好判定)
先更新数据库再删除缓存---并发的时候A线程还没来得及删除缓存,B线程读取了旧值,使用异步线程或者MQ对缓存删除失败重试
阿里巴巴canal开源组件---canal可以模拟mysql主从复制从节点同步协议获取数据库增量blog日志(二进制),程序获取数据执行redis操作保持数据一致
redis高级篇-hyperloglog
hyperloglog大小为12kb,是一种基础统计数据结果,误差为0.81%。
使用场景有统计UV(独立访客量),DAV(用户访问量),MAU
redis高级篇-GEO
GEO底层是zset结果,把坐标系通过dabase32转成字符串,非常方便的对信息做排序,可以很方便的实现计算两个坐标的距离、查找附近酒店等功能。
GEO要将不同地理位置数据根据业务逻辑分散到不同的key中,防止大key产生。
redis高级篇-bitmap
bitmap是一个二进制字符串,可以高效的表示布尔值。
常见的使用场景用户签到、用户是否登录等。
redis布隆过滤器
实现原理:在redis定义一个足够长得bitmap数组,然后通过程序对数据得key多次进行hash计算然后取模获得数组下标值,如果该下标数组值为1则判断存在(开源谷歌guava)
优点:8个比特位1个字节,使用很小得空间就可以做大量数据判断
缺点:判断存在当实际不一定存在,判断不存在就一定不存在,有误差
使用场景:过滤黑名单、垃圾邮件等
redis过期机制及内存淘汰策略?
过期机制-定时清理:设置了过期时间的key会被存放到特定的字典,然后redis定期扫描,采用的是贪心策略比如每次取其中的20个,如果里面有超过1/4过期了,就再执行一次;惰性删除:查询到key的时候去判断是否过期,如果过期了就删除不返回。
内存淘汰策略-淘汰设置了过期时间的使用最少的key(key存了使用时间戳,根据时间戳新老判断而不是使用次数)、淘汰设置了过期时间的最快到期的key、随机淘汰设置了过期时间的key、淘汰使用最少的key、随机淘汰key。
lru,最少最近使用(最近使用时间减去当前时间越长删除优先级最高)
lfu,最近使用频率最小
什么是缓存穿透,如何避免?
缓存穿透-频繁的查询一个redis及数据库不存在的key(伪key)。
如何避免-数据库差不多时,在redis把这个key缓存为null;利用布隆过滤器,把数据库的key缓存到布隆过滤器,如果不存在直接拦截返回(特性:不存在的一定不存在,存在的不一定存在,如果hash碰撞过多可以考虑增大数组或者多次hash)。
什么是缓存击穿,如何避免?
缓存击穿-热点key失效。在高并发场景下大量请求落到数据库上。
如何避免-redis集群部署避免单机故障,设置过期时间的时候增加随机数避免大量的key在同一时间过期
什么是缓存击穿、雪崩,如何避免?
缓存雪崩-缓存被穿透、击穿使大量的请求落到数据库,造成缓慢或者宕机。
如何避免-避免缓存被穿透、击穿,双检机制。
使用redis如何设计分布式锁?
使用setnx命令达到互斥效果,表示某个key存在的时候不允许操作。假如客户端宕机了释放锁失败了会存在死锁问题,解决这个问题可以给锁加一个过期时间,但是这个过期时间不好设置因为不排除客户端方法执行时间比过期时间长,所以可以把key的value设置成不一样的值或者引入了守护线程的概念(看门狗),定期查询客户端状态给锁续期。
redlock,红锁原理就是在多个主机实例中获取锁,如果超过1/2实例获取成功就代表加锁成功。获取锁之前会先获取当前时间,获取锁成功后会用成功时间-传入时间来判断是不是获取成功。
redis分布式锁在生产环境主要用redission实现,redission加锁、删除锁都使用lua脚本保证事务一致性,自带看门狗线程给锁续期。(默认10秒扫描一次锁,如果锁得剩余时间小于1/3,则续约30秒)
什么是bigkey?会有什么影响?
bigkey指的是key对应的value大而不是key本身,一般string类型大于10k。
主要影响有:集群的时候可能会出现内存分配不均匀(根据key去分摊有的大有的小),由于bigkey处理速度比较慢redis又是单线程所以会出现超时阻塞,bigkey网络流量比较大会出现网络拥塞。
redis数据持久化有哪些?
AOF-持久化redis操作日志,基本不会丢失数据但是性能比较差而且恢复数据时间比较长。
RDB-根据策略生成数据库快照,性能比较好但是会丢失数据。
RDB-AOF混合持久化-设置aof-use-rdb-preamble为yes,redis会同时生成数据快照跟AOF文件,AOF文件里面包含了RDB快照及后续操作命令,数据恢复速度会比较快及文件比较小。