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

简介: 门店预约高峰期约满、同一个时段被约两次?根因十有八九是容量预估不准+并发预约没加锁。本文从预约记录分布、并发请求日志、数据库行锁三层,完整复盘一次门店预约超卖事故的压测与修复,附可复用的行锁代码和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预扣,选哪种方案要根据业务场景定,但"并发扣减必须加锁"这个原则不能变。

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

相关文章
|
2月前
|
前端开发 NoSQL 数据库
用户重复点了两次提交按钮?表单幂等设计与重复提交的一次真实排查
用户重复点两次提交按钮,后台收到几十条重复线索?根因十有八九是前端没做防重+后端没做幂等。本文从前端按钮状态、网关限流、后端幂等校验三层,完整复盘一次活动报名重复提交事故的排查与修复,附可复用的幂等代码和5条踩坑经验。
|
1月前
|
人工智能 缓存 安全
2026大模型网关体系解读:多模型共存时代的基础设施演进与选型逻辑
本文面向技术负责人与AI工程师,解析大模型网关的演进逻辑:从统一接口(可替换)到调度治理(可运营),再到Agent入口(可治理)。剖析多模型共存的四大动因及五大工程难题,厘清其在AI基础设施栈中的定位,并提供选型决策树与未来趋势洞察。(239字)
222 1
|
2月前
|
存储 人工智能 安全
阿里云国际代理商:云栖大会Agentic Cloud全解读 智能体从Demo到生产的工程化路径
本文介绍2026云栖大会上阿里云发布的Agentic Cloud战略:以智能体为中心的新型云架构,涵盖AI Native、Agent Native与Context Engine三层技术栈,并推出AgentCore、Agent Sandbox等生产级工具,推动AI从Demo迈向规模化落地。(239字)
|
1月前
|
人工智能 自然语言处理 数据可视化
阿里云百炼是什么?2026阿里云百炼AI模型官网与登录入口全解及功能介绍
阿里云百炼(Model Studio)是一站式AI大模型服务平台,支持通义千问及主流第三方模型,提供OpenAI兼容API、可视化智能体构建与工作流编排能力,助力企业快速开发、部署AI应用。(239字)
493 0
|
2月前
|
SQL 应用服务中间件 数据库
网站半夜突然开始大量502:Nginx超时、连接池耗尽与慢查询的全链路排查
网站半夜突然大量502,根因不在网关而在应用响应不过来。本文从Nginx错误日志、应用连接池状态、数据库慢查询三层,完整复盘一次40分钟定位的真实事故,附可复用的排查命令和5条踩坑经验。
|
20天前
|
人工智能 中间件 Java
LangChain 到底是什么:从链式连接到 Agent 运行时,讲透 v1.0 的核心概念
LangChain 是大模型应用开发框架,非单纯API封装。v1.0聚焦Agent工程化:以`create_agent`为核心,基于LangGraph实现可持久化、可中断、可观测的智能体循环;统一模型接口、强化工具描述、分层记忆管理,并通过中间件支持人工介入、摘要压缩与隐私脱敏,推动AI从“能跑”走向“可靠生产”。(239字)
287 1
|
24天前
|
JSON 编解码 API
ComfyUI 图生图底层拆解|SD 潜空间 Img2Img 工作流 + API 批量出图脚本
本文详解ComfyUI图生图底层原理与生产实践:从潜空间噪声扰动机制、denoise强度实操标尺,到纯原生节点链路、Python批量API调用脚本,覆盖OOM显存优化、ControlNet/IP-Adapter扩展及短剧漫剧落地方案,助力稳定高效批量出图。(239字)
315 2
|
27天前
|
Java Linux 开发工具
【保姆级】IDEA官网下载+安装+配置+使用教程(所有版本汇总,2026最新版)
IntelliJ IDEA 是 JetBrains 开发的主流 Java IDE,支持 Java、Kotlin、Spring 等开箱即用,提供智能代码分析、重构与调试。含免费社区版(适合学习/中小型项目)和付费 Ultimate 版(含微服务、数据库、远程开发等高级功能),全面支持 Windows/macOS/Linux。
|
30天前
|
Ubuntu Linux iOS开发
【保姆级】PowerShell下载和使用教程(所有版本汇总,2026最新实测)
PowerShell 是微软开发的跨平台命令行工具与脚本语言,支持 Windows、macOS 和 Linux。它采用“动词-名词”命名规范(如 Get-Process),功能强大:可管理系统、查询资源、批量操作、自动化运维,并支持管道、筛选、脚本编写与调试。当前主流版本为跨平台的 PowerShell 7.x(推荐 LTS 版),与系统自带的 Windows PowerShell 5.1 共存不冲突。(239 字)
|
1月前
|
人工智能 缓存 监控
2026年最新阿里云百炼Token Plan订阅配置价格表,套餐档位与Credits计费全解析
综合来看,百炼Token Plan将多模型、多工具整合到统一订阅套餐,Credits统一计费,相比单独按量调用,长期高频使用能够显著降低AI开发成本。个人开发者可以根据自身开发强度,从四档个人套餐中选择,团队多人协作场景,按岗位分配对应坐席,搭配共享用量包应对流量波动。在正式订阅之前,先用免费额度测试模型,评估日常调用消耗,再挑选匹配档位,避免套餐规格选择过高或者不足。合理利用额度监控,优化调用请求,能够最大化发挥订阅套餐的价值,稳定支撑AI智能体、代码开发、多模态创作等各类项目落地。
650 1