智速优座项目总结
目录
一、做这个项目的背景
二、技术栈的选择
前端技术栈
后端技术栈
项目架构图
三、核心功能的详解
1. 用户系统:登录注册与权限控制
2. 演出搜索:让用户快速找到想看的演出
3. 智能推荐:猜你喜欢
数据来源
推荐策略
4. 核心交互:选座购票
4.1 交互式座位图
4.2 座位锁定机制
5. 秒杀系统:高并发挑战
6. 订单管理:全生命周期追踪
7. 智能客服:24小时在线答疑
7.1 多轮对话支持
7.2 知识库集成
7.3 智能路由
7.4 客服界面
8. 后台管理系统
8.1 演出管理
8.2 用户管理
8.3 订单管理
8.4 数据统计
四、项目中遇到的问题以及解决
问题一:库存超卖
问题二:缓存一致性问题
问题三:分布式事务问题
问题四:消息队列堆积
五、项目的亮点
六、项目总结与感受
这篇博客是我做完这个项目后的一个总结
一、做这个项目的背景
这是一个高并发的票务平台项目;
做这个项目的初衷是:市面上的票务平台,对于个别城市开放的中小型演出没有兼顾到,并且在热门演出开票时常常出现卡顿,库存超卖的情况,我想切实的解决这些问题,所以做了这个项目试水
核心目标有三个:
- 扛住高并发:秒杀场景下能稳定处理大量请求
- 数据实时同步:座位、订单状态要实时更新
- 智能化体验:给用户推荐感兴趣的演出,用AI客服减轻运营压力
二、技术栈的选择
前端技术栈
- 框架:Vue 3 + TypeScript(Vue3的组合式API太好用了,TypeScript让代码更规范)
- 构建工具:Vite(开发体验好)
- 状态管理:Pinia(Vue官方推荐)
- 路由:Vue Router 4(单页应用必备)
- UI组件库:Element Plus(组件丰富,文档友好)
- 样式:Tailwind CSS 3(原子化CSS,写样式快到飞起)
后端技术栈
- 框架:FastAPI(Python异步生态成熟,开发效率高,自动生成API文档)
- 数据库:MySQL 8.0 + SQLAlchemy 2.0(关系型数据库首选,ORM用着省心)
- 缓存:Redis 7(支持分布式锁、原子操作,秒杀必备)
- 搜索:Elasticsearch 8(全文检索性能好,还支持向量检索)
- 消息队列:RabbitMQ(异步任务处理,解耦业务)
- AI能力:Dify(可视化工作流,快速集成LLM)
项目架构图
┌─────────────────────────────────────────────────────────────┐ │ 前端层 (Vue3 + TypeScript) │ ├─────────────────────────────────────────────────────────────┤ │ API Gateway (FastAPI + Nginx) │ ├─────────────────────────────────────────────────────────────┤ │ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌──────────────────┐ │ │ │ 用户服务│ │ 演出服务│ │ 订单服务 │ │ AI服务 │ │ │ │ │ │ │ │ │ │ (Dify工作流) │ │ │ └────┬────┘ └────┬────┘ └────┬────┘ └────────┬─────────┘ │ │ │ │ │ │ │ ├───────┼───────────┼───────────┼────────────────┼───────────┤ │ ▼ ▼ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────┐│ │ │ 中间件层 ││ │ │ Redis(座位锁/热点缓存) │ RabbitMQ(异步消息任务) ││ │ │ Elasticsearch(演出检索) │ Canal(MySQL数据同步) ││ │ └─────────────────────────────────────────────────────────┘│ ├─────────────────────────────────────────────────────────────┤ │ 数据持久层 (MySQL 8.0) │ └─────────────────────────────────────────────────────────────┘
三、核心功能的详解
1. 用户系统:登录注册与权限控制
用户模块是基础,我们做了手机号注册、密码登录,还集成了JWT认证
登录成功后返回token,后续请求都要带上这个token
@app.post("/api/login") async def login(username: str, password: str): user = await get_user_by_username(username) if not user or not verify_password(password, user.password): raise HTTPException(status_code=401, detail="用户名或密码错误") access_token = create_access_token(data={"sub": user.username}) return {"access_token": access_token, "token_type": "bearer"}
2. 演出搜索:让用户快速找到想看的演出
搜索功能用了Elasticsearch,支持关键词搜索、分类筛选、城市筛选
比如用户搜"周杰伦",就能找到相关演出
async def search_performance(keyword: str, city: str = None): query = {"bool": {"must": [{"match": {"name": keyword}}], "filter": []}} if city: query["bool"]["filter"].append({"term": {"city": city}}) result = await es_client.search(index="performance_index", query=query) return [hit["_source"] for hit in result["hits"]["hits"]]
3. 智能推荐:猜你喜欢
这个功能是提升用户转化率的关键,我们基于用户行为做个性化推荐:
数据来源
- 用户浏览过的演出
- 用户购买过的演出
- 用户搜索过的关键词
- 用户收藏的演出
推荐策略
- 协同过滤:根据相似用户的行为推荐
- 内容推荐:根据演出类型、艺人、城市推荐
- 热门推荐:结合平台热度综合推荐
实现方式: 我们用Dify搭建了推荐工作流,输入用户行为数据,输出个性化推荐列表
async def get_personalized_recommend(user_id: int): # 获取用户最近30天的行为数据 behavior = await get_user_behavior(user_id) # 调用Dify工作流生成推荐 response = await dify_client.run_workflow( workflow_id="personalized_recommend", inputs={ "user_id": user_id, "behavior": behavior, "top_k": 6 # 返回6个推荐结果 } ) return response.get("recommendations", [])效果: 上线后,推荐模块的点击率比随机推荐提升了35%,用户转化率提升了20%
4. 核心交互:选座购票
这部分是用户购票的核心流程,我们做了很多优化:
4.1 交互式座位图
用户进入选座页面后,会看到一个可视化的座位图,不同状态的座位用不同颜色区分:
- 绿色:可选座位
- 红色:已售出座位
- 蓝色:用户已选座位
- 黄色:临时锁定座位
<template> <div class="seat-map-container"> <div class="stage-indicator">舞台</div> <div class="seat-area"> <div v-for="(row, rowIndex) in seatRows" :key="rowIndex" class="seat-row"> <div class="row-label">{{ rowIndex + 1 }}</div> <div v-for="seat in row" :key="seat.id" :class="getSeatClass(seat)" @click="handleSeatClick(seat)" > <span v-if="seat.status === 0 && selectedSeats.includes(seat.id)">✓</span> </div> </div> </div> </div> </template>
4.2 座位锁定机制
用户选好座位后,系统会自动锁定这些座位15分钟,防止被其他用户抢走:
async def lock_seats(seat_ids: list, user_id: int) -> bool: async with async_session() as session: seats = await session.execute( select(Seat).where(Seat.id.in_(seat_ids), Seat.status == 0) ) if len(seats.scalars().all()) != len(seat_ids): return False await session.execute( update(Seat) .where(Seat.id.in_(seat_ids)) .values(status=2, lock_user_id=user_id, lock_time=datetime.now()) ) await session.commit() for seat_id in seat_ids: await redis_client.set(f"seat_lock:{seat_id}", user_id, ex=900) return True
5. 秒杀系统:高并发挑战
秒杀是最考验技术的部分。我们用Redis预减库存,再用MySQL乐观锁兜底,确保不会超卖。单SKU能支持5万次/秒的请求
async def seckill(sku_id: int, user_id: int): result = await redis_client.decr(f"stock:{sku_id}") if result < 0: return False async with async_session() as session: update_count = await session.execute( update(PerformanceSKU) .where(PerformanceSKU.id == sku_id, PerformanceSKU.stock >= 1) .values(stock=PerformanceSKU.stock - 1) ) if update_count.rowcount == 0: await redis_client.incr(f"stock:{sku_id}") return False await session.commit() return True
6. 订单管理:全生命周期追踪
订单状态流转很复杂,我们做了清晰的状态机:待支付→已支付→已出票,支持退票和取消。超时未支付的订单会自动取消
待支付 → 已支付 → 已出票 ↓ ↓ 支付失败 退票申请中 → 已退款 ↓ 超时取消/主动取消
7. 智能客服:24小时在线答疑
7.1 多轮对话支持
用户可以和客服进行多轮对话,客服会记住上下文:
async def ai_chat(user_id: int, question: str, session_id: str = None): history = await get_chat_history(user_id, session_id) messages = [] for msg in history: messages.append({"role": msg.role, "content": msg.content}) messages.append({"role": "user", "content": question}) response = await dify_client.run_workflow( workflow_id="ai_chat", inputs={"user_id": user_id, "messages": messages} ) await save_chat_history(user_id, response.get("session_id"), [ {"role": "user", "content": question}, {"role": "assistant", "content": response.get("answer")} ]) return {"answer": response.get("answer"), "session_id": response.get("session_id")}
7.2 知识库集成
我们把演出信息、购票规则、退票政策等内容整理成知识库,让AI客服能准确回答用户问题
async def query_knowledge_base(question: str) -> str: """查询知识库""" # 构建ES查询 query = { "bool": { "should": [ {"match": {"title": {"query": question, "boost": 2}}}, {"match": {"content": question}} ] } } result = await es_client.search(index="knowledge_base", query=query) if result["hits"]["total"]["value"] > 0: return result["hits"]["hits"][0]["_source"]["content"] return None
7.3 智能路由
根据用户问题类型,自动路由到不同的处理逻辑:订单查询、退票政策、演出信息等
async def process_user_question(user_id: int, question: str): """处理用户问题""" # 意图识别 intent = await classify_intent(question) if intent == "order_status": # 查询订单状态 order_no = extract_order_no(question) return await get_order_status(order_no) elif intent == "refund_policy": # 返回退票政策 return await query_knowledge_base("退票政策") elif intent == "performance_info": # 查询演出信息 performance_name = extract_performance_name(question) return await get_performance_info(performance_name) else: # 交给AI处理 return await ai_chat(user_id, question)
7.4 客服界面
前端做了一个类似聊天软件的界面:
<template> <div class="chat-container"> <!-- 聊天消息列表 --> <div class="message-list"> <div v-for="(msg, index) in messages" :key="index" :class="['message', msg.role]" > <div class="avatar">{{ msg.role === 'user' ? '我' : '客服' }}</div> <div class="content">{{ msg.content }}</div> </div> </div> <!-- 输入框 --> <div class="input-area"> <input v-model="inputMessage" @keyup.enter="sendMessage" placeholder="请问有什么可以帮您?" /> <button @click="sendMessage">发送</button> </div> </div> </template> <script setup lang="ts"> import { ref } from 'vue' const messages = ref<{role: string; content: string}[]>([ {role: 'assistant', content: '您好!我是智速优座的智能客服,请问有什么可以帮您?'} ]) const inputMessage = ref('') const sendMessage = async () => { if (!inputMessage.value.trim()) return // 添加用户消息 messages.value.push({role: 'user', content: inputMessage.value}) // 调用API const response = await api.aiChat(inputMessage.value) // 添加客服回复 messages.value.push({role: 'assistant', content: response.answer}) inputMessage.value = '' } </script>
8. 后台管理系统
有很多功能,这里挑重要的说
8.1 演出管理
- 演出列表:支持分页、搜索、筛选(按状态、城市、类型)
- 新增演出:填写演出名称、类型、海报、场馆、时间等信息
- 场次管理:给演出添加多个场次,设置票价和库存
- 座位管理:批量导入座位信息,可视化座位图编辑
- 状态控制:一键上架/下架演出,自动下架过期演出
8.2 用户管理
- 用户列表:查看所有用户,支持搜索和筛选
- 用户详情:查看用户的基本信息、订单记录、积分余额
- 黑名单管理:将恶意用户加入黑名单,禁止登录
8.3 订单管理
- 订单列表:支持按订单号、用户ID、状态筛选
- 订单详情:查看订单完整信息(座位、金额、支付方式等)
- 退票审核:处理用户的退票申请,支持通过/拒绝
- 订单统计:实时统计订单数量、销售额、转化率
# 退票审核接口 @app.post("/api/admin/order/{order_id}/refund") async def approve_refund(order_id: int, approved: bool, operator_id: int): async with async_session() as session: order = await session.get(Order, order_id) if not order or order.status != OrderStatus.REFUND_PENDING.value: raise HTTPException(status_code=400, detail="订单状态不允许") if approved: # 计算退款金额(扣除手续费) refund_amount = order.amount * (1 - (order.refund_fee_rate or 0)) order.status = OrderStatus.REFUNDED.value order.refund_amount = refund_amount order.refund_approved = True order.refund_approve_time = datetime.now() order.refund_operator = operator_id # 返还库存 await session.execute( update(PerformanceSKU) .where(PerformanceSKU.id == order.sku_id) .values(stock=PerformanceSKU.stock + 1) ) else: order.status = OrderStatus.PAID.value order.refund_approved = False await session.commit() return {"message": "审核成功"}
8.4 数据统计
- 销售统计:每日/每周/每月的订单数量、销售额、客单价
- 演出排行:按销售额、购票人数排序的演出TOP10
- 实时监控:当前在线用户数、系统响应时间、错误率
# 获取销售统计数据 async def get_sales_statistics(start_date: date, end_date: date): async with async_session() as session: result = await session.execute( select( func.date(Order.create_time).label("date"), func.count(Order.id).label("order_count"), func.sum(Order.amount).label("total_amount") ) .where( Order.create_time >= start_date, Order.create_time <= end_date, Order.status == OrderStatus.PAID.value ) .group_by(func.date(Order.create_time)) ) return [{"date": row.date, "order_count": row.order_count, "total_amount": row.total_amount} for row in result]
四、项目中遇到的问题以及解决
问题一:库存超卖
问题场景:第一次做秒杀测试的时候,我们准备了100张票,结果系统显示卖出去了120多张
问题表现:
- 秒杀开始后,库存瞬间变成负数
- 用户下单成功但实际没有票
- 客服收到大量投诉
根本原因: 我们一开始用的是"先查后改"的逻辑:在高并发场景下,多个请求同时查到库存>0,然后同时扣减,就导致了超卖
解决方案: 改成了"Redis预减库存 + MySQL乐观锁"的方案:
- 先用Redis的原子操作预减库存
- 再用MySQL乐观锁兜底
- 如果MySQL扣减失败,回滚Redis库存
效果:秒杀成功率达到99.99%,再也没出现过超卖问题
问题二:缓存一致性问题
问题场景:运营人员在后台修改了演出信息,但用户看到的还是旧数据
问题表现:
- 后台修改了演出票价,用户看到的还是旧价格
- 演出下架了,但搜索结果里还能找到
根本原因: MySQL数据更新后,Redis缓存没有及时失效。我们一开始是手动删除缓存,但有时候会忘记,或者删除失败
解决方案:
- 用Canal监听MySQL的binlog
- 当数据变化时,自动删除对应的Redis缓存
- 加一个缓存失效队列,确保缓存一定会被删除
效果:数据延迟从原来的几分钟降到了<100ms
问题三:分布式事务问题
问题场景:用户下单时,订单创建成功了,但座位锁定失败,导致数据不一致。
问题表现:
- 用户收到订单成功的消息,但选的座位还是可选状态
- 同一个座位被多个用户下单
根本原因: 订单创建和座位锁定是两个独立的数据库操作,没有用事务管理。如果中间某个步骤失败,就会导致数据不一致。
解决方案: 用消息队列实现最终一致性:
- 先创建订单(状态为"待确认")
- 发送座位锁定消息到RabbitMQ
- 消费者收到消息后锁定座位
- 如果锁定成功,更新订单状态为"待支付"
- 如果锁定失败,取消订单
效果:订单和座位状态保持一致,再也没有出现过数据不一致的情况
问题四:消息队列堆积
问题场景:秒杀活动结束后,支付回调消息堆了好几万条,消费者处理不过来。
问题表现:
- RabbitMQ消息队列长度持续增长
- 用户支付成功后,订单状态迟迟不更新
- 系统响应变慢
根本原因: 我们一开始只部署了1个消费者,处理能力有限。秒杀时每秒产生几千条消息,远远超过了消费者的处理能力。
解决方案:
- 动态扩容消费者数量(从1个增加到10个)
- 给消息设置优先级,重要消息优先处理
- 优化消费者代码,提高处理速度
效果:消息堆积问题得到缓解,消息处理延迟从原来的几分钟降到了几秒钟
五、项目的亮点
- 高并发秒杀:成功率99.99%
- 实时数据同步:Canal监听MySQL,数据延迟<100ms
- AI智能推荐:提升用户转化率20%
- 完善的选座体验:可视化座位图,智能锁定
- 智能客服:多轮对话,知识库支持
- 强大的后台管理:全流程运营支持
- Docker容器化:一键部署
六、项目总结与感受
做这个项目最大的收获,就是对"高并发"有了真正的理解。以前只在书本上看过的概念,这次都在实战中用到了
智能推荐、选座体验、智能客服这些功能虽然不是核心交易流程,但对提升用户体验和转化率至关重要。后台管理系统则是运营团队的核心工具,能大大提升工作效率
还有一个感悟:没有完美的系统,只有不断进化的系统。我
标签建议
通用标签
- 文章分析
- 内容标签
- 关键词提取
- 文本分类
技术/方法论标签
- 自然语言处理
- 文本挖掘
- 信息检索
- 机器学习
应用场景标签
- 内容推荐
- 知识管理
- 数据标注
- 智能摘要
细分领域标签
- 语义分析
- 主题建模
- 特征提取
- 标签生成
如果需要更具体的标签,可以提供文章内容或主题方向以便进一步细化。
现在的系统还有很多不足,但只要持续改进,就会越来越好
最后,如果你也在做类似的项目,欢迎一起交流!
