面试题答案
一键面试预防Redis大Key产生
- 数据设计优化:
- 合理拆分数据结构:例如,在电商系统中,原本可能将一个商品的所有信息(包括详细描述、图片URL列表、评论等)存储在一个Hash结构的大Key中。应将其拆分为多个小Key,如商品基本信息一个Key,评论单独一个Key(可以用商品ID作为前缀,如
product:1:info
,product:1:comments
)。这样每个Key的数据量相对较小,避免了大Key的产生。 - 控制集合元素数量:对于Set、List、ZSet等集合类型,在业务允许的情况下,限制每个集合中的元素数量。例如在一个排行榜业务中,若使用ZSet存储用户的积分排行榜,可设置每1000个用户为一组,使用不同的ZSet存储(如
rank:1 - 1000
,rank:1001 - 2000
等)。
- 合理拆分数据结构:例如,在电商系统中,原本可能将一个商品的所有信息(包括详细描述、图片URL列表、评论等)存储在一个Hash结构的大Key中。应将其拆分为多个小Key,如商品基本信息一个Key,评论单独一个Key(可以用商品ID作为前缀,如
- 业务逻辑优化:
- 避免全量操作:在一些批量处理业务中,如批量更新用户信息,如果直接将所有用户信息整合为一个大Key更新到Redis,易产生大Key。应采用分批处理的方式,每次处理一部分用户信息,逐步更新到Redis。
- 定期清理无效数据:对于一些时效性较强的数据,如限时活动的缓存数据,在活动结束后及时清理相关Key,防止这些Key不断累积数据变成大Key。
大Key出现后的治理(不影响线上业务)
- 数据迁移:
- 异步迁移:使用Redis的
SCAN
命令(对于Hash类型使用HSCAN
,List类型使用LRANGE
等)逐步读取大Key中的数据,然后将数据迁移到新的小Key中。例如,在一个社交系统中,有一个大Key存储了某个用户所有的好友关系(List类型),可以使用LRANGE
每次读取一部分好友关系,然后插入到新的以用户ID和分页信息命名的小Key中(如user:1:friends:page1
,user:1:friends:page2
等)。在迁移过程中,线上业务仍然可以从原大Key读取数据,待迁移完成后,再切换到新的小Key读写。 - 影子Redis实例:创建一个影子Redis实例,将大Key的数据逐步迁移到影子实例,并修改线上业务代码,使其在读写时先从影子实例读取,如果影子实例没有再从原实例读取。随着时间推移,大部分业务流量会转移到影子实例,此时可以将原大Key删除,然后将影子实例替换原实例。
- 异步迁移:使用Redis的
- 优化存储结构:
- 转换数据结构:例如,如果大Key是一个非常大的Hash结构,且其中部分字段访问频率很低,可以将这些低频字段提取出来,存储到另外一个Key中。比如在一个用户资料存储的Hash大Key中,用户的历史登录IP信息访问频率低,可将其提取到一个新的Key(如
user:1:history_ips
),原Hash大Key只保留常用信息。这样原大Key的体积会减小,同时不影响高频业务的访问。
- 转换数据结构:例如,如果大Key是一个非常大的Hash结构,且其中部分字段访问频率很低,可以将这些低频字段提取出来,存储到另外一个Key中。比如在一个用户资料存储的Hash大Key中,用户的历史登录IP信息访问频率低,可将其提取到一个新的Key(如