Redis进阶-Redis键值设计及BigKey问题

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: Redis进阶-Redis键值设计及BigKey问题


键值设计

key设计

  • (1)【建议】: 可读性和可管理性
    以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id
    o2o:order:1

  • (2)【建议】:简洁性
    保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视,例如:
    user:{uid}:friends:messages:{mid} 简化为 u:{uid}🇫🇷m:{mid}

  • (3)【强制】:不要包含特殊字符
    反例:包含空格、换行、单双引号以及其他转义字符

value设计

  • (1)【强制】:拒绝bigkey(防止网卡流量、慢查询)
  • (1)(2)【推荐】:选择适合的数据类型。
    例如:实体类型(要合理控制和使用数据结构,但也要注意节省内存和性能之间的平衡)
    反例:
set user:1:name tom
  set user:1:age 19
  set user:1:favor football
  • 正例:
hmset user:1 name tom age 19 favor football

  • (1)3.【推荐】:控制key的生命周期,redis不是垃圾桶
    建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期)

big key

我们知道,Redis 的一个字符串最大512M,一个二级数据结构(比如 hash、list、set 、zset)可以存储2^32-1 个元素 ,约40亿个元素。 但是不是以为着我们可以任意存储元素呢? 时刻牢记,在读写这个角度上,目前Redis还是单线程的。


定义

其实不然,按照经验来说 ,如何定义bigKey 呢?

  • 字符串类型:它的big体现在单个value值很大,一般认为超过10KB就是bigkey。
  • 非字符串类型:哈希、列表、集合、有序集合,它们的big体现在元素个数太多。

一般来说,string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。当然了这不是绝对的,请依据场景,灵活处理。


反例

我们来看个反例: 一个hash 存储用户信息,我有100万用户,我全都放到一个key里。。。。这不管从哪个角度看 ,bigkey无疑。


bigkey的产生

一般来说,bigkey的产生都是由于程序设计不当,或者对于数据规模预料不清楚造成的,来看几个例子:

  • 社交类:粉丝列表,如果某些明星的粉丝数据,如果不精心设计下,一个明星的粉丝 百万很少了吧,你都把这百万的粉丝数据放到一个key中存储,毫无疑问是bigkey
  • 统计类:比如按天存储某项功能或者网站的用户集合,用户很少,倒是没多大问题,一旦用户多了起来,必是bigkey
  • 缓存类:将数据从数据库加载出来以后序列化放到Redis里,这个方式非常常用,但有两个地方需要注意,第一,是不是有必要把所有字段都缓存;第二,有没有相关关联的数据,不要为了图方便把相关数据都存一个key下,产生bigkey。

如何优化bigkey

核心思想: 分治 拆分


  • big list: list1、list2、…listN
    big hash:可以讲数据分段存储,比如一个大的key,假设存了1百万的用户数据,可以拆分成 200个key,每个key下面存放5000个用户数据
  • 如果bigkey不可避免,也要思考一下要不要每次把所有元素都取出来(例如有时候仅仅需要
    hmget,而不是hgetall),删除也是一样,尽量使用优雅的方式来处理
  • 【推荐】:选择适合的数据类型
    例如:实体类型(要合理控制和使用数据结构,但也要注意节省内存和性能之间的平衡)
    反例:
set user:1:name tom
set user:1:age 19
set user:1:favor football
  • 正例:
hmset user:1 name tom age 19 favor football
  • 【推荐】:控制key的生命周期,redis不是垃圾桶
    建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期)。

删除bigKey的注意事项

对于非字符串的bigkey,比如 hash list set zset , 不要使用del 删除, 请使用 hscan 、sscan、zscan方式渐进式删除。

同时要注意防止bigkey过期时间自动删除问题(例如一个100万的hash设置1小时过期,会触发del操作,造成阻塞)


bigkey的危害
  • 导致redis阻塞
    这个也很好理解: 我们知道Redis 官方号称10万QPS, 我们通常打不到这个值,但是大几万的QPS还是没问题的,这也就意味着 redis 的执行速度 1秒几万条, 速度相当的快的。 假设你有个bigKey , 操作一次耗时1秒,那Redis 单线程 在这1秒钟就只能处理你这个Key, 后面堵了一堆请求。。。。 并且你的应用 序列化和反序列化这种大key , 也消耗CPU 。
  • 导致网络拥塞
    假设我们的交换机,千兆网络(小b),那么 实际带宽 1024 / 8 = 128M . 假设你的这个key的大小 500KB, 客户端并发 1000获取这个key, 那么就意味着 1000 * 500KB = 500M ,那就是每秒产生500M的流量。先不说你的Redis能不能处理的过来这个并发下的bigKey,单说你的这个千兆网络, 你说你这个网络I/O能扛得住吗? 一般服务器会采用单机多实例的方式来部署,也就是说一个bigkey可能会对其他实例也造成影响,其后果不堪设想。

  • 过期删除- Redis4.0新特性(三)-Lazy Free
    针对那种我们设置了过期时间的big key , 在redis4.0前,没有lazy free功能,我们只能通过类似scan big key,每次删除少量的元素,分多次删除;但在面对“被动”删除键的场景,这种取巧的删除就无能为力。
    举个例子:Redis Cluster大集群,业务缓慢地写入一个带有TTL的2000多万个字段的Hash键,当这个键过期时,redis开始被动清理它时,导致redis被阻塞20多秒,结果发生了fail over ,造成故障。
    Redis 4.0提供了过期异步删除(lazyfree-lazyexpire yes)
    lazy free 惰性删除或延迟释放: 当删除键的时候,redis提供异步延时释放key内存的功能,把key释放操作放在Background I/O单独的子线程处理中,减少删除big key对redis主线程的阻塞,有效地避免删除big key带来的性能和可用性问题。
    redis4.0有lazy free功能后,这类主动或被动的删除big key时,时间复杂度O(1)。


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore     ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
7月前
|
存储 缓存 NoSQL
深入解析Redis:一种快速、高效的键值存储系统
**Redis** 是一款高性能的键值存储系统,以其内存数据、高效数据结构、持久化机制和丰富的功能在现代应用中占有一席之地。支持字符串、哈希、列表、集合和有序集合等多种数据结构,适用于缓存、计数、分布式锁和消息队列等场景。安装Redis涉及下载、编译和配置`redis.conf`。基本操作包括键值对的设置与获取,以及哈希、列表、集合和有序集合的操作。高级特性涵盖发布/订阅、事务处理和Lua脚本。优化策略包括选择合适数据结构、配置缓存和使用Pipeline。注意安全、监控和备份策略,以确保系统稳定和数据安全。
420 1
|
7月前
|
存储 缓存 Java
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
【Spring原理高级进阶】有Redis为啥不用?深入剖析 Spring Cache:缓存的工作原理、缓存注解的使用方法与最佳实践
|
2月前
|
消息中间件 缓存 NoSQL
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
大数据-49 Redis 缓存问题中 穿透、雪崩、击穿、数据不一致、HotKey、BigKey
66 2
|
5月前
|
NoSQL Redis 容器
Redis性能优化问题之如何判断 Redis 实例是否写入了 bigkey
Redis性能优化问题之如何判断 Redis 实例是否写入了 bigkey
|
5月前
|
存储 消息中间件 NoSQL
中间件键值存储模型Redis
【7月更文挑战第11天】
57 3
|
7月前
|
存储 缓存 NoSQL
Redis经典问题:BigKey问题
BigKey问题常困扰着Redis用户,其影响不容忽视。本文将深入探讨BigKey问题的本质及解决方案,帮助你优化Redis性能,提升系统稳定性。
569 2
|
6月前
|
NoSQL 数据可视化 Java
rodert单排学习redis进阶【白银一】
rodert单排学习redis进阶【白银一】
34 0
|
6月前
|
NoSQL Redis 数据库
rodert单排学习redis进阶【青铜】2
rodert单排学习redis进阶【青铜】
38 0
|
6月前
|
缓存 NoSQL Java
rodert单排学习redis进阶【青铜】1
rodert单排学习redis进阶【青铜】
46 0
|
6月前
|
NoSQL 关系型数据库 MySQL
Redis进阶-select 1. /xxx 切换数据库DBSIZE- 获取当前数据库中的key的个数flushdb-删除当前数据的所有keyflushall-删除所有表的所有库Re
Redis进阶-select 1. /xxx 切换数据库DBSIZE- 获取当前数据库中的key的个数flushdb-删除当前数据的所有keyflushall-删除所有表的所有库Re