跳至主要內容

Redis面试题

xw大约 7 分钟面试题面试题大全

BigKey、HotKey问题如何预防和解决

会导致的问题:会使服务的性能下降 ,还会影响用户正常使用功能,甚至会造成大范围的服务故障,发生系统雪崩。

在Redis中,一个字符串类型最大可以到512MB,一个二级数据结构(比如hash、list、set、Zset等)可以存储大约40亿个(2^32-1)个元素,但实际上不会达到这么大的值,一般情况下如果达到下面的情况,就可以认为它是Bigkey了。

  • 单个string类型的value值超过1MB,就可以认为是Bigkey。
  • 哈希、列表、集合、有序集合等,它们的元素个数超过2000个,就可以认为是Bigkey。

HotKey: 一个key对应在一个redis分片中,当短时间内大量的请求打到该分片上,key被频繁访问,该key就是热key。

bigKey的问题:

  1. 数据请求大量超时,redis读取数据是单线程的,当一个key数据响应的久一点,就会造成后续请求频繁超时。
  2. 侵占带宽,当一个key所占空间过大,多次请求就会占用比较大的带宽,直接影响服务的正常运行。
  3. 内存溢出活处理阻塞:当一个较大的key存在时,持续新增,key所占内存会越来越大,严重时会导致内存数据溢出;当key过
    期需要删除时,由于数据量过大,可能发生主库较响应时间过长,主从数据同步异常(删除掉的数据,从库还在使用)。
  4. 迁移困难:对key进行迁移时,是通过 migrate 命令来完成的,migrate 实际上是通过 dump + restore + del 三个命令组合成原子命令完成,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生才 会释放:迁移成功,迁移失败,等待超时

hotkey的问题:

  1. 分片服务瘫痪:redis集群会分很多个分片,每个分片有其要处理的数据范围。当某一个分片被频繁请求,该分片服务就 可能会瘫痪。
  2. redis分布式集群优势弱化:请求不够均衡,过于单点,那么redis分布式集群的优势也必然被弱化
  3. 可能造成资产损失
  4. 引发缓存击穿:当缓存请求不到,就会去请求数据库。如果请求过于集中,redis承载不了,就会有大量请 求打到数据库。此时,可能引发数据库服务瘫痪。进而引发系统雪崩
  5. cpu占用高,影响其他服务:单个分片cpu占用率过高,其他分片无法拥有cpu资源,从而被影响

如何发现bigkeys和hotkeys

  1. 使用自带命令

    ##查看bigkey
    redis-cli -a 登录密码 --bigkeys
    ##查看hotkey
    redis-cli -a 登录密码 --hotkeys
    

    image-20240304142704005

  2. scan扫描+长度命令

  3. redis-rdb-tools开源工具

    GitHub地址:https://github.com/sripathikrishnan/redis-rdb-toolsopen in new window

解决方案

bigkey:

  • 对bigkey进行拆分
  • 对bigkey进行清理,使用unlink命令进行删除
  • 定期清理失效数据

hotkey:

  • 增加redis集群副本数量,将hotkey尽量分散到不同节点,但是存在极端情况下hotkey还是分布在同一个节点上。

  • 使用二级缓存(本地缓存)

    使用本地缓存需要注意两个问题:

    • 如果对热 Key 进行本地缓存,需要防止本地缓存过大,影响系统性能;
    • 需要处理本地缓存和 Redis 集群数据的一致性问题。
  • 热key备份,将热key备份并分布到不同节点,但是要注意备份的一致性问题。通过一个大于等于 1 小于 M 的随机数,得到一个 bakHotKey,程序会优先访问 bakHotKey,在得不到数据的情况下,再访问原来的 hotkey,并将 hotkey 的内容写回 bakHotKey。值得注意的是,bakHotKey 的过期时间是 hotkey 的过期时间加上一个较小的随机正整数,这是通过坡度过期的方式,保证在 hotkey 过期时,所有 bakHotKey 不会同时过期而造成缓存雪崩。

亿级用户日活统计有几种方案

  1. 利用 bitmap 实现
  2. 利用 HyperLogLog 实现

hyperloglog只会根据元素来计算基数,不会存储元素本身,所以不能像其它类型一样返回各个元素 hyperloglog是概率算法,是牺牲准确率换区空间的, 对于对精度要求不高的情况下可以使用,因为概率算法本身不直接存储数据本身,能保证误差在一定范 围内,又不占用空间,误差在0.81%左右

在 Redis 中实现的 HyperLogLog,只需要12K内存就能统计2^64 个数据。不过有得必有失,HyperLogLog计数存在一定的误差,误差率整体较低。标准误差为 0.81% ,不到1%。当然,误差可以被设置辅助计算因子进行降低。

HLL算法的优点在于它具有极低的内存消耗和高效的计算速度,并且可以处理极大的数据集。

HyperLogLog与bitmap对比

1、bitmap 优势是:非常均衡的特性,精准统计,可以得到每个统计对象的状态,秒出。 缺点是:当你的统计对象数量十分十分巨大时,可能会占用到一点存储空间,但也可在接受范围内。也可以通过分片,或者压缩的额外手段去解决。

注意:bitmap是精确的

2、HyperLogLog 优势是: 可以统计夸张到无法想象的数量,并且占用小的夸张的内存。 缺点是: 建立在牺牲准确率的基础上,而且无法得到每个统计对象的状态。

生产环境上Redis设置的内存是多少,如何修改redis内存?

如果不设置内存大小,在64位操作系统下不限制内存大小,在32位操作系统下最多使用3G。使用info memory查看内存使用情况。

> info memory
  • used_memory:由 Redis 分配器分配的内存总量,包含了redis进程内部的开销和数据占用的内存,以字节(byte)为单位
  • used_memory_human:已更直观的单位展示分配的内存总量。
  • used_memory_rss:向操作系统申请的内存大小。与 top 、 ps等命令的输出一致。
  • used_memory_rss_human:已更直观的单位展示向操作系统申请的内存大小。
  • used_memory_peak:redis的内存消耗峰值(以字节为单位)
  • used_memory_peak_human:以更直观的格式返回redis的内存消耗峰值
  • used_memory_peak_perc:使用内存达到峰值内存的百分比,即(used_memory/used_memory_peak) *100%
  • used_memory_overhead:Redis为了维护数据集的内部机制所需的内存开销,包括所有客户端输出缓冲区、查询缓冲区、AOF重写缓冲区和主从复制的backlog。
  • used_memory_startup:Redis服务器启动时消耗的内存
  • used_memory_dataset:数据占用的内存大小,即used_memory-sed_memory_overhead
  • used_memory_dataset_perc:数据占用的内存大小的百分比,100%*(used_memory_dataset/(used_memory-used_memory_startup))
  • total_system_memory:整个系统内存
  • total_system_memory_human:以更直观的格式显示整个系统内存
  • used_memory_lua:Lua脚本存储占用的内存
  • used_memory_lua_human:以更直观的格式显示Lua脚本存储占用的内存
  • maxmemory:Redis实例的最大内存配置
  • maxmemory_human:以更直观的格式显示Redis实例的最大内存配置
  • maxmemory_policy:当达到maxmemory时的淘汰策略
  • mem_fragmentation_ratio:碎片率,used_memory_rss/ used_memory
  • mem_allocator:内存分配器
  • active_defrag_running:表示没有活动的defrag任务正在运行,1表示有活动的defrag任务正在运行(defrag:表示内存碎片整理)
  • lazyfree_pending_objects:0表示不存在延迟释放的挂起对象

可以通过修改配置文件和命令两种方式修改内存。

配置文件修改:

image-20231213111905456

命令修改:

> config set maxmemory 104857600
"OK"

> config get maxmemory
1) "maxmemory"
2) "104857600"

注意

一般推荐Redis设置内存为最大物理内存的四分之三,也就是0.75

Redis内存淘汰策略

内存淘汰策略:

  • noeviction: 不会驱逐任何key(6.x默认是这个)
  • allkeys-lru: 对所有key使用LRU算法进行删除
  • volatile-lru: 对所有设置了过期时间的key使用LRU算法进行删除
  • allkeys-random: 对所有key随机删除
  • volatile-random: 对所有设置了过期时间的key随机删除
  • volatile-ttl: 删除马上要过期的key
  • allkeys-lfu: 对所有key使用LFU算法进行删除
  • volatile-lfu: 对所有设置了过期时间的key使用LFU算法进行删除

一般使用 allkeys-lru。