当前位置: 首页 > ops >正文

Redis数据结构选择策略--String?Hash?怎么选?

背景:

先想下我们要做一个用户砸蛋抽券的活动,然后需要对于不同的数据需要设计不同的Redis数据结构,是String呢?还是Hash?怎么选择?

要知道:不同数据采用不同Redis数据结构的设计是基于数据特性和操作需求做出的合理选择~

先看设计好的:

    private static final String COUPON_KEY = "egg_break:coupons";  // 存储奖券库存private static final String PROB_KEY = "egg_break:probabilities";  // 存储奖券概率private static final String DAY_KEY = "egg_break:current_day";  // 当前活动天数private static final String USER_PREFIX = "egg_break:user:";  // 用户数据前缀private static final String LOCK_PREFIX = "egg_break:lock:";  // 锁前缀private static final String DAILY_INIT_KEY = "egg_break:daily_init"; // 新增

然后分析如下: 

一、Hash结构的使用场景

1. 奖券库存(COUPON_KEY)

private static final String COUPON_KEY = "egg_break:coupons"; // Hash结构

使用Hash的原因

就像一张表格:

券类型数量
51000
7500
10200
  • 键名设计技巧

    • egg_break:coupons

      • egg_break是活动名前缀(防止和其他业务冲突)

      • coupons明确表示存储的是奖券信息

  • 多字段管理:需要存储多种奖券类型及其对应库存(如:"5元券"→100, "10元券"→50)

  • 原子操作相比String存储序列化的JSON,可以单独获取/更新某个Value,即可以直接对特定奖券执行HINCRBY增减库存,无需读取整个数据集

  • 高效查询:通过HGET可以快速获取特定奖券的库存量

  • 相比String结构(每个信息一个key,所以需要多个key)而Hash一个key下多个field,可以减少key的数量,节省内存

  • 在需要整体获取所有券信息时,String需要多次get,而Hash只需一次hgetall

操作示例

HSET egg_break:coupons "5元券" 100 "10元券" 50
HINCRBY egg_break:coupons "5元券" -1  # 扣减库存

2. 奖券概率(PROB_KEY)

private static final String PROB_KEY = "egg_break:probabilities"; // Hash结构

使用Hash的原因

  • 关联数据:需要与奖券库存保持相同的键结构(相同的奖券名称作为field)

  • 批量获取:可以通过HGETALL一次性获取所有奖券及其概率,用于概率计算

  • 动态更新:可以单独修改某个奖券的概率而不影响其他数据

另外注意点:

  • 使用字符串存储(Redis本身没有浮点类型)
  • 为什么不和数量存在一起?
    遵循"单一职责原则":一个Hash只负责一件事,要么管数量,要么管概率

二、String结构的使用场景

1. 当前活动天数(DAY_KEY)

private static final String DAY_KEY = "egg_break:current_day"; // String结构

使用String的原因

  • 单一值只需要存储一个整数值表示当前天数

  • 原子递增:可以使用INCR命令安全地增加天数

  • 简单读取:只需要GET命令即可获取当前值

  • 为什么用String而不是数字?
    Redis命令set默认就是字符串存储,足够简单

操作示例

SET egg_break:current_day 1
INCR egg_break:current_day  # 天数+1

2. 每日初始数量(DAILY_INIT_KEY)

private static final String DAILY_INIT_KEY = "egg_break:daily_init"; // String结构

使用String的原因

  • 整体性数据:通常作为整体配置读取(如JSON格式的每日初始化设置)

  • 一次性设置:每日初始化时整体写入,不需要单独修改其中部分

  • 可能的结构

    { "day1": {"5元券": 100, "10元券": 50}, "day2": {"5元券": 80, "10元券": 70} }

三、数据结构选择决策矩阵

考虑因素Hash结构String结构
数据复杂度多个键值对的组合单一值或序列化后的复杂对象
访问模式需要单独访问或修改部分字段总是整体读写
原子操作需求需要字段级原子操作(如HINCRBY)需要键级原子操作(如INCR)
数据关联性需要保持相同field结构的关联数据独立数据项
典型命令HSET/HGET/HINCRBY/HGETALLSET/GET/INCR/DECR

四、其他可能的数据结构选择

1. 用户数据(USER_PREFIX + userId)

当前代码中使用Hash存储用户数据也是合理的:

String userKey = USER_PREFIX + userId; // Hash结构

优势

  • 可以单独更新用户某天的记录(HSET day1 "5元券")

  • 可以高效检查某天是否参与(HEXISTS day1)

2. 为什么不用Sorted Set?

虽然Sorted Set适合带权重的场景,但在本系统中:

  • 奖券概率只在抽奖时一次性使用,不需要持续排序

  • 库存管理需要精确的数值操作,Sorted Set的score是浮点数可能不精确

总结下思路:

  1. 选择依据优先级

    • 首先考虑数据访问模式(整体读写 vs 部分读写)

    • 其次考虑原子操作需求

    • 最后考虑内存效率(Hash对少量字段更高效)

http://www.xdnf.cn/news/13087.html

相关文章:

  • C++ Saucer 编写Windows桌面应用
  • AI——DeepSeek+LangChain+streamlit 实现智能汽车维修服务
  • 视觉slam十四讲实践部分记录——ch2、ch3
  • 字节开源代码模型——Seed-Coder 本地部署教程,模型自驱动数据筛选,让每行代码都精准落位!
  • ​第八章:漏洞里的人间烟火
  • Linux线程与进程关系及底层实现
  • 瑞数信息入选Gartner《中国API管理市场指南》
  • 亚马逊测评,采购环境安全需要解决哪些问题,提高成功率
  • 验证redis数据结构
  • 课堂笔记:吴恩达的AI课(AI FOR EVERYONE)-第一周part2 人工智能术语人工智能公司应该怎么做
  • 恶补电源:1.电桥
  • 【第一章:人工智能基础】01.Python基础及常用工具包-(3)常用数据科学工具包
  • 性能测试分析
  • 深度剖析Diffusion与Transformer在图像生成中的计算逻辑与融合之道
  • 火山引擎云服务器使用感怎么样
  • HarmonyOS运动开发:打造你的专属运动节拍器
  • python打卡day49
  • 大数据学习(135)-Linux系统性指令
  • Windows 环境下,使用 ESP32 JTAG 接口进行固件下载
  • 浅谈互联网主流通信协议
  • 【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
  • 【堆垛策略】设计方法
  • SAP软件年结科目余额结转详解
  • ShuffleNet 改进:与通道注意力机制(CAM)的结合实现
  • 如何用Coze+Fetch快速构建结构化文档
  • deepbayes lecture2:变分推断
  • 【实证分析】上市公司企业风险承担水平数据集(2000-2022年)
  • Houdini POP入门学习06 - 物理属性2
  • 十二、MySQL 8 新特性底层原理
  • 角色塑造江湖秘籍