十年前我刚入行时,参与的第一个项目是单体架构的图书管理系统。当用户量突破5000时,系统开始频繁崩溃,那次通宵排查问题的经历让我深刻认识到:在互联网三高(高并发、高可用、高性能)需求面前,传统集中式架构就像用算盘处理天文数据。如今作为经历过20+分布式项目的老兵,我想分享些实战心得。
分布式系统本质是通过网络连接的独立计算机集合,对外表现为统一系统。其核心特征中,最关键的三个是:
我在电商项目中的教训:初期按功能模块拆分为用户、订单、商品三个服务,结果订单服务成为瓶颈。后来采用**领域驱动设计(DDD)**重新划分:
重要经验:服务粒度不是越小越好,每次RPC调用增加5-10ms延迟。建议初期保持适度粗粒度,随业务演进再拆分。
常用通信方式性能实测数据(单次调用耗时):
| 协议类型 | 平均延迟 | 适用场景 |
|---|---|---|
| HTTP/1.1 | 35ms | 对外API、浏览器兼容 |
| HTTP/2 | 22ms | 内部服务、多路复用 |
| gRPC(HTTP/2) | 18ms | 高性能内部调用 |
| WebSocket | 28ms | 实时推送场景 |
| Dubbo协议 | 15ms | Java生态内部服务 |
我在物联网项目中混合使用gRPC和WebSocket,设备控制用gRPC保证时效性,状态推送用WebSocket减少连接开销。
电商秒杀场景下的库存一致性方案演进:
java复制// Redis原子递减
Long remain = redisTemplate.opsForValue()
.increment("stock:"+itemId, -1);
if(remain >= 0) {
// 异步消息队列处理订单
kafkaTemplate.send("order-create", order);
}
以Spring Cloud Alibaba为例,注册中心选型对比:
| 组件 | CP/AP | 健康检查 | 适用规模 |
|---|---|---|---|
| Nacos | 可切换 | 多种策略 | <500节点 |
| Zookeeper | CP | 心跳 | <300节点 |
| Consul | CP | 主动探测 | <1000节点 |
避坑指南:
/actuator/deregister接口,避免流量损失多环境配置管理方案:
code复制├── application.yml
├── application-dev.yml
├── application-test.yml
└── application-prod.yml
通过spring.profiles.active指定环境,结合Nacos配置中心实现:
java复制@RefreshScope
@RestController
public class ConfigController {
@Value("${custom.config}")
private String config;
}
关键点:配置变更时,使用
@RefreshScope注解的Bean会动态刷新,但静态变量不会更新,这是常见配置失效的原因。
Sentinel规则配置示例:
java复制// 限流规则
FlowRule rule = new FlowRule();
rule.setResource("createOrder");
rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
rule.setCount(100); // 阈值
FlowRuleManager.loadRules(Collections.singletonList(rule));
// 降级规则
DegradeRule degradeRule = new DegradeRule();
degradeRule.setResource("queryOrder");
degradeRule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
degradeRule.setCount(200); // 响应时间阈值(ms)
degradeRule.setTimeWindow(10); // 熔断时长(s)
典型错误:
SkyWalking探针配置关键参数:
properties复制# 应用名
agent.service_name=${SW_AGENT_NAME:my-service}
# 采样率
agent.sample_n_per_3_secs=${SW_AGENT_SAMPLE:5}
# 忽略特定端点
agent.ignore_suffix=${SW_AGENT_IGNORE:.jpg,.css}
追踪数据关联技巧:
sw8头部:java复制ContextCarrier carrier = new ContextCarrier();
ContextManager.inject(carrier);
executor.execute(() -> {
ContextManager.extract(carrier);
// 异步任务逻辑
});
常见方案对比:
| 方案 | 一致性 | 性能 | 适用场景 |
|---|---|---|---|
| 2PC | 强一致 | 差 | 金融核心交易 |
| TCC | 最终 | 中 | 高并发订单 |
| SAGA | 最终 | 好 | 长事务流程 |
| 本地消息表 | 最终 | 好 | 异步通知场景 |
| 事务消息 | 最终 | 中 | 跨系统数据同步 |
TCC模式开发要点:
ShardingSphere配置示例:
yaml复制spring:
shardingsphere:
datasource:
names: ds0,ds1
sharding:
tables:
t_order:
actual-data-nodes: ds$->{0..1}.t_order_$->{0..15}
table-strategy:
inline:
sharding-column: order_id
algorithm-expression: t_order_$->{order_id % 16}
database-strategy:
inline:
sharding-column: user_id
algorithm-expression: ds$->{user_id % 2}
分片键选择原则:
多级缓存架构示例:
code复制请求 → Nginx本地缓存 → Redis集群 → JVM缓存 → DB
关键实现代码:
java复制public Product getProduct(Long id) {
// 1. 查JVM缓存
Product product = caffeineCache.get(id);
if(product == null) {
// 2. 查Redis
String json = redisTemplate.opsForValue().get("product:"+id);
if(json != null) {
product = JSON.parseObject(json, Product.class);
// 回填本地缓存
caffeineCache.put(id, product);
} else {
// 3. 查数据库
product = productMapper.selectById(id);
// 异步写入Redis
asyncExecutor.execute(() -> {
redisTemplate.opsForValue().set(
"product:"+id,
JSON.toJSONString(product),
5, TimeUnit.MINUTES);
});
}
}
return product;
}
订单创建流程优化前后对比:
改造前(同步):
改造后(异步):
java复制public void createOrder(OrderDTO dto) {
// 1. 预扣库存(同步)
stockService.decrease(dto.getItemId(), dto.getCount());
// 2. 发送领域事件
eventPublisher.publishEvent(new OrderCreatedEvent(dto));
// 3. 立即返回
return Result.success();
}
// 事件处理器
@EventListener
public void handleOrderCreated(OrderCreatedEvent event) {
// 异步执行后续步骤
asyncExecutor.execute(() -> {
orderService.save(event.getOrder());
logisticsService.create(event.getOrder());
notifyService.send(event.getOrder());
});
}
→ 主流程耗时降至120ms
OAuth2+JWT实现要点:
java复制@Configuration
@EnableAuthorizationServer
public class AuthConfig extends AuthorizationServerConfigurerAdapter {
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("webapp")
.secret(passwordEncoder.encode("secret"))
.scopes("read", "write")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(3600);
}
}
// 资源服务器配置
@EnableResourceServer
public class ResourceConfig extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/api/**").authenticated()
.antMatchers("/admin/**").hasRole("ADMIN");
}
}
安全建议:
生产环境网络分区示例:
code复制公网区域 → DMZ区(网关) → 应用区 → 数据区
关键控制措施:
Prometheus+Grafana监控项配置:
yaml复制# prometheus.yml
scrape_configs:
- job_name: 'spring_app'
metrics_path: '/actuator/prometheus'
static_configs:
- targets: ['app:8080']
关键监控指标:
ELK技术栈优化实践:
code复制Filebeat(日志采集) → Kafka(缓冲) → Logstash(处理) → ES(存储)
日志规范建议:
[%d{yyyy-MM-dd HH:mm:ss}] [%thread] [%-5level] [%logger{36}] - %msg%n分层构建示例:
dockerfile复制# 构建阶段
FROM maven:3.8-jdk-11 as builder
COPY pom.xml .
RUN mvn dependency:go-offline
COPY src/ ./src/
RUN mvn package -DskipTests
# 运行阶段
FROM openjdk:11-jre-slim
COPY --from=builder /target/app.jar /app.jar
USER nobody
ENTRYPOINT ["java","-jar","/app.jar"]
优化技巧:
Deployment配置要点:
yaml复制apiVersion: apps/v1
kind: Deployment
metadata:
name: order-service
spec:
replicas: 3
selector:
matchLabels:
app: order
template:
spec:
containers:
- name: order
image: registry/order:v1.2
resources:
limits:
cpu: "2"
memory: 2Gi
readinessProbe:
httpGet:
path: /actuator/health
port: 8080
initialDelaySeconds: 30
调度策略:
ArgoCD应用定义:
yaml复制apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: payment-service
spec:
destination:
namespace: production
server: https://kubernetes.default.svc
source:
path: k8s/overlays/prod
repoURL: git@github.com:myorg/config.git
targetRevision: HEAD
syncPolicy:
automated:
prune: true
selfHeal: true
流程规范:
Chaos Mesh实验示例:
yaml复制apiVersion: chaos-mesh.org/v1alpha1
kind: NetworkChaos
metadata:
name: network-delay
spec:
action: delay
mode: one
selector:
namespaces:
- production
labelSelectors:
"app": "order-service"
delay:
latency: "500ms"
correlation: "100"
jitter: "100ms"
duration: "5m"
测试策略:
现象:零点秒杀时订单服务雪崩
根因分析:
改进措施:
现象:订单已支付但库存未扣减
排查过程:
解决方案:
java复制@KafkaListener(topics = "order-pay")
public void handlePayEvent(PayEvent event) {
// 幂等检查
if(paymentService.isProcessed(event.getId())) {
return;
}
// 业务处理
inventoryService.decrease(event.getItemId());
paymentService.markProcessed(event.getId());
}
不同规模下的架构选择:
| 团队规模 | 推荐架构 | 核心组件 |
|---|---|---|
| 5人以下 | 单体+模块化 | Spring Boot + MyBatis |
| 5-20人 | 微服务雏形 | Spring Cloud + Nacos |
| 20-50人 | 完整微服务 | K8s + Istio + Sentinel |
| 50人以上 | 服务网格 | 自研中间件+全链路治理 |
平滑迁移示例(单体→微服务):
我的日常开发环境:
性能排查利器:
bash复制# 查看方法调用耗时
trace com.example.Service * '#cost > 100'
Git分支模型优化:
code复制main(保护分支) ← release/*(发布分支) ← feature/*(功能分支)
代码审查要点:
Swagger+Knife4j集成:
java复制@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.paths(PathSelectors.any())
.build()
.apiInfo(metaData());
}
}
文档驱动开发:
电商应用推荐配置:
bash复制# JDK11+ G1GC参数
-XX:+UseG1GC
-XX:MaxGCPauseMillis=200
-XX:InitiatingHeapOccupancyPercent=45
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=512m
-Xms4g -Xmx4g # 堆内存设为相同避免扩容
调优步骤:
慢查询优化前后对比:
sql复制-- 优化前(执行时间1.8s)
SELECT * FROM orders
WHERE status = 'PAID'
ORDER BY create_time DESC;
-- 优化后(执行时间0.02s)
SELECT * FROM orders
WHERE status = 'PAID'
ORDER BY create_time DESC
LIMIT 100;
优化手段:
Istio流量管理示例:
yaml复制apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: product-vs
spec:
hosts:
- product-service
http:
- route:
- destination:
host: product-service
subset: v1
weight: 90
- destination:
host: product-service
subset: v2
weight: 10
落地难点:
Spring Cloud Function示例:
java复制@Bean
public Function<String, String> uppercase() {
return value -> value.toUpperCase();
}
适用场景:
分布式核心知识图谱:
我反复阅读的经典:
技术深度与广度的平衡:
架构设计评估框架:
典型反模式:
合理原则:
我踩过的坑:
选型 checklist:
分布式系统开发就像建造城市,既要规划主干道(核心架构),也要设计小巷弄(服务细节)。我总结的三条经验:
最后分享一个实用技巧:在架构设计文档中,永远保留"已知问题"章节,这能帮助团队保持技术清醒。就像我在当前项目中标注的:"消息积压处理方案待优化,预计Q3引入背压机制"。这种坦诚反而能赢得信任。