1. 项目背景与核心需求
HPV疫苗作为预防宫颈癌的重要手段,近年来接种需求呈现爆发式增长。但传统预约方式存在几个痛点:医院线下排队耗时费力、电话预约占线率高、第三方平台信息不透明。我们团队在实地调研了3家三甲医院后发现,平均每位用户需要尝试5-7次才能成功预约,其中68%的用户表示曾遭遇"秒光"情况。
这个基于微信小程序的解决方案主要解决三个核心问题:
- 信息不对称:整合区域疫苗库存数据,可视化展示可预约时段
- 公平性问题:采用智能排队算法防止黄牛刷单
- 操作便捷性:利用微信生态实现一键预约+支付闭环
提示:系统设计时要特别注意《疫苗流通和预防接种管理条例》第二十六条规定,必须确保预约信息与疾控系统实时同步。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 整体技术栈选型
前端采用微信小程序原生框架,相比uni-app等跨平台方案,原生框架在以下场景具有优势:
- 调用微信支付接口时无需额外适配层
- 能够直接使用最新的小程序直播组件(用于疫苗科普)
- 性能损耗降低约30%(经压测对比)
后端采用SpringBoot 2.7 + MyBatis-Plus组合,数据库使用MySQL 8.0。特别说明几个关键选型原因:
- 引入Redisson实现分布式锁,解决超卖问题(实测QPS 2000+场景下零失误)
- 采用Hutool工具包的Snowflake算法生成预约单号,避免UUID无序性导致的索引失效
- 使用Spring Schedule实现动态库存同步,与疾控中心API保持≤5秒延迟
2.2 微服务拆分策略
将系统拆分为三个微服务(实际开发中可根据团队规模调整):
| 服务模块 | 核心技术点 | QPS要求 |
|---|---|---|
| 预约核心服务 | Redis+Lua秒杀脚本 | 3000+ |
| 用户服务 | JWT+微信开放平台授权 | 1500 |
| 库存同步服务 | WebSocket长连接+断线重传机制 | 500 |
3. 核心功能实现细节
3.1 高并发预约设计
抢苗场景的典型技术挑战在于:
- 瞬时流量可能是平常的100倍以上
- 必须保证库存扣减的原子性
- 需要防止脚本恶意刷单
我们的解决方案包含四层防护:
- 前端层:增加图形验证码+滑动拼图二次验证
- 网关层:Nginx限流(单个IP 10次/分钟)
- 服务层:Redis预减库存+异步MQ扣减数据库
- 数据层:MySQL乐观锁+唯一索引防重
关键代码片段(Lua脚本实现库存原子操作):
lua复制local stock = tonumber(redis.call('GET', KEYS[1]))
if stock > 0 then
redis.call('DECR', KEYS[1])
return 1
end
return 0
3.2 智能排队算法
采用动态权重排队机制,考虑因素包括:
- 用户历史履约记录(爽约率)
- 属地优先原则(本地户籍加权)
- 特殊人群标识(孕妇、适龄女性等)
算法实现类结构:
java复制public class QueuePriority implements Comparable<QueuePriority> {
private String userId;
private double baseScore; // 基础分
private double dynamicWeight; // 动态权重
@Override
public int compareTo(QueuePriority o) {
return Double.compare(
this.baseScore * this.dynamicWeight,
o.baseScore * o.dynamicWeight
);
}
}
4. 数据库优化实践
4.1 表结构设计要点
核心表vaccine_appointment需要特别注意:
- 使用DATETIME(3)存储预约时间(精确到毫秒)
- 对(user_id, vaccine_id)建立联合唯一索引
- 采用TINYINT存储状态枚举值
sql复制CREATE TABLE `vaccine_appointment` (
`id` BIGINT NOT NULL COMMENT '雪花算法ID',
`user_id` VARCHAR(32) NOT NULL,
`vaccine_id` INT NOT NULL,
`appoint_time` DATETIME(3) NOT NULL,
`status` TINYINT DEFAULT 0 COMMENT '0-待支付 1-已预约 2-已取消',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_vaccine` (`user_id`,`vaccine_id`),
KEY `idx_status_time` (`status`,`appoint_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
4.2 查询优化案例
疫苗列表页面临的问题:
- 需要关联查询库存表、医疗机构表
- 筛选条件复杂(区域、疫苗类型、时间范围)
优化方案:
- 使用冗余字段存储医疗机构名称(避免连表)
- 对高频查询建立覆盖索引:
sql复制ALTER TABLE `vaccine_stock`
ADD INDEX `idx_cover_query` (`hospital_id`, `vaccine_type`, `stock_date`);
5. 异常处理与监控
5.1 典型异常场景
在压力测试中发现的三个关键问题:
- 微信支付回调延迟导致状态不一致
- 解决方案:增加补偿任务,每5分钟扫描待支付订单
- 疾控中心接口超时(平均响应时间>2s)
- 解决方案:本地缓存+异步更新策略
- 小程序端因网络抖动提交重复请求
- 解决方案:前端防重+服务端幂等设计
5.2 监控指标配置
使用Prometheus监控以下关键指标:
| 指标名称 | 告警阈值 | 应对措施 |
|---|---|---|
| appointment_api_latency | P99 > 500ms | 自动扩容+降级本地缓存 |
| payment_callback_failures | 连续5次失败 | 触发人工核查流程 |
| redis_connection_usage | >80%持续5分钟 | 告警通知+连接池调优 |
6. 部署与运维实践
6.1 容器化部署方案
采用Docker Compose编排以下服务:
yaml复制version: '3.8'
services:
app-service:
image: hpv-app:${TAG}
deploy:
resources:
limits:
cpus: '2'
memory: 2G
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 5s
retries: 3
redis:
image: redis:6.2-alpine
command: redis-server --requirepass ${REDIS_PASS}
6.2 灰度发布策略
通过Nginx配置实现按用户分流的灰度发布:
nginx复制split_clients "${arg_user_id}" $variant {
10% "v2";
* "v1";
}
location /api {
proxy_pass http://$variant_upstream;
}
7. 安全防护措施
7.1 防黄牛机制
除常规验证码外,我们还实现了:
- 行为分析引擎:检测异常点击模式(如固定间隔毫秒数)
- 设备指纹技术:通过wx.getSystemInfo生成设备特征码
- 预约冷却期:同一身份证号15天内限约1次
7.2 数据加密方案
敏感字段采用AES-GCM加密:
java复制public class CryptoUtil {
private static final String ALGORITHM = "AES/GCM/NoPadding";
public static String encrypt(String data, String key) {
// 实现细节省略...
}
}
8. 项目演进方向
在实际运行中,我们收集到用户的两个核心诉求:
- 预约结果预测:基于历史数据预测下次放号时间
- 智能提醒:在附近医院有苗时推送通知
下一步计划引入:
- 时序预测模型(Prophet算法)
- 地理位置围栏判断
- 小程序订阅消息模板优化
经验:在MySQL中存储地理坐标时,建议使用POINT类型并建立SPATIAL索引,查询效率比单独存经纬度提升5-8倍。
