1. 项目概述
这个企业级物资采购销售管理系统是我去年带队完成的一个中型项目,当时客户是一家年采购额超过5亿元的制造业企业。他们原有的单机版管理系统已经无法支撑日益复杂的供应链业务,经常出现数据不同步、响应延迟等问题。经过三个月的开发迭代,我们基于SpringCloud微服务架构重构了整个系统,最终实现了日均10万级订单的处理能力。
系统最大的特点是通过业务解耦实现了六大角色的高效协同。在传统架构中,采购、销售、库存模块往往强耦合,任何一个环节的改动都可能引发连锁反应。而我们的微服务设计让每个业务单元都能独立部署和扩展,比如在去年双十一大促期间,销售模块的实例可以快速扩容3倍,而其他服务保持原样,既保证了系统稳定性又节省了资源。
2. 技术架构设计
2.1 微服务组件选型
在技术选型阶段,我们对比了多种微服务方案,最终确定的架构组合是:
- 注册中心:Nacos(相比Eureka支持配置中心,相比Consul对Java生态更友好)
- API网关:SpringCloud Gateway(性能是Zuul的1.6倍,支持异步非阻塞)
- 熔断降级:Sentinel(比Hystrix提供更细粒度的流量控制)
- 分布式事务:Seata(AT模式对业务代码侵入小)
实际踩坑:初期使用Feign进行服务调用时,遇到文件上传大小限制问题。解决方案是在网关和服务的配置文件中同时添加:
yaml复制spring: servlet: multipart: max-file-size: 50MB max-request-size: 100MB
2.2 前后端分离实践
前端采用Vue3+Element Plus组合,通过axios与后端交互。这里分享几个关键配置点:
- 跨域处理:在网关层统一配置CORS,避免每个服务重复设置
java复制@Bean
public CorsWebFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
config.addAllowedOrigin("*");
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsWebFilter(source);
}
- 接口安全:采用JWT+OAuth2混合模式,前端需要处理:
javascript复制// axios拦截器示例
service.interceptors.request.use(config => {
config.headers['Authorization'] = 'Bearer ' + getToken()
return config
})
3. 核心业务模块实现
3.1 采购管理模块设计
采购流程的状态机设计是核心难点,我们最终采用状态模式实现:
java复制public interface PurchaseState {
void submit(PurchaseOrder order);
void approve(PurchaseOrder order);
void reject(PurchaseOrder order);
void complete(PurchaseOrder order);
}
// 具体状态实现
public class DraftState implements PurchaseState {
@Override
public void submit(PurchaseOrder order) {
order.setState(new PendingApprovalState());
// 发送通知给审批人
}
// 其他方法抛出UnsupportedOperationException
}
库存预警算法采用了动态安全库存计算:
sql复制-- 安全库存计算公式
UPDATE inventory_config
SET safety_stock = CEILING(
AVG(daily_usage) * MAX(lead_time) *
(1 + (SELECT risk_factor FROM supplier WHERE id=:supplierId))
)
WHERE material_id = :materialId;
3.2 销售信用控制
客户信用评估模型包含5个维度:
- 历史付款及时率(权重40%)
- 当前欠款比例(权重25%)
- 合作年限系数(权重15%)
- 行业风险等级(权重10%)
- 第三方征信数据(权重10%)
实现代码片段:
java复制public CreditResult evaluateCredit(Long clientId) {
Client client = clientRepository.findById(clientId);
BigDecimal score = BigDecimal.ZERO;
score = score.add(paymentHistoryService.calculateScore(clientId).multiply(0.4));
score = score.add(currentDebtService.calculateScore(clientId).multiply(0.25));
// 其他维度计算...
return new CreditResult(
score,
getCreditLimit(score),
getPaymentTerms(score)
);
}
4. 分布式系统难点解决方案
4.1 库存扣减的一致性问题
采用"预占库存+最终扣减"的二阶段方案:
- 下单时先预占:
UPDATE stock SET locked = locked + ? WHERE sku = ? AND available >= ? - 支付成功后实际扣减:
UPDATE stock SET total = total - ?, locked = locked - ? WHERE sku = ?
配合Seata的AT模式,关键配置:
properties复制# seata.conf
client.tm.degradeCheck=false
store.mode=db
store.db.datasource=druid
4.2 订单超时自动取消
使用RabbitMQ的延迟队列实现:
java复制@Bean
public Queue orderDelayQueue() {
return QueueBuilder.durable("order.delay.queue")
.withArgument("x-dead-letter-exchange", "order.event.exchange")
.withArgument("x-dead-letter-routing-key", "order.cancel")
.withArgument("x-message-ttl", 1800000) // 30分钟
.build();
}
@RabbitListener(queues = "order.cancel.queue")
public void handleCancel(OrderMessage message) {
orderService.cancelOrder(message.getOrderId());
}
5. 性能优化实践
5.1 缓存策略设计
采用多级缓存架构:
- 本地缓存(Caffeine):缓存用户权限等高频访问数据
java复制@Bean
public CacheManager cacheManager() {
CaffeineCacheManager manager = new CaffeineCacheManager();
manager.setCaffeine(Caffeine.newBuilder()
.expireAfterWrite(10, TimeUnit.MINUTES)
.maximumSize(1000));
return manager;
}
- Redis缓存:存储商品详情等结构化数据,使用Hash结构节省内存
bash复制# Redis内存优化配置
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
5.2 数据库分库分表
采购订单表按年份分表,配置示例:
yaml复制spring:
shardingsphere:
datasource:
names: ds0,ds1
sharding:
tables:
purchase_order:
actual-data-nodes: ds$->{0..1}.purchase_order_$->{2020..2023}
table-strategy:
standard:
precise-algorithm-class-name: com.example.YearPreciseShardingAlgorithm
range-algorithm-class-name: com.example.YearRangeShardingAlgorithm
6. 监控与运维方案
6.1 全链路监控体系
Prometheus配置关键指标:
yaml复制scrape_configs:
- job_name: 'spring'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['gateway:8080','product-service:8080','order-service:8080']
Grafana监控看板包含:
- JVM内存/线程监控
- 微服务调用拓扑图
- 业务指标(订单创建速率、支付成功率等)
- 异常告警(5xx错误率>1%自动触发)
6.2 日志收集方案
采用ELK+Filebeat架构:
yaml复制# filebeat.yml
filebeat.inputs:
- type: log
paths:
- /var/log/service/*.log
output.logstash:
hosts: ["logstash:5044"]
日志规范要求所有服务统一格式:
java复制@Slf4j
public class OrderController {
public ResponseEntity createOrder() {
MDC.put("traceId", UUID.randomUUID().toString());
log.info("Create order start, params: {}", params);
// ...
}
}
7. 部署与扩展方案
7.1 Kubernetes部署文件示例
Deployment配置片段:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: product-service
spec:
replicas: 3
strategy:
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
template:
spec:
containers:
- name: product
image: registry.example.com/product:v1.2.0
resources:
limits:
cpu: "2"
memory: 2Gi
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
7.2 自动扩缩容策略
基于Keda的自动伸缩配置:
yaml复制apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: order-service-scaler
spec:
scaleTargetRef:
name: order-service
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus-server
metricName: order_pending_count
threshold: "100"
query: sum(rate(order_pending_total[1m]))
8. 项目经验总结
在实际开发中,有几个关键点需要特别注意:
-
接口版本控制:从项目开始就规范接口版本,我们采用URL路径版本化(/api/v1/orders),避免后期兼容性问题
-
分布式事务取舍:不是所有场景都需要强一致性,比如客户评价功能最终采用异步补偿机制,将系统吞吐量提升了40%
-
测试策略:
- 单元测试覆盖核心算法
- 契约测试保证接口兼容性
- 混沌测试验证系统容错能力
-
文档管理:使用Swagger+Knife4j自动生成API文档,但需要特别注意:
java复制@Configuration
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30)
.securitySchemes(Collections.singletonList(
new ApiKey("Authorization", "Authorization", "header")))
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.build();
}
}
这个项目让我深刻体会到微服务架构的灵活性优势。在后期客户新增跨境电商模块时,我们仅用2周就完成了独立服务的开发和集成,这要归功于前期良好的架构设计。建议开发类似系统时,一定要在前期做好领域划分和接口规范定义。