如何设计秒杀场景处理高并发以及超卖现象
布隆过滤器原理了解一下
使用位图,然后如果存储一个数据x,选择N个哈希函数计算 hash 值,hash 值取模得到位图位置,对应的位置设置为1。由于存在hash 冲突,比如x 和 y可能对应同样的位置,然后导致再次检测这个x 是否存在时,会这个误判为存在,但是如果这个位图不为1, 这个一定不存在。
Redis 有哪些数据类型?分别适合什么场景
Redis 最常用的是五种基础类型:String、Hash、List、Set、ZSet。随着版本演进,又陆续加入了 BitMap、HyperLogLog、GEO、Stream 四种特殊类型。
五种基础类型
| 类型 | 结构 | 典型场景 |
|---|---|---|
| String | 字符串、数字或二进制 | 缓存对象、计数器、分布式锁、共享 Session |
| Hash | field-value 映射表 | 存储对象属性、购物车 |
| List | 双端链表 | 简单消息队列、最新消息列表 |
| Set | 无序且不重复的集合 | 点赞、共同关注、抽奖去重 |
| ZSet | 按 score 排序的集合 | 排行榜、延时队列、按时间排序 |
几个常用写法:
bash
SET product:stock:2001 100 # 缓存库存
INCR article:view:8848 # 阅读量 +1
SET lock:order:5 uuid NX EX 10 # 分布式锁,10 秒过期
HSET cart:user:1001 sku:77 2 # 购物车里某商品数量为 2
SINTER follow:alice follow:bob # 两人的共同关注
ZADD rank:game 9800 "player_7" # 写入排行榜分数
ZREVRANGE rank:game 0 9 WITHSCORES # 取前十名补充说明:
- 用 List 做消息队列有局限:消息没有全局唯一 ID,也不支持多个消费组分别消费。
- Hash 存对象时可以单独修改某个字段,比把整个对象序列化成 String 更灵活。
四种特殊类型
| 类型 | 版本 | 特点 | 典型场景 |
|---|---|---|---|
| BitMap | 2.2 | 按位存储 0/1,极省空间 | 签到、在线状态、连续签到统计 |
| HyperLogLog | 2.8 | 基数估算,固定约 12KB,有少量误差 | 百万级网页 UV 统计 |
| GEO | 3.2 | 存储经纬度,计算距离和范围 | 附近的人、打车派单 |
| Stream | 5.0 | 专为消息队列设计 | 可靠的消息队列 |
Stream 弥补了 List 做队列的不足:自动生成全局唯一消息 ID,支持消费组,还有消息确认(ACK)机制。
bash
SETBIT sign:1001:202610 13 1 # 用户 1001 在本月第 14 天签到
BITCOUNT sign:1001:202610 # 本月签到天数
PFADD uv:page:home u1 u2 u3 # 记录访客
PFCOUNT uv:page:home # 估算 UV底层编码(简单了解)
数据类型是对外的接口,底层会根据数据量选择不同的编码以节省内存。例如 ZSet 元素少时用紧凑的 listpack,多时改用跳表加哈希表;Hash 和 Set 也会在 listpack/intset 与哈希表之间切换。
总结
String、Hash、List、Set、ZSet 覆盖了缓存、计数、去重、排序等大多数需求;BitMap、HyperLogLog、GEO、Stream 分别针对二值统计、基数统计、地理位置和消息队列做了优化。面试时把每种类型和一两个具体场景对应起来讲,最有说服力。
📮 联系方式
微信:BuZhiCoder | QQ:1776418445 扫码添加,备注「求职」优先通过
