常见场景题
常见场景题
场景设计题答题模版:核心待解决问题点 + 解决方式
如何设计一个秒杀功能?
需要解决的问题点:
- 瞬时流量承接
- 防止超卖
- 避免对正常服务影响
- 兜底方案(数据库兜底不超卖)
一般的设计是:
- 秒杀页面静态化,通过 CDN 减少请求压力
- 网关层做限流和防刷
- 库存提前加载到 Redis,通过 DECR 原子扣减库存
- 扣库存成功后把下单请求写入 MQ,实现削峰填谷
- 订单服务异步消费 MQ 创建订单
- 数据库通过 update … where stock > 0 再次保证不超卖
缓存和数据库一致性如何保证?
方案 1:Cache Aside(旁路缓存)
- 读:先查缓存,缓存未命中再查数据库,查询结果写入缓存
- 写:先更新数据库,后删除缓存
优点:实现简单;缺点:可能存在短暂的缓存不一致
方案 2:延时双删
- 写:先更新数据库,删除缓存;sleep(100ms)二次删除缓存
优点:解决并发写导致脏数据问题,缺点:需要 sleep,不够优雅
方案 3:消息队列异步更新缓存(最终一致性)
- 写:先更新数据库,发送消息到 MQ;异步消费 MQ 删除缓存
优点:解耦,可重试,最终一致性
方案 4:Binlog + Canal
- 写:Mysql -> Binlog -> Canal 监听 -> Cache Update Service -> Redis
优点:数据驱动,不侵入业务,最终一致性
有一张表里面有三个字段,分别是(id,开始时间,结束时间),表中数据量为 5000W,找出任意时刻最大并发数?
解题思路:把区间问题转成“事件点”问题;然后按时间排序,做一次 前缀和扫描(Sweep Line 算法)
例子:
| id | start | end |
|---|---|---|
| 1 | 1 | 5 |
| 2 | 2 | 7 |
| 3 | 4 | 6 |
第一步:转换为事件
| time | value |
|---|---|
| 1 | +1 |
| 5 | -1 |
| 2 | +1 |
| 7 | -1 |
| 4 | +1 |
| 6 | -1 |
第二步:按时间排序
| time | value |
|---|---|
| 1 | +1 |
| 2 | +1 |
| 4 | +1 |
| 5 | -1 |
| 6 | -1 |
| 7 | -1 |
第三步:前缀和统计
| time | value | current | max |
|---|---|---|---|
| 1 | +1 | 1 | 1 |
| 2 | +1 | 2 | 2 |
| 4 | +1 | 3 | 3 |
| 5 | -1 | 2 | 3 |
| 6 | -1 | 1 | 3 |
| 7 | -1 | 0 | 3 |
所以最大并发 = 3
分布式锁一般都怎样实现?
见分布式锁
现在有 40 亿个 QQ 号,给你 1G 的内存,如何实现去重?
- 方案1位图(Bitmap): 原理是每个QQ号对应1位,若存在则置 1,否则置 0
需要知道 QQ 号的范围
- 方案2归并: 将 40 亿个 QQ 号分成多块文件,用map去重后,归并结果
- 方案3布隆过滤器(Bloom Filter): 通过多个哈希函数将 QQ 号映射到一个位数组中,判断是否存在
假阳性;可能存在误判(false positive),但不会漏判(false negative)
如果要实现一个抢红包的功能,红包金额是如何计算的?
方案 A:平均分 + 小随机偏移
1
2
3
4
原理:
1、平均分 = totalAmount / n
2、每个红包加上随机波动:amount_i = average ± random(0, maxOffset)
3、最后一个红包用剩余金额补齐
优点是实现简单,缺点是红包差异不大,随机感低
方案 B:动态随机法(微信红包算法)
1
2
3
4
原理:
1、第 i 个人抢红包时,剩余金额为 R,剩余人数为 k
2、随机生成一个金额:
3、更新剩余金额和人数:
优点是随机性好,正态分布。
如果项目需要你实现敏感词过滤功能,如何实现?
方案1: 字典树(Trie / 前缀树)
方案2: Bloom Filter
实现一个算法,展示直播间送礼top 10用户
方案1: 小顶堆 Heap<user_id, total_value> + 哈希表 Map<user_id, total_value>
- 小顶堆快速维护 Top 10;堆操作时间复杂度
O(logK),整体时间复杂度O(N logK); 堆空间复杂度O(K) - 哈希表快速查询某个用户总礼物金额
方案2: Redis ZSet
ZINCRBY live:<room_id> <gift_value> <user_id>→ 增加礼物总额ZREVRANGE live:<room_id> 0 9 WITHSCORES→ 获取 Top 10
设计一个并发安全,lru缓存
数据结构:哈希表 + 双向链表
- 哈希表提供 O(1) 的访问时间,存储 key, value 是指向双向链表节点
- 双向链表维护访问顺序,头部是最近访问的元素,尾部是最久未访问的元素
1
2
3
优化:
1 、空间换时间:多 shard 分片锁,减少锁竞争
2 、借鉴 Redis,近似 LRU,候选池优化采样效果
使用redis实现延时队列
核心需求:延时消息需要根据延时时间排序,所以使用ZSet
使用ZSet。score为执行时间戳,member为消息
需要优化问题点:
消费端轮询空转
- 获取最后一条消息执行时间戳,sleep
重复消费问题
- lua脚本原子化操作:获取消息 + 删除消息
- 消费者幂等
消息保证不丢
- 到期任务 → 放入 ready_queue(List)
高并发优化
- 分片
百万规模消息优化
- 使用时间轮,每个 slot = 一个时间片(比如 1 秒),slot是list数据结构 ``` 一个圆盘(时间轮):
slot_0 slot_1 slot_2 … slot_59 ```
This post is licensed under CC BY 4.0 by the author.