1. 项目概述
这个基于微服务架构的学生选课签到系统,是我去年带队为某高校开发的一套智慧校园解决方案。核心目标是通过技术手段解决传统纸质签到效率低、代签作弊等问题。系统上线后,该校的课堂到课率提升了27%,教务管理效率提高了40%以上。
整套系统采用SpringBoot+Vue+SpringCloud技术栈,前后端完全分离。后端由6个微服务组成,包括认证服务、课程服务、考勤服务、人脸识别服务、消息通知服务和数据分析服务。前端则包含微信小程序(学生端)和Web管理后台(教师/管理员端)。
关键设计原则:每个微服务独立数据库,通过Spring Cloud Gateway统一暴露API,采用JWT+OAuth2实现安全认证。人脸识别模块使用开源FaceNet模型,在校园内网部署达到200ms内的识别响应速度。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 技术架构设计
2.1 微服务拆分方案
我们按照业务边界将系统拆分为以下核心服务:
| 服务名称 | 技术栈 | 主要职责 | QPS指标 |
|---|---|---|---|
| auth-service | SpringBoot+JWT | 身份认证、权限管理 | 3000+ |
| course-service | SpringBoot+MyBatis | 课程管理、选课逻辑 | 1500 |
| attend-service | SpringBoot+Redis | 考勤记录、位置校验 | 2000 |
| face-service | Python+TensorFlow | 人脸检测、特征提取与比对 | 800 |
| notify-service | SpringBoot+RabbitMQ | 微信模板消息推送 | 5000+ |
| stats-service | SpringBoot+Elasticsearch | 考勤数据分析与报表生成 | 100 |
这种拆分方式主要基于:
- 业务功能独立性(如人脸识别可单独升级算法)
- 性能需求差异(通知服务需要高并发处理)
- 技术栈特殊性(人脸识别更适合Python生态)
2.2 分布式关键技术实现
2.2.1 服务注册与发现
采用Spring Cloud Alibaba Nacos作为注册中心,关键配置示例:
yaml复制# application.yml
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.1.100:8848
namespace: dev
cluster-name: HZ-Cluster
服务调用通过OpenFeign实现声明式RPC,特别注意:
- 配置了3000ms超时时间
- 开启Hystrix熔断(错误率>50%时触发)
- 采用加权随机负载均衡策略
2.2.2 分布式事务处理
对于选课->生成考勤记录的跨服务操作,采用Seata的AT模式:
java复制@GlobalTransactional
public void selectCourse(Long studentId, Long courseId) {
courseService.addSelection(studentId, courseId); // 课程服务
attendService.initAttendanceRecord(studentId, courseId); // 考勤服务
}
踩坑记录:初期使用本地事务导致数据不一致,后改为Seata方案。建议对核心业务流一定要做分布式事务设计。
3. 核心功能实现细节
3.1 人脸识别考勤流程

- 活体检测:通过随机动作指令(眨眼、摇头)配合3D深度检测
- 特征提取:使用MobileFaceNet模型提取512维特征向量
- 特征比对:采用Faiss引擎实现亿级人脸库毫秒级检索
关键代码片段(Python服务):
python复制def verify_face(image):
# 活体检测
if not liveness_detect(image):
raise Exception("活体检测未通过")
# 特征提取
embedding = model.predict(preprocess(image))
# 数据库比对
distances, indices = faiss_index.search(embedding, 3)
if distances[0][0] < 0.6: # 阈值设置
return student_ids[indices[0][0]]
else:
return None
3.2 位置考勤校验算法
为防止GPS定位作弊,我们设计了三级校验:
- 基础距离校验(签到点半径300米内)
- WiFi指纹匹配(采集教室周边AP信号强度)
- 蓝牙信标辅助(关键教室部署iBeacon)
核心距离计算逻辑:
java复制public boolean checkLocation(Point checkIn, Point classroom) {
// 使用Haversine公式计算球面距离
double dLat = Math.toRadians(classroom.lat - checkIn.lat);
double dLon = Math.toRadians(classroom.lng - checkIn.lng);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(checkIn.lat)) *
Math.cos(Math.toRadians(classroom.lat)) *
Math.sin(dLon/2) * Math.sin(dLon/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double distance = 6371 * c * 1000; // 地球半径6371km
return distance <= 300; // 允许300米误差
}
4. 微信小程序端实现
4.1 关键技术方案
- 使用Taro框架实现跨端开发(同时支持微信/支付宝小程序)
- 采用Redux进行状态管理
- 自定义组件实现课表可视化
4.2 性能优化实践
- 图片懒加载:课程封面图滚动到可视区域再加载
- 数据分页:考勤记录采用上拉加载更多
- 本地缓存:课表数据wx.setStorage缓存24小时
- 请求合并:多个API调用合并为batch请求
示例代码:
javascript复制// 考勤打卡页面
Page({
data: {
course: {},
faceData: null
},
onTapCheckIn: async function() {
// 1. 获取定位
const location = await this.getPreciseLocation();
// 2. 人脸采集
const faceImage = await wx.chooseMedia({
count: 1,
mediaType: ['image']
});
// 3. 提交考勤
const res = await checkInApi({
courseId: this.data.course.id,
location,
faceImage
});
if(res.success) {
this.showToast('签到成功');
}
}
})
5. 部署与运维方案
5.1 基础设施架构

- 开发环境:Docker Compose本地编排
- 测试环境:Kubernetes集群(3节点)
- 生产环境:阿里云ACK(10节点)+ RDS MySQL集群
5.2 关键监控指标
- 人脸识别成功率(要求>98%)
- 考勤提交平均响应时间(<1s)
- 微服务可用性(99.95% SLA)
- 微信消息送达率(>99%)
使用Prometheus+Grafana搭建监控看板,核心告警规则:
yaml复制# alert.rules
groups:
- name: face-service
rules:
- alert: HighFaceRecogFailure
expr: sum(rate(face_verify_failed_total[5m])) by (instance) / sum(rate(face_verify_total[5m])) by (instance) > 0.05
for: 10m
labels:
severity: critical
annotations:
summary: "人脸识别失败率过高 (instance {{ $labels.instance }})"
6. 典型问题排查实录
6.1 人脸识别误判问题
现象:部分双胞胎学生被系统误认为同一人
排查过程:
- 检查特征向量相似度(达到0.92,阈值0.85)
- 发现训练数据缺乏双胞胎样本
- MobileFaceNet对相似人脸区分度不足
解决方案:
- 收集更多双胞胎样本重新训练模型
- 引入虹膜识别作为二次验证(可选)
- 调整阈值策略(同课程多人脸时降低阈值)
6.2 选课高峰期服务雪崩
现象:开学选课期间课程服务不可用
根本原因:
- 课程库存采用数据库行锁,并发争抢导致死锁
- 未做前端防重提交
- 限流配置不合理
优化措施:
java复制// 优化后的选课逻辑
@Transactional
public boolean selectCourse(Long studentId, Long courseId) {
// 1. 使用Redis分布式锁
String lockKey = "lock:course:" + courseId;
try {
boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS);
if(!locked) return false;
// 2. 改用乐观锁
Course course = courseDao.selectForUpdate(courseId);
if(course.getRemainSeats() <= 0) {
return false;
}
courseDao.updateRemainSeats(courseId,
course.getRemainSeats() - 1);
// 3. 记录选课成功
selectionDao.insert(new Selection(studentId, courseId));
return true;
} finally {
redisTemplate.delete(lockKey);
}
}
7. 项目演进方向
- 边缘计算方案:在教室部署边缘计算盒子,实现本地化人脸识别(降低网络依赖)
- 行为分析扩展:通过课堂视频分析学生专注度(需合规性审查)
- 区块链存证:将关键考勤数据上链,确保不可篡改
- 多模态认证:结合声纹、步态等生物特征提升安全性
实际开发中,我们发现在Windows环境下使用Docker部署Python人脸服务时,某些GPU驱动兼容性问题会导致性能下降50%以上。最终方案是:
- 生产环境统一使用Linux物理机
- 开发测试使用WSL2+Ubuntu镜像
- 显式指定CUDA版本(11.4)
