1. 项目概述
去年这个时候,我们团队负责的XX服务正式上线了。作为核心开发成员之一,我完整经历了从架构设计到上线的全过程,也见证了这一年来的各种起起落落。今天想用这篇长文记录下这段难忘的经历,既是对过去工作的复盘,也希望能给正在做类似项目的同行一些参考。
这个服务本质上是一个面向B端客户的XX系统,主要解决的是XX行业中的XX问题。上线初期日活只有几百,现在已经稳定在5万+。看似简单的数字背后,是无数个加班调试的夜晚和无数次紧急修复的经历。
2. 技术架构演进
2.1 初始架构设计
最初版本采用的是经典的三层架构:
- 前端:Vue.js + Element UI
- 后端:Spring Boot + MyBatis
- 数据库:MySQL主从架构
当时考虑的主要是快速上线验证业务模型,所以很多设计都比较保守。比如缓存只用了简单的Redis单节点,消息队列用的RabbitMQ社区版。
经验之谈:初创项目切忌过度设计,但一定要预留好扩展点。我们当时在接口层做了很好的抽象,这为后续架构升级省了不少事。
2.2 第一次重大升级
上线3个月后,日活突破1万时遇到了第一个瓶颈:数据库写入延迟明显增加。我们做了以下优化:
- 引入ShardingSphere实现分库分表
- 将Redis升级为集群模式
- 增加了本地缓存(Caffeine)作为二级缓存
这次升级持续了两周,期间服务不可用时间控制在30分钟以内。关键是在业务低峰期分批迁移数据,同时准备了完善的回滚方案。
2.3 当前架构全景
现在的架构已经演变成这样:
[图示:前端 -> API网关 -> 微服务集群 -> 消息队列 -> 数据处理层 -> 多类型数据库]具体组件选型:
- 网关:Spring Cloud Gateway
- 注册中心:Nacos
- 配置中心:Apollo
- 监控:Prometheus + Grafana
- 日志:ELK Stack
3. 典型问题与解决方案
3.1 缓存雪崩事件
去年双十一期间,因为某个热点key集中过期导致缓存雪崩,数据库瞬时QPS暴增。我们当时的应急方案:
- 立即启用降级策略,返回兜底数据
- 通过Sentinel实现限流
- 手动刷新缓存
后续改进:
- 给所有缓存增加随机过期时间
- 实现多级缓存策略
- 完善了压测方案
3.2 分布式事务难题
在订单履约流程中,需要跨三个服务更新状态。最初用的本地事务表方案,后来发现某些场景下数据不一致。最终采用的方案:
- 普通操作:TCC模式
- 对账操作:基于消息队列的最终一致性
- 关键路径:接入Seata
4. 运维监控体系
4.1 监控指标建设
我们定义了四个黄金指标:
- 请求量
- 错误率
- 响应时间
- 饱和度
通过Grafana配置了分级告警:
- P0级(立即电话通知)
- P1级(企业微信通知)
- P2级(次日处理)
4.2 日志分析实践
最初的日志分散在各个机器上,排查问题效率极低。现在的日志体系:
- Filebeat收集日志
- Logstash进行过滤处理
- Elasticsearch存储
- Kibana可视化
特别有用的一个技巧:给每个请求生成唯一traceId,可以实现全链路追踪。
5. 团队协作经验
5.1 代码质量管理
我们坚持的几个原则:
- 每次MR必须经过至少两人review
- 单元测试覆盖率要求80%以上
- 使用SonarQube进行静态扫描
5.2 持续交付流程
当前的CI/CD流水线:
代码提交 -> 代码扫描 -> 单元测试 -> 构建镜像 -> 集成测试 -> 灰度发布 -> 全量发布关键改进点:
- 引入了渐进式发布策略
- 每个环境使用完全相同的镜像
- 完善了自动化回滚机制
6. 未来优化方向
虽然系统已经相对稳定,但还有不少需要改进的地方:
- 服务网格化改造
- 实现全链路压测
- 优化资源利用率
- 完善混沌工程体系
这一年来最大的体会是:好的系统不是设计出来的,而是迭代出来的。每次遇到问题都是改进的机会,关键是要建立快速反馈和持续优化的机制。