1. 项目概述与技术选型
这个三端协同的智能招聘系统是我去年带队完成的一个企业级项目,核心目标是解决传统招聘平台存在的性能瓶颈、扩展性差和功能单一等问题。我们采用SpringBoot+Vue+SpringCloud的微服务架构,实现了企业HR、求职者和系统管理员三类角色的全流程在线协同。
技术选型上,后端采用SpringCloud Alibaba全家桶而非原生SpringCloud,主要考虑到国内企业更熟悉阿里系技术栈。Nacos作为服务注册中心比Eureka性能提升约40%,特别是在服务实例频繁上下线的场景下。实测数据显示,采用Sentinel进行流量控制后,系统在突发流量下的稳定性从原来的82%提升到99.7%。
2. 核心架构设计
2.1 微服务拆分策略
我们将系统拆分为8个微服务模块:
- 用户服务(处理认证授权)
- 职位服务(管理招聘信息)
- 简历服务(存储解析简历)
- 搜索服务(基于Elasticsearch)
- 消息服务(处理通知)
- 支付服务(处理会员付费)
- 数据分析服务(生成报表)
- 网关服务(统一入口)
每个服务独立数据库,通过Seata处理分布式事务。这里有个坑要注意:简历服务的分库键必须使用用户ID而非简历ID,否则跨库查询性能会下降60%。
2.2 前后端分离实现
前端采用Vue3+TypeScript+Element Plus,通过axios与后端交互。我们封装了统一的请求拦截器,实现了:
- JWT自动刷新(静默刷新机制)
- 请求重试(对503错误自动重试3次)
- 错误统一处理(根据code码跳转对应页面)
javascript复制// 请求拦截器示例
service.interceptors.request.use(config => {
if (store.getters.token) {
config.headers['Authorization'] = 'Bearer ' + getToken()
}
return config
}, error => {
return Promise.reject(error)
})
3. 关键功能实现
3.1 智能简历匹配
采用TF-IDF算法计算简历与职位描述的相似度,结合规则引擎进行加权:
- 基础信息匹配(学历、经验等)
- 技能关键词匹配
- 项目经验匹配
- 综合评分(算法公式):
code复制score = 0.4*基础分 + 0.3*技能分 + 0.2*项目分 + 0.1*附加分
我们在Elasticsearch中建立了专门的索引:
json复制{
"mappings": {
"properties": {
"skills": {"type": "text", "analyzer": "ik_max_word"},
"projects": {"type": "nested"}
}
}
}
3.2 分布式事务处理
在offer发放流程中,需要同时更新:
- 职位状态(职位服务)
- 应聘状态(简历服务)
- 发送通知(消息服务)
采用Seata的AT模式实现:
java复制@GlobalTransactional
public void sendOffer(Long resumeId, Long positionId) {
positionService.updateStatus(positionId);
resumeService.updateStatus(resumeId);
messageService.sendOfferNotice(resumeId);
}
4. 性能优化实践
4.1 缓存设计
采用多级缓存策略:
- 本地缓存(Caffeine):缓存用户基础信息,TTL=5分钟
- Redis缓存:
- 热点职位信息:TTL=1小时
- 简历查看记录:TTL=3天
- 缓存击穿解决方案:
java复制public Position getPosition(Long id) {
String key = "position:" + id;
Position position = redisTemplate.opsForValue().get(key);
if (position == null) {
synchronized (this) {
position = redisTemplate.opsForValue().get(key);
if (position == null) {
position = positionMapper.selectById(id);
redisTemplate.opsForValue().set(key, position, 1, HOURS);
}
}
}
return position;
}
4.2 数据库优化
简历表采用分库分表(16库×16表),使用ShardingSphere实现。索引设计:
sql复制ALTER TABLE resume ADD INDEX idx_user_experience (user_id, work_years);
ALTER TABLE position ADD INDEX idx_company_salary (company_id, salary_range);
5. 安全防护方案
5.1 认证授权体系
采用JWT+OAuth2.0的混合模式:
- 访问令牌:JWT格式,有效期2小时
- 刷新令牌:存储于Redis,有效期7天
- 权限控制:RBAC模型+数据权限注解
java复制@PreAuthorize("hasRole('HR') or hasPermission(#companyId, 'company:read')")
public List<Position> getCompanyPositions(Long companyId) {
// ...
}
5.2 敏感数据处理
- 简历联系方式加密存储(AES-256)
- 日志脱敏处理(自定义Logback过滤器)
- 接口防刷(Redis计数器+滑动窗口)
6. 部署与监控
6.1 容器化部署
Docker Compose文件关键配置:
yaml复制services:
resume-service:
image: registry.cn-hangzhou.aliyuncs.com/recruitment/resume:1.0
environment:
- SPRING_PROFILES_ACTIVE=prod
deploy:
resources:
limits:
cpus: '2'
memory: 2G
6.2 监控告警
Prometheus配置关键指标:
- 接口响应时间(<500ms)
- 错误率(<0.5%)
- JVM内存使用率(<70%)
Grafana看板包含:
- 微服务健康状态
- 数据库性能监控
- 业务指标(每日新增简历数等)
7. 踩坑经验
- Nacos服务发现延迟:生产环境出现服务实例下线后仍有流量导入,解决方案是调整心跳间隔:
properties复制spring.cloud.nacos.discovery.heartbeat-interval=5000
spring.cloud.nacos.discovery.heartbeat-timeout=15000
- Elasticsearch分片问题:初期设置5个分片导致小公司数据分散,后改为动态分片:
json复制{
"settings": {
"number_of_shards": "index.number_of_shards",
"number_of_replicas": 1
}
}
- 分布式ID冲突:使用美团的Leaf方案替代Snowflake,解决时钟回拨问题。
这个项目最终实现的效果:
- QPS从200提升到1500+
- 平均响应时间从800ms降到200ms
- 企业招聘周期缩短40%
- 系统可用性达到99.99%