Architecture Lessons Learned from Real‑World Failures
The article shares four real‑world failure cases—over‑splitting into microservices, skipping performance testing, accumulating technical debt, and relying on a single‑point database—to illustrate why careful architectural decisions, thorough testing, debt repayment, and high‑availability design are essential for sustainable software systems.
Case 1 – Over‑confident microservice splitting
Background
In 2019 the author designed a new project and, following the microservice trend, split the entire system into separate services.
Design
┌────────────────────────────────────────┐
│ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │用户服务│ │商品服务│ │订单服务│ │
│ └──────┘ └──────┘ └──────┘ │
│ ┌──────┐ ┌──────┐ ┌──────┐ │
│ │库存服务│ │支付服务│ │评价服务│ │
│ └──────┘ └──────┘ └──────┘ │
│ │
│ ┌──────────────────────────────────┐ │
│ │ 服务治理(配置/注册/网关) │ │
│ └──────────────────────────────────┘ │
└────────────────────────────────────────┘Actual situation
开发3个月后的状态:
┌──────┐ ┌──────┐ ┌──────┐
│用户服务│ │商品服务│ │订单服务│
│ 正常 │ │ 正常 │ │ 正常 │
└──────┘ └──────┘ └──────┘
团队状态:
- 5个人的团队
- 维护6个服务
- 每天花2小时处理服务间通信问题
- 本来2周能做完的功能,花了2个月Problems
Team capability insufficient: 5 people maintaining 6 services, each only partially skilled.
Complexity exploded: service governance consumed roughly half of development time.
Cost outweighs benefit: the business was simple and did not need microservices.
Lesson
Microservices are not a silver bullet; split only when the team size exceeds ten, the business complexity justifies it, and the organization has solid service‑governance capability. Otherwise a monolith may be a better choice.
Solution
半年后的重构:
┌─────────────────────────────────┐
│ 单体应用 │
│ │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │用户 │ │商品 │ │订单 │ │
│ │模块 │ │模块 │ │模块 │ │
│ └─────┘ └─────┘ └─────┘ │
│ │
│ ┌─────┐ ┌─────┐ │
│ │库存 │ │支付 │ │
│ │模块 │ │模块 │ │
│ └─────┘ └─────┘ │
│ │
└─────────────────────────────────┘
开发效率提升约3倍Case 2 – Ignoring performance testing
Background
In 2020 the author built a simple activity‑registration system and assumed a single MySQL instance would be sufficient.
Design
CREATE TABLE `activity_signup` (
`id` BIGINT PRIMARY KEY AUTO_INCREMENT,
`activity_id` BIGINT NOT NULL,
`user_id` BIGINT NOT NULL,
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY `uk_activity_user` (`activity_id`, `user_id`)
);Actual situation
上线第一天:
10:00 活动开始
10:00:01 用户开始报名
10:00:05 数据库CPU飙升99%
10:00:30 系统开始报错
10:01:00 系统完全不可用
结果:
- 5000人报名的活动,只有500人成功
- 活动页面崩溃30分钟
- 被用户骂到热搜Problem analysis
瓶颈分析:
1. 5000 QPS涌入
2. MySQL只能承受约500 QPS
3. 没有缓存、没有队列
4. 直接击穿数据库
问题:
- 没有做性能测试
- 没有做容量规划
- 没有考虑秒杀场景Lesson
Performance testing is mandatory. Before each release answer: what is the system’s QPS limit? Where are the bottlenecks? How to handle overload?
Solution
重构后的设计:
┌────────────────────────────────────────┐
│ 用户请求 │
│ │ │
│ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 限流熔断 │ │ 消息队列 │───→│ 异步处理 │ │
│ │ (Kafka) │ │ │ │
│ └────┬─────┘ └────┬─────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ MySQL │ │ MySQL │ │
│ └──────────┘ └──────────┘ │
└────────────────────────────────────────┘
效果:系统能够轻松支撑10万 QPS。Case 3 – Technical debt snowball
Background
In 2018 the author inherited a five‑year‑old legacy system with no documentation.
Actual situation
第一次打开代码的感受:
模块A:
├── UserService.java (2000行)
├── UserHelper.java (1500行)
├── UserUtils.java (1000行)
├── UserCommon.java (1800行)
└── UserManager.java (2200行)
5个类,8500行代码,没人知道它们之间的关系。
每个类都有类似注释:
// 这里是处理用户相关逻辑的类 —— 张三 2018-01
// 我也不知道这个方法是干啥的 —— 李四 2019-03
// 这个方法好像有bug,我不敢改 —— 王五 2020-06Problems
1. 代码没人敢改
- 改了会出 bug
- 出了 bug 没人修复
2. 技术债务累积
- 老代码不敢动
- 新代码继续堆砌
- 债务越滚越大
3. 团队士气低落
- 没人愿意碰这个系统
- 人员流动加速
- 形成恶性循环Lesson
Technical debt must be repaid regularly; it behaves like a credit‑card where interest accrues and the debt can explode if not managed.
Solution
技术债务治理计划:
第一阶段(1个月) – 摸清家底
- 代码审查
- 识别关键债务
- 建立债务清单
第二阶段(3个月) – 止血
- 修复最紧急的 bug
- 添加单元/集成测试
- 编写关键文档
第三阶段(持续) – 渐进重构
- 新功能使用新架构实现
- 老功能逐步迁移到新模块
- 每周预留约 20% 时间处理债务
结果:1 年后技术债务降低约 70%。Case 4 – Single‑point‑failure disaster
Background
In 2021 the author built a payment system and assumed a single MySQL instance would be sufficient for a small company.
Design
# docker-compose.yml
version: '3'
services:
mysql:
image: mysql:8.0
ports:
- "3306:3306"
volumes:
- ./data:/var/lib/mysqlActual situation
凌晨2点:
运维:系统挂了
运维:MySQL 服务器磁盘坏了
运维:没有备份
结果:
- 系统停机 3 天
- 丢失 2 天数据
- 赔偿用户损失约 50 万元
- 作者被降职Lesson
High availability is a basic requirement, not optional. Production systems must consider data backup, service redundancy, failover, and disaster recovery.
Solution
重构后的高可用架构:
┌────────────────────────────────────────┐
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │ App 1 │ │ App 2 │ │ App 3 │ │
│ └────┬───┘ └────┬───┘ └────┬───┘ │
│ │ │ │ │
│ └──────────┼──────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Keepalived │ │
│ │ VIP漂移 │ │
│ └──────┬──────┘ │
│ │ │
│ ┌──────────┴──────────┐ │
│ │ │ │
│ ┌────▼────┐ ┌────▼────┐ │
│ │ MySQL主 │◄─同步───→│ MySQL从 │ │
│ └─────────┘ └─────────┘ │
│ │
│ 数据备份:每天全量 + 每小时增量 │
└────────────────────────────────────────┘Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
IT Learning Made Simple
Learn IT: using simple language and everyday examples to study.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
