Redis面试(三)

1.Redis报内存不足怎么处理

Redis内存不足的集中处理方式:

  • 修改配置文件redis.cof的maxmemory参数,增加Redis的可用内存
  • 通过命令修改set maxmemory动态设置内存上限
  • 修改内存淘汰策略,及时释放内存
  • 使用Redis集群,及时进行扩容

2.Redis的过期回收策略

  • 惰性删除: 惰性删除是指当我们查询key的时候才对key进行检测,如果已经达到过期时间,则删除,显然有一个缺点就是如果过期的key没有被访问,那么就会一直不被删除,而一直占用内存。
  • 定期删除:定期删除是指Redis每隔一段时间对数据库做一次检查,删除里面的过期key,由于不可能做轮询key,所以Redis是每次随机抽取一下key做检查

3.Redis有哪些内存溢出控制策略

内存达到maxmemory上限时候会触发响应的控制策略,Redis支持6种策略

  • noeviction: 默认策略,不会删除任何数据,拒绝写入任何数据并且返回错误信息,此时Redis只响应读操作
  • volatile-lru:根据lru算法设置了超时属性的值,知道腾出足够的空间为止,如果没有可删除的健对象,回退到noeviction策略。
  • allkeys-lru:根据LRU算法删除健,不管数据有没有设置超时属性,直到特腾出足够空间为止
  • allkeys-random:随机删除所有的健,直到腾出空间为止。
  • volatile-random:随机删除过期的健,直到腾出足够的空间
  • volatile-ttl:根据键值属性,删除最近将要过期的数据,如果没有回退到noeviction策略。

4.Redis阻塞?怎么解决

Redis面试(三)_第1张图片

  • API或者数据结构不合理
    通常Redis执行命令速度非常快,但是不合理的使用命令,可能会导致执行速度变慢,导致阻塞,特别在高并发的时候,应该尽量避免在大对象执行算法复杂度超过O(n)的。
    对慢查询的处理分为两步
    1.使用查询show log get{n}命令可以获取最近的n条慢查询命令
    2.发现慢查询后可从以下两个方向优化
    - 修改为低算法的复杂度的命令,如hgetall改为hmget等,禁用keys,sort命令等
    - 调整大对象:缩短大对象数据或者把大对象进行拆分为多个小对象,防止一次命令操作过多的数据。

  • CPU饱和问题
    单线程的Redis处理命令时候只使用一个CPU,CPU饱和是指Redis单核CPU使用率接近100%。
    处理步骤如下:
    1.判断当前Redis并发量是否已经到达极限
    2.如果当前并发QPs是已经几万+,那么可能已经到极限,可能需要做集群的水平化扩容来分担压力。
    3.如果QPS只有几十,几百那么可能就要排查命令和内存的使用。

  • 持久化相关的阻塞
    对于开起了持久化功能的Redis节点,需要排查是否是持久化导致的阻塞。
    1.fork阻塞:fork发生在RDB和AOF重写的时,Redis主线程调用fork操作产生共享,由子进程完成持久化文件重写工作,如果fork操作本身耗时长,必然会导致主线程的阻塞。
    2.AOF刷盘阻塞:当我们开启AoF持久化的时候,文件的刷盘方式一般采用每秒一次,后台线程每秒对AOF文件做fsync操作,当硬盘压力过大,fsync需要等待直到写入完成,如果主线程发现距离上一次的fsync成功超过两秒,为了安全性它会阻塞直到后台线程完成fsync操作。
    3.Hugepage写操作阻塞:对于开启Transparent HugePages的 操作系统,每次写命令引起的复制内存页单位由4K变为2MB,放大了512 倍,会拖慢写操作的执行时间,导致大量写操作慢查询

5.大key问题

大key情况:

  • 单个key存储的value很大,超过10KB
  • hash,set,zset,list储存过多的元素(以万为单位)

大key会造成什么情况

  • 客户端耗时增加,甚至超时
  • 对大key进行IO操作时,会严重占用带宽和CPU造成Redis集群中数据倾斜。
  • 主动删除,被动删除可能会造成阻塞。

如何找到大key

  • bigkeys命令:使用bigkeys命令以遍历的方式分析Redis实例中的所有key,并返回整体统计信息并返回每个数据类型中Top1的大key
  • redis-db-tools::redis-rdb-tools是由Python写的用来分析Redis的rdb快照文件用的工具,它可以把rdb快照文件生
    成json文件或者生成报表用来分析Redis的使用详情

如何处理大key
Redis面试(三)_第2张图片
删除大key

  • 当Redis版本大于4.0时,可使用UNLINK命令安全地删除大Key,该命令能够以非阻塞的方式,逐步地清理
    传入的Key。
  • 当Redis版本小于4.0时,避免使用阻塞式命令KEYS,而是建议通过SCAN命令执行增量迭代扫描key,然后判
    断进行删除。
    压缩和拆分key
  • 当vaule是string时,比较难拆分,则使用序列化、压缩算法将key的大小控制在合理范围内,但是序列化和
    反序列化都会带来更多时间上的消耗。
  • 当value是string,压缩之后仍然是大key,则需要进行拆分,一个大key分为不同的部分,记录每个部分的
    key,使用multiget等操作实现事务读取。
  • 当value是list/set等集合类型时,根据预估的数据规模来进行分片,不同的元素计算后分到不同的片。

6.使用Redis如何实现异步队列

  • 使用list作为消息队列,lpush生产消息,rpop消费消息
    这种方式,消费者死循环rpop从队列中消费消息,即使队列里面没有消息,也会进行rpop,导致redis的CPU消耗;可以通过让消费者休眠的方式来处理,但是这样又会有消息延迟的问题。
    Redis面试(三)_第3张图片
  • 使用list作为消息队列,lpush生产消息,brpop进行消费消息
    brpop是rpop的阻塞版本,list为空的时候,他会一直阻塞,直到list中有消息或者超时,但这种方式只能进行一对一的消息队列。
    Redis面试(三)_第4张图片
  • 使用Redis的pub/sub来进行消息的发布/订阅
    发布/订阅模式可以1:N的消息发布/订阅,发布者将消息发布到指定的频道,订阅响应频道的客户端都能收到消息。
    Redis面试(三)_第5张图片
    但是这种消息是不可靠的,不保证订阅者一定能收到消息,也不进行消息的存储,所以一般的异步消息队列还是交给专业的消息队列。

7.Redis支持事务吗

Redis提供了简单的事务,但是它对事务ACID的支持并不完备。
multi命令表示事务的开始,exec命令表示事务结束。Redis事务的原理,是所有的指令在 exec 之前不执行,而是缓存在
服务器的一个事务队列中,服务器一旦收到 exec 指令,才开执行整个事务队列,执行完毕后一次性返回所有指令的运
行结果
Redis事务为什么不支持回滚
Redis的事务不支持回滚
如果执行的命令有语法错误,Redis 会执行失败,这些问题可以从程序层面捕获并解决。但是如果出现其他问题,则
依然会继续执行余下的命令。
这样做的原因是因为回滚需要增加很多工作,而不支持回滚则可以保持简单、快速的特性。

8.Redis实现分布式了解吗

Redis是分布式锁本质上要实现的目标就是在 Redis 里面占一个“茅坑”,当别的进程也要来占时,发现已经有人蹲
在那里了,就只好放弃或者稍后再试。

  • V1:setnx命令
    占坑一般使用的是setnx(set if not exists)指令,只允许被一个客户端占,用完了在调用对del指令释放。
    但是有个问题如果逻辑执行到中间出现了异常,可能会导致del指令没有被调用,陷入了死锁。

  • V2锁超时释放
    所以在拿到锁之后,再给锁加上一个过期时间,比如5秒,这样即使服务中间出现异常也可以保证5秒之后锁会自动释放。

  • V3:set指令
    这个问题在Redis 2.8版本中得到了解决,这个版本加入了set 指令的扩展参数,使得 setnx和expire指令可以一起执

9.假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如何将它们全部找出来

使用 keys 指令可以扫出指定模式的 key 列表。但是要注意 keys 指令会导致线程阻塞一段时间,线上服务会停
顿,直到指令执行完毕,服务才能恢复。这个时候可以使用 scan 指令, scan 指令可以无阻塞的提取出指定模式
的 key 列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用指
keys 令长。

你可能感兴趣的:(面试,java知识,redis,面试,数据库)