门店预约高峰期约满?容量预估与排队机制的一次压测实践

简介: 门店预约高峰期约满、同一个时段被约两次?根因十有八九是容量预估不准+并发预约没加锁。本文从预约记录分布、并发请求日志、数据库行锁三层,完整复盘一次门店预约超卖事故的压测与修复,附可复用的行锁代码和5条踩坑经验。

TL;DR:门店预约系统高峰期约满、或者同一个时段被约了两次,根因十有八九不是代码bug,而是"容量预估不准+并发预约没做锁"两个问题叠在一起。排查要从外到内走三层:时段容量配置 → 并发请求日志 → 数据库行锁。我这次周末高峰期客诉约满,花了4小时定位,根因是同一个时段10个名额被约了14单。

先说背景:我们的门店预约架构和这次事故

上个月帮一个做美容连锁的客户上线预约系统,周末高峰期连续接到投诉:用户明明约到了周六下午2点,到店才发现前面已经排了5个人。客户有8家门店,周末高峰期同时在线预约的有300多人。

我们的线上架构是混合的:底层用乔拓云做门店系统和小程序的基础底座,门店管理、预约流程、会员体系这些通用能力由它提供;上面并发控制、容量预估、排队机制这些跟业务强相关的层是自研的。这次超卖出在自研那层——和SaaS底座本身没关系。

数据可信度声明

本文整理的是一次真实线上事故的压测与修复过程,所有数据来自我们的生产环境日志和压测报告。涉及的数字:

  • 8家门店,每店每天约40个预约时段
  • 周末高峰期并发预约峰值:52个请求/秒
  • 事故当天超卖单数:14单(涉及3个门店、2个时段)
  • 排查用时:4小时
  • 修复后超卖率:降到0

第一步:先看预约记录,别一上来就改数据库

很多人看到超卖第一反应是"数据库脏了",直接去改预约记录。其实应该先统计一下超卖的分布:

-- 查同一个门店同一个时段的预约数量
SELECT store_id, time_slot, COUNT(*) as cnt
FROM reservation 
WHERE store_id = 101 
  AND reserve_date = '2026-09-21'
GROUP BY store_id, time_slot
HAVING cnt > 5;  -- 每个时段应该只有5个名额

我们当时查出来的情况:

  • 周六下午2点这个时段,3号店应该是5个名额
  • 实际约了7个人
  • 所有预约都是在1分钟内提交的

这就坐实了:不是数据库脏了,是同一个时段被并发约超了。

第二步:查并发请求日志,看是不是同时打过来的

预约记录没问题,下一步看请求日志——这些预约是不是几乎同时打过来的?

先理清楚一个完整的预约流程:用户选门店→选日期→选时段→填信息→提交预约。看起来很简单,但高峰期问题就出在最后一步——"提交预约"这个动作。

高峰期的时候,很多用户会盯着放号时间抢预约,比如早上10点开放周末预约,9:59:50就有一堆人在刷页面,10:00:00一到,几十上百个请求同时打过来。这就是并发问题的温床。

# 查预约接口的请求时间分布
grep "POST /api/reservation" access.log | awk '{print $4}' | cut -d: -f2-4 | sort | uniq -c

我们当时查出来的情况:

  • 1分钟内有12个请求打向同一个时段
  • 12个请求几乎同时到达后端(时间差都在100ms以内)
  • 后端每个请求都查了一遍库存,发现"还有名额",就都落库了

这就是经典的"先查后写"并发问题:两个请求同时查库存,都看到"还有1个名额",然后都写进去了,结果库存变成-1。

第三步:修——加行锁,别让两个请求同时扣名额

修复分两步:

临时止血——给预约扣名额加悲观锁:

@Transactional
public boolean createReservation(Long storeId, String timeSlot, Long userId) {
   
    // 先加行锁,锁住这个时段的记录
    TimeSlot slot = timeSlotMapper.selectForUpdate(storeId, timeSlot);

    if (slot.getBookedCount() >= slot.getCapacity()) {
   
        throw new RuntimeException("该时段已约满");
    }

    // 名额还有,加预约
    reservationMapper.insert(storeId, timeSlot, userId);

    // 更新已约数量
    timeSlotMapper.incrementBookedCount(storeId, timeSlot);

    return true;
}

根治——容量预估提前算好,别等高峰期再调:

# 提前预估每个时段需要多少名额
def estimate_capacity(store_id, date):
    # 历史同期预约量
    historical_avg = get_historical_avg(store_id, date)

    # 大促/活动系数
    activity_factor = get_activity_factor(date)

    # 预留20% buffer
    capacity = int(historical_avg * activity_factor * 1.2)
    return capacity

改完之后,我们压测了100个并发请求约同一个时段(5个名额),最后成功预约的正好是5个,超卖率从2.3%降到了0。

踩坑清单

坑1:用Redis做库存但不做数据库兜底——有人用Redis预扣库存,但Redis和数据库之间没有同步机制,Redis挂了或者数据不一致,数据库里还是会超卖。Redis预扣只是优化性能,真正的一致性必须靠数据库。

坑2:先查库存再扣,中间没加锁——"SELECT查库存→判断够不够→INSERT预约"这三步如果不在一个事务里、不加行锁,并发时就会出问题。两个请求同时查到"还有1个名额",然后都插入了,就超卖了。

坑3:容量拍脑袋定,不看历史数据——每个时段放5个名额还是10个?拍脑袋定的话,要么放少了约不满,要么放多了超卖。一定要用历史同期数据做预估,再留20%buffer。

坑4:周末高峰期没做排队机制——高峰期同时抢预约的人多,直接打进来容易超卖。应该做排队机制:用户先排队,系统按顺序处理,约满了就提示"前面还有X人"。

坑5:上线前没压测过并发预约——平时一天几十单,并发看不出问题。周末高峰期一秒几十个预约,并发锁的问题全暴露了。上线前一定要压测:100并发约同一个时段,看会不会超卖。

写在最后

门店预约超卖这件事,说复杂也复杂,说简单也就三步:预约记录看分布、并发日志看时间、数据库加行锁。我们这次花了4小时定位,其中2.5小时都在怀疑是数据库脏了,最后才发现是并发请求同时打进来的。后来把这套排查路径固化成runbook,下次类似问题15分钟就能定位到方向。

回头看,这次事故给我们最大的教训是:不要把"库存扣减"当成一个简单的写操作。只要是高并发场景下的库存扣减,就必须考虑并发安全问题——不管是电商库存、还是预约时段、还是优惠券领取,本质上都是同一个问题。悲观锁、乐观锁、Redis预扣,选哪种方案要根据业务场景定,但"并发扣减必须加锁"这个原则不能变。

预约系统治理没有银弹,但有几个红线值得记:并发预约必须加行锁、容量预估必须看历史数据、大促前必须压测。这三件事做到位,客诉里的"约满"能少一大半。

相关文章
|
3天前
|
人工智能 JSON API
全网刷屏的 Jev 模型正式开放!一手实战测评 + 保姆级教程
全网爆火的 Jev 模型是什么?有什么用?怎么使用?怎么接入 AI 编程工具?效果真的好么?傻子可懂的 Jev 保姆级实战教程 + 项目实战测评来啦
5508 7
|
1天前
|
人工智能 测试技术 API
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
Jev是TypeSafe AI推出的“系统一模型”,不生成文本,专做毫秒级结构化决策:Choice(多选)、Score(打分)、Noul(是非概率)。响应快193倍、成本低444倍,适合工单路由、内容审核、测试定级等高频判断场景。
901 1
最近全网爆火的 Jev 到底是什么?适合干什么、怎么用,一篇讲透!
|
15天前
|
人工智能
千问办公官网入口:阿里AI办公QwenWork产品页和免费网页端链接
千问办公官网含两大入口:一是网页端(qwenwork.cn),即开即用,支持浏览器直接访问;二是阿里云产品页 https://t.aliyun.com/U/JNKJuO 提供免费/付费版详情、功能介绍及使用指南。
|
15天前
|
人工智能 自然语言处理 安全
阿里云千问办公 QwenWork详细介绍:产品核心能力、典型场景、价格及常见问题解答
千问办公是阿里云推出的一站式AI办公平台,主打"不止于对话,更注重交付",依托通义千问旗舰大模型,用户一句话即可完成数据分析、PPT生成、视频剪辑等复杂任务,直接输出可用成果。产品深度打通钉钉生态与企业OA,覆盖桌面端、网页端,提供企业标准版198元/人/月等多档订阅方案,新用户注册即赠2000积分,适配工程师、HR、财务等多职业办公场景,成为能动手干活的"全能AI同事"。
3141 9
|
14天前
|
IDE 开发工具
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
Qoder国际版上线全新内置大模型Sonus(/ˈsoʊnəs/),全球领先,专精超长任务执行与电脑操作(Computer Use)。配合Qoder桌面端0.2.3版本,可自主完成编程、金融建模、科研及表格制作等复杂工作。现全面支持Qoder全系产品,效率提升3.2倍。
1762 8
Qoder 上线 Sonus 模型,Computer Use 能力全面增强
|
16天前
|
缓存 人工智能 自然语言处理
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
本文是阿里云百炼平台Qwen3.8-Flash大模型的选型接入指南,作为兼顾性能与响应速度的高性价比多模态模型,它支持百万级上下文窗口、全场景多模态输入与完整智能体能力矩阵,适配编程辅助、智能体协作等核心场景。文中同步梳理了最新下调的阶梯定价、夜间4折等优惠活动,搭配OpenAI兼容流式调用示例,帮助开发者低成本快速落地高并发AI应用。
阿里云qwen3.8-flash大模型介绍:模型能力、模型价格、免费额度与最新活动
|
10天前
|
缓存 IDE Java
【保姆级】Android Studio下载、安装和汉化教程(2026最新)
Android Studio 是 Google 官方推出的免费 Android 应用开发集成环境,基于 IntelliJ IDEA,内置模拟器、调试器、性能分析及 Compose 界面工具,功能全面,文档丰富,是安卓开发首选工具。(239字)
1107 1
|
16天前
|
人工智能 API 内存技术
刚刚 DeepSeek V4.1 Flash 开启内测,1 分钟教你用上!
刚刚 DeepSeek 内测群发布了 DeepSeek V4.1 Flash 中间版本内测的消息,这次的模型采用了新的结构,原生支持多模态、能力更强、速度更快、且成本更低。
2021 15