从单机到K8S:一个电商项目的真实架构演进史(含Docker实战配置)
从单机到K8S:一个电商项目的真实架构演进史
2018年夏天,我们团队接手了一个日均订单不足100的小型电商项目。当时整个系统跑在一台4核8G的云服务器上,技术栈是经典的Spring Boot+MySQL组合。谁也没想到,三年后这个系统需要支撑百万级并发,架构也经历了五次重大迭代。今天我就用真实配置片段,还原这段惊心动魄的技术升级之旅。
1. 单机时代的生死时速
最初的架构简单到可以用一张图说明:
[前端] -> [Nginx] -> [Tomcat+Spring Boot] -> [MySQL]
第一个618大促成了架构演进的导火索。当天上午10点流量暴涨后,数据库CPU直接飙到100%,订单提交接口响应时间从200ms恶化到15秒。我们临时做了三件事救火:
- 紧急扩容云服务器到8核16G
- 在Nginx配置静态资源缓存
location ~* \.(jpg|css|js)$ { expires 7d; add_header Cache-Control "public"; } - 给商品表添加了索引
ALTER TABLE products ADD INDEX idx_category_status (category_id, status);
提示:单机架构下,垂直扩容(Scale Up)是最快的应急方案,但成本呈指数级增长
这次事件让我们意识到两个关键问题:
- 数据库成为明显瓶颈
- 静态资源消耗了60%的带宽
2. 第一次解耦:应用与数据分离
我们把架构拆分成三个独立部分:
- 2台应用服务器(4核8G)
- 1台数据库服务器(8核32G,SSD存储)
- 1台文件存储服务器(专门存放图片视频)
关键配置变化:
- 应用服务器禁用本地存储
spring.servlet.multipart.location=/tmp file.upload-dir=http://storage-server/uploads - 数据库连接池调整
@Bean public HikariDataSource dataSource() { HikariConfig config = new HikariConfig(); config.setMaximumPoolSize(20); // 原为50 config.setConnectionTimeout(30000); return new HikariDataSource(config); }
这个阶段我们收获的最大教训是:网络延迟成为新瓶颈。应用服务器与数据库之间的平均往返时间(RTT)达到3ms,导致复杂查询性能反而下降。
3. 缓存体系的构建
当DAU突破5万时,数据库再次成为瓶颈。我们引入了多级缓存体系:
| 缓存层级 | 实现方案 | 命中率 | 响应时间 |
|---|---|---|---|
| CDN | 阿里云CDN | 40% | <50ms |
| 页面缓存 | Redis | 30% | 2ms |
| 对象缓存 | Redis | 25% | 1ms |
| 数据库 | MySQL | 5% | 10-100ms |
最关键的Redis配置:
spring:
redis:
lettuce:
pool:
max-active: 50
max-idle: 20
min-idle: 5
timeout: 5000
cache:
ttl: 1800 # 30分钟过期
缓存带来的性能提升立竿见影:
- 商品详情页QPS从200提升到1500
- 数据库负载下降70%
但我们也踩了个大坑:某次大促时Redis内存爆满触发LRU淘汰,导致缓存雪崩。后来通过以下措施解决:
- 增加内存监控报警
- 采用多级过期策略
- 实现缓存降级机制
4. 微服务化改造
当代码库膨胀到50万行时,单体架构的弊端开始显现:
- 每次发布需要全量部署
- 局部修改可能影响全局
- 技术栈无法按需选择
我们按业务域拆分为六个微服务:
- 用户中心
- 商品服务
- 订单服务
- 支付服务
- 营销服务
- 物流服务
服务通信方案对比:
| 方案 | 协议 | 性能 | 复杂度 | 最终选择 |
|---|---|---|---|---|
| Feign | HTTP | 中 | 低 | ✓ |
| gRPC | HTTP/2 | 高 | 中 | 部分场景 |
| RocketMQ | 消息队列 | 异步 | 高 | 最终一致场景 |
订单服务的Dubbo配置示例:
<dubbo:service
interface="com.ec.order.OrderService"
ref="orderService"
version="1.0.0"
timeout="3000"
retries="2"/>
微服务化过程中最大的挑战是分布式事务。我们最终采用"最终一致性+补偿机制"的方案:
@Transactional
public void createOrder(OrderDTO order) {
// 1. 本地事务
orderMapper.insert(order);
// 2. 发送MQ消息
rocketMQTemplate.asyncSend(
"order-create-topic",
JSON.toJSONString(order),
new SendCallback() {
@Override
public void onSuccess(SendResult sendResult) {
// 记录发送成功日志
}
@Override
public void onException(Throwable e) {
// 启动补偿流程
compensateOrder(order);
}
});
}
5. 容器化与K8S落地
随着服务器数量突破50台,运维成本呈指数增长。我们开始向容器化架构迁移:
Docker化改造关键步骤:
- 编写多阶段构建Dockerfile
FROM maven:3.8-jdk-11 AS build COPY . /app RUN mvn -f /app/pom.xml clean package FROM openjdk:11-jre-slim COPY --from=build /app/target/*.jar /app.jar ENTRYPOINT ["java","-jar","/app.jar"] - 构建镜像并推送到仓库
docker build -t registry.ec.com/order-service:v1.2.0 . docker push registry.ec.com/order-service:v1.2.0 - 编写K8S部署文件
apiVersion: apps/v1 kind: Deployment metadata: name: order-service spec: replicas: 3 selector: matchLabels: app: order-service template: metadata: labels: app: order-service spec: containers: - name: order-service image: registry.ec.com/order-service:v1.2.0 ports: - containerPort: 8080 resources: limits: cpu: "1" memory: 1Gi
K8S带来的核心收益:
- 资源利用率提升40%
- 部署时间从小时级降到分钟级
- 自动扩缩容应对流量高峰
在迁移过程中,我们特别注重监控体系的建设。这是Prometheus的监控配置片段:
- job_name: 'order-service'
metrics_path: '/actuator/prometheus'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_app]
action: keep
regex: order-service
6. 架构演进的经验总结
回顾这段演进历程,有几个关键决策点值得分享:
-
技术选型评估矩阵:
- 团队熟悉度(权重30%)
- 社区活跃度(权重25%)
- 企业长期需求(权重20%)
- 学习成本(权重15%)
- 商业支持(权重10%)
-
架构改造的黄金法则:
- 永远先监控再优化
- 能水平扩展就不垂直扩展
- 非核心链路先试水新技术
- 保持架构的可逆性
-
性能优化checklist:
- [ ] 数据库查询是否走索引
- [ ] 缓存命中率是否>90%
- [ ] 线程池配置是否合理
- [ ] JVM参数是否优化
- [ ] 网络延迟是否可控
在容器化过程中,我们最大的收获是建立了完善的CI/CD流水线。这是Jenkinsfile的核心片段:
pipeline {
agent any
stages {
stage('Build') {
steps {
sh 'mvn clean package -DskipTests'
}
}
stage('Test') {
steps {
parallel(
"Unit Test": { sh 'mvn test' },
"Integration Test": { sh 'mvn verify -Pintegration' }
)
}
}
stage('Deploy') {
when {
branch 'main'
}
steps {
sh 'kubectl apply -f k8s/deployment.yaml'
}
}
}
}
架构演进没有终点。现在我们正在探索Service Mesh和Serverless方向,但每次技术升级都遵循一个原则:用最小改动解决当前最主要矛盾。
更多推荐
所有评论(0)