一、微服务架构概述与设计
随着电商业务的快速发展,单体架构已无法满足高并发、高可用的需求。本文将基于Spring Cloud Alibaba生态,构建一个完整的分布式电商平台。
1.1 系统架构设计
我们的电商平台将包含以下核心服务:
- 用户服务 (user-service) – 用户注册、登录、管理
- 商品服务 (product-service) – 商品管理、分类、搜索
- 订单服务 (order-service) – 订单创建、支付、管理
- 库存服务 (inventory-service) – 库存管理、扣减
- 支付服务 (payment-service) – 支付处理、回调
- 网关服务 (api-gateway) – 统一入口、路由转发
1.2 技术栈选型
- Spring Boot 2.7+
- Spring Cloud Alibaba 2021.0.1+
- Nacos – 服务注册与配置中心
- Sentinel – 流量控制与熔断降级
- Seata – 分布式事务解决方案
- RocketMQ – 消息队列
- MySQL + MyBatis Plus – 数据持久化
- Redis – 缓存与分布式锁
二、环境准备与项目搭建
2.1 创建父工程
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ecommerce</groupId>
<artifactId>ecommerce-platform</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<modules>
<module>user-service</module>
<module>product-service</module>
<module>order-service</module>
<module>inventory-service</module>
<module>payment-service</module>
<module>api-gateway</module>
<module>common-core</module>
</modules>
<properties>
<java.version>11</java.version>
<spring-boot.version>2.7.3</spring-boot.version>
<spring-cloud.version>2021.0.4</spring-cloud.version>
<spring-cloud-alibaba.version>2021.0.4.0</spring-cloud-alibaba.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>${spring-cloud-alibaba.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2.2 通用模块设计 (common-core)
// 统一响应格式
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> implements Serializable {
private Integer code;
private String message;
private T data;
private Long timestamp;
public static <T> ApiResponse<T> success(T data) {
return new ApiResponse(200, "成功", data, System.currentTimeMillis());
}
public static ApiResponse<?> error(String message) {
return new ApiResponse(500, message, null, System.currentTimeMillis());
}
}
// 全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(BusinessException.class)
public ApiResponse<?> handleBusinessException(BusinessException e) {
return ApiResponse.error(e.getMessage());
}
@ExceptionHandler(Exception.class)
public ApiResponse<?> handleException(Exception e) {
log.error("系统异常: ", e);
return ApiResponse.error("系统繁忙,请稍后重试");
}
}
// 分布式ID生成器
@Component
public class SnowflakeIdGenerator {
private final Snowflake snowflake;
public SnowflakeIdGenerator() {
this.snowflake = Snowflake.create(1, 1);
}
public long nextId() {
return snowflake.nextId();
}
}
三、核心服务实现
3.1 用户服务实现
// User实体类
@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.ASSIGN_ID)
private Long id;
private String username;
private String password;
private String email;
private String phone;
private Integer status;
private Date createTime;
private Date updateTime;
}
// UserService实现
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public ApiResponse<UserVO> register(UserRegisterDTO dto) {
// 验证用户名是否已存在
if (lambdaQuery().eq(User::getUsername, dto.getUsername()).exists()) {
throw new BusinessException("用户名已存在");
}
// 密码加密
String encryptedPassword = PasswordUtil.encrypt(dto.getPassword());
// 创建用户
User user = new User();
user.setUsername(dto.getUsername());
user.setPassword(encryptedPassword);
user.setEmail(dto.getEmail());
user.setPhone(dto.getPhone());
user.setStatus(1);
user.setCreateTime(new Date());
save(user);
// 发送注册成功事件
rocketMQTemplate.send("user-register-topic",
MessageBuilder.withPayload(user).build());
return ApiResponse.success(convertToVO(user));
}
@Override
@SentinelResource(value = "userLogin", blockHandler = "loginBlockHandler")
public ApiResponse<String> login(UserLoginDTO dto) {
User user = lambdaQuery()
.eq(User::getUsername, dto.getUsername())
.one();
if (user == null || !PasswordUtil.matches(dto.getPassword(), user.getPassword())) {
throw new BusinessException("用户名或密码错误");
}
// 生成JWT token
String token = JwtUtil.generateToken(user.getId(), user.getUsername());
// 缓存用户信息
redisTemplate.opsForValue().set("user:" + user.getId(), user, 30, TimeUnit.MINUTES);
return ApiResponse.success(token);
}
public ApiResponse<String> loginBlockHandler(UserLoginDTO dto, BlockException ex) {
log.warn("登录接口被限流: {}", dto.getUsername());
return ApiResponse.error("系统繁忙,请稍后重试");
}
}
3.2 商品服务实现
// 商品查询服务
@Service
@Slf4j
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product>
implements ProductService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
@Cacheable(value = "product", key = "#id")
public Product getProductById(Long id) {
log.info("查询数据库获取商品详情: {}", id);
return getById(id);
}
@Override
public Page<ProductVO> searchProducts(ProductQueryDTO queryDTO) {
return lambdaQuery()
.like(StringUtils.isNotBlank(queryDTO.getKeyword()),
Product::getName, queryDTO.getKeyword())
.eq(queryDTO.getCategoryId() != null,
Product::getCategoryId, queryDTO.getCategoryId())
.between(queryDTO.getMinPrice() != null && queryDTO.getMaxPrice() != null,
Product::getPrice, queryDTO.getMinPrice(), queryDTO.getMaxPrice())
.eq(Product::getStatus, 1)
.page(new Page(queryDTO.getPageNum(), queryDTO.getPageSize()))
.convert(this::convertToVO);
}
@Override
@Transactional(rollbackFor = Exception.class)
public boolean reduceStock(Long productId, Integer quantity) {
// 使用分布式锁防止超卖
String lockKey = "product:stock:lock:" + productId;
String requestId = UUID.randomUUID().toString();
try {
// 尝试获取分布式锁
Boolean locked = redisTemplate.opsForValue()
.setIfAbsent(lockKey, requestId, 10, TimeUnit.SECONDS);
if (Boolean.TRUE.equals(locked)) {
Product product = getById(productId);
if (product.getStock() < quantity) {
throw new BusinessException("库存不足");
}
// 扣减库存
boolean updated = lambdaUpdate()
.setSql("stock = stock - " + quantity)
.eq(Product::getId, productId)
.ge(Product::getStock, quantity)
.update();
if (!updated) {
throw new BusinessException("库存扣减失败");
}
// 发送库存变更消息
rocketMQTemplate.send("stock-change-topic",
MessageBuilder.withPayload(new StockChangeEvent(productId, -quantity)).build());
return true;
} else {
throw new BusinessException("系统繁忙,请重试");
}
} finally {
// 释放锁
if (requestId.equals(redisTemplate.opsForValue().get(lockKey))) {
redisTemplate.delete(lockKey);
}
}
}
}
3.3 订单服务实现
// 订单服务
@Service
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order>
implements OrderService {
@Autowired
private ProductFeignClient productFeignClient;
@Autowired
private InventoryFeignClient inventoryFeignClient;
@Override
@GlobalTransactional(name = "create_order", rollbackFor = Exception.class)
public ApiResponse<OrderVO> createOrder(OrderCreateDTO createDTO) {
Long userId = UserContext.getCurrentUserId();
// 1. 验证商品信息
ApiResponse<ProductVO> productResponse = productFeignClient.getProductById(createDTO.getProductId());
if (!productResponse.getCode().equals(200)) {
throw new BusinessException("商品不存在");
}
ProductVO product = productResponse.getData();
if (product.getStock() inventoryResponse = inventoryFeignClient.reduceStock(
createDTO.getProductId(), createDTO.getQuantity());
if (!inventoryResponse.getCode().equals(200)) {
throw new BusinessException("库存扣减失败");
}
// 3. 创建订单
Order order = new Order();
order.setOrderNo(generateOrderNo());
order.setUserId(userId);
order.setProductId(createDTO.getProductId());
order.setQuantity(createDTO.getQuantity());
order.setTotalAmount(product.getPrice().multiply(
new BigDecimal(createDTO.getQuantity())));
order.setStatus(OrderStatus.CREATED.getCode());
order.setCreateTime(new Date());
save(order);
// 4. 发送订单创建消息
rocketMQTemplate.send("order-create-topic",
MessageBuilder.withPayload(order).build());
return ApiResponse.success(convertToVO(order));
}
private String generateOrderNo() {
return "ORDER" + System.currentTimeMillis() +
String.format("%04d", ThreadLocalRandom.current().nextInt(1000));
}
}
四、服务治理与配置
4.1 Nacos服务注册与配置
# application.yml
spring:
application:
name: user-service
cloud:
nacos:
discovery:
server-addr: ${NACOS_HOST:localhost}:8848
namespace: ${NACOS_NAMESPACE:public}
config:
server-addr: ${NACOS_HOST:localhost}:8848
file-extension: yaml
namespace: ${NACOS_NAMESPACE:public}
shared-configs:
- data-id: common.yaml
refresh: true
- data-id: datasource.yaml
refresh: true
- data-id: redis.yaml
refresh: true
# bootstrap.yml
spring:
profiles:
active: dev
cloud:
nacos:
config:
group: DEFAULT_GROUP
prefix: ${spring.application.name}
4.2 Sentinel流量控制配置
@Configuration
public class SentinelConfig {
@PostConstruct
public void init() {
// 配置限流规则
List<FlowRule> rules = new ArrayList();
// 用户登录接口限流
FlowRule loginRule = new FlowRule();
loginRule.setResource("userLogin");
loginRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
loginRule.setCount(10); // 每秒10次
rules.add(loginRule);
// 商品查询接口限流
FlowRule productRule = new FlowRule();
productRule.setResource("getProductById");
productRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
productRule.setCount(100);
rules.add(productRule);
FlowRuleManager.loadRules(rules);
}
}
// 自定义降级处理
@Component
public class CustomBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
BlockException e) throws Exception {
response.setContentType("application/json;charset=utf-8");
response.setStatus(429);
Map<String, Object> result = new HashMap();
result.put("code", 429);
result.put("message", "请求过于频繁,请稍后重试");
result.put("timestamp", System.currentTimeMillis());
response.getWriter().write(new ObjectMapper().writeValueAsString(result));
}
}
4.3 Seata分布式事务配置
# seata配置
seata:
enabled: true
application-id: ${spring.application.name}
tx-service-group: default_tx_group
enable-auto-data-source-proxy: true
config:
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
namespace: ${spring.cloud.nacos.discovery.namespace}
group: SEATA_GROUP
registry:
type: nacos
nacos:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
namespace: ${spring.cloud.nacos.discovery.namespace}
group: SEATA_GROUP
// 数据源代理配置
@Configuration
public class DataSourceConfiguration {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DruidDataSource druidDataSource() {
return new DruidDataSource();
}
@Primary
@Bean("dataSource")
public DataSource dataSource(DruidDataSource druidDataSource) {
return new DataSourceProxy(druidDataSource);
}
}
五、API网关与安全控制
5.1 Spring Cloud Gateway配置
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r.path("/api/user/**")
.filters(f -> f.stripPrefix(1)
.addRequestHeader("X-Request-Time", String.valueOf(System.currentTimeMillis()))
.circuitBreaker(config -> config.setName("userCircuitBreaker")
.setFallbackUri("forward:/fallback/user")))
.uri("lb://user-service"))
.route("product-service", r -> r.path("/api/product/**")
.filters(f -> f.stripPrefix(1)
.requestRateLimiter(config -> config.setRateLimiter(redisRateLimiter())
.setKeyResolver(userKeyResolver())))
.uri("lb://product-service"))
.route("order-service", r -> r.path("/api/order/**")
.filters(f -> f.stripPrefix(1)
.modifyRequestBody(String.class, String.class,
(exchange, s) -> Mono.just(s)))
.uri("lb://order-service"))
.build();
}
@Bean
public RedisRateLimiter redisRateLimiter() {
return new RedisRateLimiter(10, 20, 1);
}
@Bean
public KeyResolver userKeyResolver() {
return exchange -> Mono.just(
exchange.getRequest().getHeaders().getFirst("X-User-Id"));
}
}
// 全局过滤器
@Component
@Order(-1)
public class AuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
if (StringUtils.isBlank(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
try {
Claims claims = JwtUtil.parseToken(token.replace("Bearer ", ""));
String userId = claims.getSubject();
// 将用户信息添加到请求头
exchange = exchange.mutate()
.request(builder -> builder.header("X-User-Id", userId))
.build();
} catch (Exception e) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}
六、部署与监控
6.1 Docker容器化部署
# Dockerfile
FROM openjdk:11-jre-slim
VOLUME /tmp
ARG JAR_FILE=target/*.jar
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-jar", "/app.jar"]
# docker-compose.yml
version: '3.8'
services:
nacos:
image: nacos/nacos-server:2.0.3
environment:
- MODE=standalone
ports:
- "8848:8848"
redis:
image: redis:6.2-alpine
ports:
- "6379:6379"
mysql:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=root
ports:
- "3306:3306"
user-service:
build: ./user-service
ports:
- "8081:8080"
depends_on:
- nacos
- redis
- mysql
product-service:
build: ./product-service
ports:
- "8082:8080"
depends_on:
- nacos
- redis
- mysql
api-gateway:
build: ./api-gateway
ports:
- "8080:8080"
depends_on:
- user-service
- product-service
6.2 监控与告警
// Spring Boot Actuator配置
management:
endpoints:
web:
exposure:
include: health,info,metrics,prometheus
endpoint:
health:
show-details: always
metrics:
enabled: true
prometheus:
enabled: true
// 自定义健康检查
@Component
public class RedisHealthIndicator implements HealthIndicator {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@Override
public Health health() {
try {
String result = redisTemplate.execute((RedisCallback<String>) connection ->
connection.ping());
if ("PONG".equals(result)) {
return Health.up().withDetail("message", "Redis连接正常").build();
} else {
return Health.down().withDetail("error", "Redis连接异常").build();
}
} catch (Exception e) {
return Health.down(e).build();
}
}
}
// 业务指标监控
@Component
public class OrderMetrics {
private final MeterRegistry meterRegistry;
private final Counter orderCreatedCounter;
private final DistributionSummary orderAmountSummary;
public OrderMetrics(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
this.orderCreatedCounter = Counter.builder("order.created")
.description("订单创建数量")
.register(meterRegistry);
this.orderAmountSummary = DistributionSummary.builder("order.amount")
.description("订单金额分布")
.register(meterRegistry);
}
public void recordOrderCreated(Order order) {
orderCreatedCounter.increment();
orderAmountSummary.record(order.getTotalAmount().doubleValue());
// 记录标签信息
meterRegistry.counter("order.created.by.user",
"userId", order.getUserId().toString())
.increment();
}
}
七、总结与最佳实践
通过本实战教程,我们构建了一个基于Spring Cloud Alibaba的完整电商微服务系统,涵盖了:
- 微服务拆分:合理的服务边界划分和职责分离
- 服务治理:Nacos实现服务注册发现和配置管理
- 流量控制:Sentinel实现熔断降级和流量控制
- 分布式事务:Seata保证数据一致性
- 消息队列:RocketMQ实现异步解耦
- API网关:统一入口和安全控制
- 监控告警:完整的可观测性方案
生产环境建议:
- 使用Kubernetes进行容器编排和管理
- 实现蓝绿部署或金丝雀发布
- 建立完善的日志收集和分析系统
- 配置APM系统进行性能监控
- 建立CI/CD流水线自动化部署
- 定期进行压力测试和性能优化
这个电商平台架构具有良好的扩展性和可维护性,可以作为企业级微服务架构的参考实现。