引言:每一个Java商城系统,都是从一台服务器开始的

2015年,我第一次参与开发一个电商系统。当时的技术栈很简单:一台Tomcat服务器、一个MySQL数据库、一套SSH(Struts+Spring+Hibernate)框架。日均订单量不过几百单,系统跑得还算顺畅。

到了2018年,日均订单量突破了5万单。那台Tomcat已经不堪重负,频繁出现OOM(内存溢出)。数据库的慢查询日志长得让人绝望。我们不得不开始重构。

这个故事,几乎是每一个Java商城系统的成长缩影。本文将以一个真实项目的演进历程为主线,分享Java商城系统的技术选型思路和实战经验。

一、第一阶段:单体架构——快速上线验证

技术选型

层面

技术组件

选型理由

框架

Spring Boot + MyBatis

开发效率高,社区活跃

数据库

MySQL 5.7

成熟稳定,满足初期需求

缓存

Redis

热点数据缓存,Session共享

前端

Thymeleaf + jQuery

服务端渲染,SEO友好

适用场景

  • 创业初期,团队人数少于10人

  • 日均订单量低于1万单

  • 业务逻辑相对简单,不需要复杂的分布式事务

踩过的坑

  • 数据库连接池耗尽:初期没有合理配置连接池大小,高峰期出现数据库连接等待超时。解决方案:配置HikariCP连接池,设置最大连接数为CPU核心数的2倍。

  • 慢查询拖垮数据库:商品列表页的SQL没有加索引,每次查询都要全表扫描。解决方案:使用慢查询日志定位问题SQL,添加复合索引。

  • Session丢失:多台服务器部署后,用户登录状态丢失。解决方案:引入Redis集中管理Session。


二、第二阶段:SOA架构——服务化改造

为什么要拆分?

当系统发展到一定程度,单体架构的问题开始暴露:

  • 耦合严重:修改订单模块的代码,可能导致支付模块出问题

  • 部署困难:一个小小的改动,需要重新部署整个应用

  • 扩展不均:订单模块需要更多资源,但无法单独扩容

拆分策略

按照业务边界,将系统拆分为多个独立的服务:

					

					
纯文本
┌─────────────────────────────────────┐
│           API Gateway               │
├──────────┬──────────┬───────────────┤
│ 商品服务  │ 订单服务  │   支付服务     │
├──────────┼──────────┼───────────────┤
│ 用户服务  │ 库存服务  │   营销服务     │
├──────────┴──────────┴───────────────┤
│           公共服务层                  │
│    (Dubbo/Zookeeper 服务治理)        │
└─────────────────────────────────────┘

技术选型

  • RPC框架:Dubbo(阿里开源,性能优异,适合内部服务调用)

  • 注册中心:Zookeeper/Nacos

  • 分布式事务:TCC模式(Try-Confirm-Cancel),适用于跨服务的资金操作

踩过的坑

  • 分布式事务一致性问题:订单创建涉及商品服务(扣库存)、订单服务(生成订单)、支付服务(冻结资金)。任何一个步骤失败,都需要回滚所有操作。解决方案:引入TCC事务框架,配合补偿机制,确保最终一致性。

  • 服务间调用超时:某个服务响应变慢,导致调用方线程阻塞,最终引发连锁故障。解决方案:设置合理的超时时间和熔断阈值,引入Hystrix熔断器。

三、第三阶段:微服务架构——精细化治理

为什么要进一步演进?

SOA架构解决了服务拆分的问题,但随着服务数量增加到几十个,新的问题出现了:

  • 配置管理混乱:每个服务都有自己的配置文件,修改一个公共配置需要逐个修改

  • 监控告警缺失:服务多了,不知道哪个服务出了问题

  • 链路追踪困难:一个请求跨越多个服务,排查问题需要逐一看日志

技术选型

能力维度

技术组件

作用

配置中心

Nacos/Apollo

统一管理配置,支持动态刷新

服务网关

Spring Cloud Gateway

路由转发、限流、鉴权

链路追踪

SkyWalking

全链路调用链追踪

监控告警

Prometheus + Grafana

指标采集与可视化

容器化

Docker + Kubernetes

自动化部署与弹性伸缩

微服务架构的收益

  • 独立部署:每个服务可以独立发布,不影响其他服务

  • 弹性伸缩:大促期间,只对订单服务和支付服务进行扩容,节省资源

  • 故障隔离:某个服务宕机,不会影响整个系统的可用性

四、关键业务模块的设计要点

商品模块:SPU与SKU模型

					

					
纯文本
SPU(Standard Product Unit):iPhone 14 Pro Max
  ├── SKU1:iPhone 14 Pro Max / 深空黑 / 256GB
  ├── SKU2:iPhone 14 Pro Max / 银色 / 256GB
  └── SKU3:iPhone 14 Pro Max / 深空黑 / 512GB

SPU是抽象的商品概念,SKU是具体的可售卖单元。商品详情页展示SPU信息,用户选择规格后确定具体的SKU。

订单模块:状态机设计

订单状态的流转必须严谨,不能出现状态跳跃或回退。推荐使用状态机模式:

					

					
纯文本
待支付 → 已支付 → 已发货 → 已签收 → 已完成
   ↓        ↓        ↓        ↓
  取消     退款     退货     售后

状态机的好处是:状态流转的逻辑集中在一个地方管理,避免了散落在各个业务代码中的if-else判断。

库存模块:分布式锁的选型

扣减库存是高并发场景下的核心操作。需要保证:同一时刻,只有一个线程能扣减某个SKU的库存。

方案

优点

缺点

数据库乐观锁

实现简单

并发性能差

Redis分布式锁

性能好

需处理锁超时

Redisson

功能完善

增加依赖

实战建议:对于绝大多数场景,Redisson提供的分布式锁已经足够。它的看门狗机制可以自动续期,避免锁超时导致的数据不一致。

五、给Java商城系统开发者的建议

建议一:不要过度设计

创业初期,能用单体解决的问题就不要上微服务。过度设计会增加开发和维护成本,拖慢产品迭代速度。等到业务规模确实需要的时候,再进行架构升级。

建议二:重视测试

电商系统的容错率很低。一个支付bug可能导致资金损失,一个库存bug可能导致超卖。建立完善的测试体系:单元测试、集成测试、压测、混沌工程。

建议三:拥抱云原生

现在的Java商城系统,已经没有必要自己搭建机房。阿里云、腾讯云、AWS提供了丰富的云服务:RDS替代自建数据库、OSS替代自建文件存储、SLB替代自建负载均衡。把精力集中在业务逻辑上,而不是基础设施的维护上。

结语:

从一个Tomcat到几十个微服务,从一台MySQL到分库分表,Java商城系统的技术演进史,就是一部业务增长史。每一次架构升级的背后,都是业务规模的增长和技术团队的成长。

技术没有银弹,也没有一步到位的完美架构。唯一不变的是:永远为下一个阶段的增长做好准备