
1) 【一句话结论】
秒杀系统需通过“限流-排队-分布式锁-消息队列-数据库双写”的组合架构,在保证高并发下公平性(先到先得/随机公平)与性能的同时,实现容错与扩展。
2) 【原理/概念讲解】
老师可以解释秒杀的核心矛盾:大量用户同时请求,如何避免超卖(库存耗尽)和保证公平性(比如先到先得,或随机但公平)。首先讲限流:漏桶模型(用户请求像水流进水库,水库容量是并发数,超过则丢弃或排队)和令牌桶模型(每秒生成固定令牌,用户请求消耗令牌,超限则排队)。然后讲分布式锁:比如用Redis的SETNX实现,保证同一时间只有一个用户能获取锁并扣减库存,防止超卖。接着讲消息队列:用户请求先入队列,由消费者异步处理,避免直接访问数据库压力过大。再讲数据库双写:比如先更新库存到Redis(快速),再异步写入数据库(保证持久性),或用事务保证一致性。公平性设计上,用队列+时间戳保证先到先得,或随机数+时间戳排序保证随机公平。
3) 【对比与适用场景】
以限流算法和分布式锁为例:
| 对比项 | 限流算法(漏桶 vs 令牌桶) | 分布式锁(Redis SETNX vs Zookeeper) |
|---|---|---|
| 定义 | 漏桶:模拟水库,固定速率流出;令牌桶:模拟自动贩卖机,按需生成令牌 | Redis SETNX:Redis原子操作;Zookeeper:Znode临时节点 |
| 特性 | 严格限制流量,丢弃超限请求;令牌桶:允许突发流量,超限请求排队 | Redis SETNX:速度快,分布式支持;Zookeeper:分布式协调,高可用 |
| 使用场景 | 对实时性要求高,需严格限制并发数(如秒杀初始阶段);令牌桶:对突发流量容忍度高(如日常抢购) | Redis SETNX:依赖Redis,适合中小规模;Zookeeper:适合大规模集群,高可用 |
4) 【示例】
伪代码示例(用户请求处理流程):
def handle_red_packet_request(user_id, product_id):
# 1. 限流:检查令牌桶,超限则返回排队
if not check_token_bucket(user_id):
return {"code": "queue", "message": "请排队"}
# 2. 获取分布式锁
lock_key = f"lock:product:{product_id}"
if not acquire_distributed_lock(lock_key, user_id):
return {"code": "failed", "message": "系统繁忙"}
# 3. 检查库存(Redis)
stock = get_stock_from_redis(product_id)
if stock <= 0:
release_distributed_lock(lock_key, user_id)
return {"code": "sold_out", "message": "已售罄"}
# 4. 扣减库存(Redis)
new_stock = stock - 1
set_stock_to_redis(product_id, new_stock)
# 5. 异步写入数据库(消息队列)
send_to_message_queue(user_id, product_id, new_stock)
# 6. 释放锁
release_distributed_lock(lock_key, user_id)
return {"code": "success", "message": "抢到红包"}
5) 【面试口播版答案】
“面试官您好,针对秒杀系统的高并发、公平性与性能问题,我的核心思路是构建一个‘限流-排队-锁控-异步-双写’的分层架构。首先,通过令牌桶算法控制用户请求速率,避免瞬间流量冲击;然后,用户请求进入消息队列排队,保证先到先得(公平性);接着,使用Redis分布式锁保证库存扣减的排他性,防止超卖;库存更新后,异步写入数据库确保数据持久性。这样既能保证公平性(队列+时间戳),又能通过异步处理提升性能,同时通过双写和锁机制实现容错。具体来说,比如用户请求先被限流,进入队列后,由消费者处理,获取锁后检查库存,扣减Redis库存,再异步写数据库,整个过程保证高并发下的公平性和性能。”
6) 【追问清单】
7) 【常见坑/雷区】