三、系统分解与边界划分
3.1 限界上下文(Bounded Context)
限界上下文定义:
上下文 A: 订单上下文
核心概念: Order, OrderItem, OrderStatus
职责: 订单创建、修改、取消、查询
事件: OrderCreated, OrderPaid, OrderCancelled
数据: 订单表、订单明细表
上下文 B: 库存上下文
核心概念: Product, Inventory, Reservation
职责: 库存管理、库存扣减、库存预留
数据: 商品表、库存表、预留记录表
上下文 C: 支付上下文
核心概念: Payment, Transaction, Refund
职责: 支付处理、退款、对账
数据: 支付单表、交易流水表
上下文映射模式:
- 合作关系: 订单上下文 ↔ 库存上下文(同步RPC调用)
- 防腐层: 订单上下文 → 物流上下文(通过适配器隔离)
- 开放主机服务: 支付上下文提供标准API
3.2 防腐层(Anti-Corruption Layer)
/**
* 防腐层示例:隔离外部物流系统
*/
@Service
public class LogisticsAntiCorruptionLayer {
private final ThirdPartyLogisticsClient legacyClient;
private final LogisticsMapper mapper;
private final CircuitBreaker circuitBreaker;
// 适配器:将外部模型转换为内部模型
public ShipmentResult createShipment(InternalShipmentRequest request) {
// 1. 转换为外部系统格式
ExternalShipmentRequest externalRequest = mapper.toExternal(request);
// 2. 调用外部系统(带熔断)
ExternalShipmentResponse externalResponse = circuitBreaker.execute(() ->
legacyClient.createShipment(externalRequest)
);
// 3. 处理外部系统的特殊响应
if (externalResponse.getCode() == 503) {
// 降级策略:记录任务,异步重试
saveToRetryQueue(request);
return ShipmentResult.deferred();
}
// 4. 转换为内部模型
return mapper.toInternal(externalResponse);
}
}
// 映射器:隔离外部模型变化的影响
@Component
public class LogisticsMapper {
public ExternalShipmentRequest toExternal(InternalShipmentRequest internal) {
ExternalShipmentRequest external = new ExternalShipmentRequest();
external.setOrderId(internal.getOrderId());
external.setReceiverName(internal.getReceiverName());
external.setReceiverAddress(internal.getAddress().toString());
external.setPackageWeight(internal.getWeight().getGrams());
// 外部系统使用旧的单位制
external.setPackageLength((int) (internal.getLength().getCm() * 10));
return external;
}
public ShipmentResult toInternal(ExternalShipmentResponse external) {
ShipmentResult result = new ShipmentResult();
result.setTrackingNumber(external.getWaybillNo());
result.setEstimatedDelivery(external.getEstimateDate());
result.setStatus(mapStatus(external.getStatus()));
return result;
}
private ShipmentStatus mapStatus(String externalStatus) {
switch (externalStatus) {
case "CREATED": return ShipmentStatus.PENDING;
case "PICKED": return ShipmentStatus.PICKED;
case "DELIVERED": return ShipmentStatus.DELIVERED;
default: return ShipmentStatus.UNKNOWN;
}
}
}
3.3 服务边界划分原则
/**
* 服务划分检查清单
*/
public class ServiceBoundaryChecklist {
// 1. 单一职责:一个服务只做一件事
// 2. 独立性:服务可以独立开发、测试、部署、扩展
// 3. 数据边界:服务拥有自己的数据存储(不应共享数据库)
// 4. 团队边界:一个服务由一个团队维护
// 5. 变更边界:不同服务的变更频率应该独立
// 反模式检查
boolean isDistributedMonolith(Service a, Service b) {
// 如果两个服务经常需要同时部署,就是分布式单体
return a.deploymentFrequency == b.deploymentFrequency;
}
boolean hasSharedDatabase(Service a, Service b) {
// 共享数据库破坏服务边界
return a.database == b.database;
}
boolean hasChattyCalls(Service a, Service b) {
// 循环调用或批量调用过多
return a.callsTo(b) > 100 && a.callsTo(b) < 1000;
}
}
四、非功能性需求设计
4.1 非功能性需求清单
性能:
- 预期QPS/TPC: 峰值 10000 QPS
- 响应时间: P99 < 200ms
- 吞吐量: 每秒处理 5000 笔订单
可用性:
- SLA目标: 99.99%(每年宕机 < 52分钟)
- MTBF: 平均故障间隔 > 30天
- MTTR: 平均恢复时间 < 15分钟
可扩展性:
- 水平扩展: 支持从3节点扩展到100节点
- 数据扩展: 支持每年2倍数据增长
- 功能扩展: 支持插件化扩展新支付方式
安全性:
- 认证: OAuth2/JWT
- 授权: RBAC权限模型
- 数据加密: TLS传输 + 字段级加密
- 合规: GDPR, PCI-DSS
可维护性:
- 代码质量: 圈复杂度 < 10
- 文档完整: API文档、架构决策记录
- 可测试性: 单元测试覆盖率 > 80%
可靠性:
- 数据持久化: 强一致或最终一致
- 灾备: RTO < 1小时, RPO < 5分钟
- 容错: 熔断、重试、降级
可观测性:
- 日志: 结构化日志, 分级管理
- 指标: 业务指标、技术指标
- 追踪: 全链路分布式追踪
4.2 SLA、SLO、SLI设计
SLI (Service Level Indicator): 服务质量指标
- 请求成功率: 成功请求数 / 总请求数
- 延迟: P99响应时间
- 吞吐量: QPS
- 可用性: 服务可访问时间比例
SLO (Service Level Objective): 服务质量目标
- 99.9%的请求成功率 > 99.99%
- P99延迟 < 200ms
- 可用性 > 99.99%
SLA (Service Level Agreement): 服务等级协议
- 承诺:99.99%可用性
- 补偿:每降低0.01%赔偿1%月费
- 例外:计划维护、第三方故障
计算公式:
- 可用性 = (总时间 - 不可用时间) / 总时间 × 100%
- 错误预算 = 1 - SLO目标
(99.99% SLO → 0.01%错误预算 ≈ 52分钟/年)
// SLI监控实现示例
@Component
public class SLIMonitor {
private final AtomicLong totalRequests = new AtomicLong();
private final AtomicLong successRequests = new AtomicLong();
private final Histogram latencyHistogram = Histogram.build()
.buckets(1, 5, 10, 25, 50, 100, 200, 500, 1000)
.register();
@Around("@annotation(Monitored)")
public Object monitor(ProceedingJoinPoint joinPoint) throws Throwable {
totalRequests.incrementAndGet();
long start = System.currentTimeMillis();
try {
Object result = joinPoint.proceed();
successRequests.incrementAndGet();
return result;
} finally {
long latency = System.currentTimeMillis() - start;
latencyHistogram.observe(latency);
}
}
@Scheduled(fixedDelay = 60000)
public void reportSLO() {
long total = totalRequests.getAndSet(0);
long success = successRequests.getAndSet(0);
double successRate = total > 0 ? (double) success / total : 1.0;
double p99 = latencyHistogram.quantile(0.99);
// 发送到监控系统
metrics.push("sl_success_rate", successRate);
metrics.push("sl_p99_latency", p99);
// 检查是否违反SLO
if (successRate < 0.999) {
alert.send("SLO Violation: success rate below 99.9%");
}
if (p99 > 200) {
alert.send("SLO Violation: P99 latency above 200ms");
}
}
}
4.3 容错设计模式
/**
* 超时控制
*/
public class TimeoutConfiguration {
@Bean
public RestTemplate restTemplate() {
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(1000) // 连接超时1秒
.setSocketTimeout(3000) // 读超时3秒
.setConnectionRequestTimeout(500) // 从池获取连接超时
.build();
return new RestTemplateBuilder()
.setConnectTimeout(Duration.ofSeconds(1))
.setReadTimeout(Duration.ofSeconds(3))
.build();
}
// 超时建议:
// - 连接超时: 通常是网络问题,100-1000ms
// - 读超时: 取决于业务处理时间,预估P99 * 2
// - 避免使用过长的超时(会堆积线程)
// - 超时后必须有降级或重试逻辑
}
/**
* 重试策略
*/
@Component
public class RetryConfiguration {
@Retryable(
value = {RemoteServiceException.class},
maxAttempts = 3,
backoff = @Backoff(delay = 100, multiplier = 2, maxDelay = 5000)
)
public String callRemoteService() {
// 重试间隔:100ms, 200ms, 400ms
return restTemplate.getForObject("http://service/api", String.class);
}
// 重试注意事项:
// 1. 只对幂等操作进行重试
// 2. 设置最大重试次数(避免死循环)
// 3. 使用退避策略避免重试风暴
// 4. 区分可重试异常(网络超时)和不可重试异常(参数错误)
}
/**
* 熔断器
*/
@Service
public class CircuitBreakerService {
private final CircuitBreaker circuitBreaker;
public CircuitBreakerService() {
CircuitBreakerConfig config = CircuitBreakerConfig.custom()
.failureRateThreshold(50) // 失败率阈值50%
.slidingWindowSize(10) // 滑动窗口大小
.minimumNumberOfCalls(5) // 最少调用次数
.waitDurationInOpenState(Duration.ofSeconds(30)) // 熔断开启时间
.permittedNumberOfCallsInHalfOpenState(3) // 半开状态试探请求数
.build();
this.circuitBreaker = CircuitBreaker.of("payment-service", config);
}
public PaymentResult processPayment(PaymentRequest request) {
return circuitBreaker.executeSupplier(() -> {
return restTemplate.postForObject("http://payment/api/charge", request, PaymentResult.class);
});
}
}
/**
* 舱壁隔离(线程池隔离)
*/
@Component
public class BulkheadConfig {
// 为不同服务分配独立的线程池
@Bean(name = "paymentExecutor")
public ExecutorService paymentExecutor() {
return new ThreadPoolExecutor(
10, 20, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
new NamedThreadFactory("payment"),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
@Bean(name = "orderExecutor")
public ExecutorService orderExecutor() {
return new ThreadPoolExecutor(
20, 50, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(200),
new NamedThreadFactory("order"),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
// 使用舱壁隔离
@Async("paymentExecutor")
public CompletableFuture<PaymentResult> processPaymentAsync(PaymentRequest request) {
// 支付调用不会影响订单处理
}
}