1. 项目概述
这个基于SpringCloud和Vue3的作品投票系统是一个典型的分布式微服务应用,采用了前后端分离的架构设计。作为一名长期从事企业级应用开发的工程师,我认为这种架构非常适合需要高并发、高可用的投票类场景。
系统核心功能包括:
- 作品展示与投票
- 实时数据统计与可视化
- 用户认证与权限管理
- 智能推荐与预警机制
在实际开发中,我们特别注重系统的三个特性:
- 响应速度:通过Redis缓存和WebSocket技术确保投票结果的实时性
- 安全性:采用JWT+SpringSecurity的认证方案
- 可扩展性:微服务架构使得各功能模块可以独立部署和扩展
2. 技术架构设计
2.1 后端技术栈
SpringCloud微服务全家桶是我们的核心选择:
- Eureka:服务注册与发现,实测单节点可支撑500+服务实例
- Feign:声明式服务调用,相比RestTemplate减少30%代码量
- Hystrix:熔断降级,当投票服务QPS超过1000时自动降级
- Gateway:API网关,统一处理跨域和权限校验
数据库选型方面:
sql复制CREATE TABLE `vote_record` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`work_id` bigint(20) NOT NULL COMMENT '作品ID',
`user_id` bigint(20) NOT NULL COMMENT '用户ID',
`vote_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_work` (`user_id`,`work_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
这个表结构设计确保了用户对同一作品只能投票一次。
2.2 前端技术栈
Vue3的组合式API大幅提升了代码组织效率:
javascript复制// 投票逻辑封装
const useVote = () => {
const voteCount = ref(0);
const isVoted = ref(false);
const submitVote = async (workId) => {
try {
await api.vote(workId);
voteCount.value++;
isVoted.value = true;
} catch (err) {
console.error('投票失败', err);
}
};
return { voteCount, isVoted, submitVote };
};
3. 核心功能实现
3.1 分布式投票防重
我们采用Redisson分布式锁解决高并发下的重复投票问题:
java复制public VoteResult vote(Long workId, Long userId) {
String lockKey = "vote_lock:" + workId + ":" + userId;
RLock lock = redissonClient.getLock(lockKey);
try {
boolean locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
if (locked) {
// 检查是否已投票
if (voteMapper.existsByUserAndWork(userId, workId)) {
return VoteResult.fail("您已经投过票了");
}
// 执行投票逻辑
voteMapper.insert(new VoteRecord(workId, userId));
return VoteResult.success();
}
} finally {
lock.unlock();
}
}
3.2 实时统计实现
统计服务采用Redis的HyperLogLog进行UV统计:
java复制public void addVoteStat(Long workId) {
String today = LocalDate.now().toString();
// PV统计
redisTemplate.opsForValue().increment("vote:pv:" + workId);
// UV统计
redisTemplate.opsForHyperLogLog().add("vote:uv:" + workId + ":" + today, userId);
}
前端通过WebSocket接收实时更新:
javascript复制const socket = new WebSocket('wss://yourdomain.com/vote-ws');
socket.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === 'vote_update') {
updateChart(data.works);
}
};
4. 性能优化实践
4.1 缓存策略
我们设计了三级缓存体系:
- 本地缓存(Caffeine):缓存用户基础信息,TTL=5分钟
- Redis缓存:存储热门作品数据,TTL=1小时
- MySQL:持久化存储所有数据
缓存更新采用双删策略:
java复制public void updateWorkInfo(Work work) {
// 先更新数据库
workMapper.updateById(work);
// 删除缓存
redisTemplate.delete("work:" + work.getId());
// 延迟再删一次
executor.schedule(() -> {
redisTemplate.delete("work:" + work.getId());
}, 1, TimeUnit.SECONDS);
}
4.2 数据库优化
针对投票记录表做了以下优化:
- 按月分表:vote_record_202301、vote_record_202302等
- 建立复合索引:(user_id, work_id)
- 使用ClickHouse作为统计分析的列式存储
5. 安全防护措施
5.1 认证授权体系
JWT令牌包含以下claims:
json复制{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022,
"exp": 1516242622,
"roles": ["USER"],
"perms": ["vote:create", "vote:list"]
}
SpringSecurity配置关键点:
java复制@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.antMatchers("/api/vote/**").hasAuthority("vote:create")
.anyRequest().authenticated()
.and()
.addFilter(new JwtAuthenticationFilter(authenticationManager()))
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
5.2 防刷机制
我们实现了基于滑动窗口的限流:
java复制@RateLimiter(value = 10, key = "#userId") // 10次/分钟
@PostMapping("/vote")
public Result vote(@RequestParam Long workId, @RequestHeader Long userId) {
return voteService.vote(workId, userId);
}
6. 智能推荐系统
6.1 协同过滤实现
ItemCF算法核心代码:
python复制def item_similarity(train):
# 计算物品共现矩阵
cooccur = defaultdict(lambda: defaultdict(int))
item_user_count = defaultdict(int)
for user, items in train.items():
for i in items:
item_user_count[i] += 1
for j in items:
if i == j:
continue
cooccur[i][j] += 1
# 计算相似度矩阵
sim = defaultdict(dict)
for i, related_items in cooccur.items():
for j, cij in related_items.items():
sim[i][j] = cij / math.sqrt(item_user_count[i] * item_user_count[j])
return sim
6.2 随机森林优化
特征工程包含:
- 用户历史投票记录
- 作品标签匹配度
- 时间衰减因子
- 社交关系权重
7. 部署与监控
7.1 容器化部署
Docker Compose配置示例:
yaml复制version: '3'
services:
eureka-server:
image: springcloud-eureka
ports:
- "8761:8761"
vote-service:
image: vote-service
environment:
- EUREKA_CLIENT_SERVICEURL_DEFAULTZONE=http://eureka-server:8761/eureka
depends_on:
- eureka-server
7.2 监控方案
我们采用Prometheus+Grafana监控体系:
- JVM指标:GC次数、堆内存使用
- 微服务指标:接口QPS、平均耗时
- 系统指标:CPU、内存、磁盘
- 业务指标:实时投票数、UV/PV
8. 踩坑经验分享
- Feign超时问题:生产环境需要调整默认超时时间
yaml复制feign:
client:
config:
default:
connectTimeout: 5000
readTimeout: 30000
- Redis序列化异常:推荐使用GenericJackson2JsonRedisSerializer
java复制@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
return template;
}
- Vue3响应式丢失:解构props需要使用toRefs
javascript复制const props = defineProps(['workInfo']);
const { title, author } = toRefs(props.workInfo);
这个项目从架构设计到具体实现涉及了现代Web开发的诸多关键技术点,特别是在高并发场景下的解决方案值得深入探讨。在实际开发中,建议先搭建好监控体系再上线,这样可以快速定位性能瓶颈。