亿级分布式系统架构演进实战(一)- 总体概要
亿级分布式系统架构演进实战(二)- 横向扩展(服务无状态化)
亿级分布式系统架构演进实战(三)- 横向扩展(数据库读写分离)
亿级分布式系统架构演进实战(四)- 横向扩展(负载均衡与弹性伸缩)
亿级分布式系统架构演进实战(五)- 横向扩展(缓存策略设计)
亿级分布式系统架构演进实战(六)- 横向扩展(监控与日志体系)
亿级分布式系统架构演进实战(七)- 横向扩展(安全防护设计)
亿级分布式系统架构演进实战(八)- 垂直拆分(领域划分及垂直分库设计)
亿级分布式系统架构演进实战(九)- 垂直拆分(服务间通信设计)
亿级分布式系统架构演进实战(十)- 垂直拆分(分布式事务管理设计)
目标:提升拆分后的系统可观测性、可控性
• 高可用保障:AP模式确保集群在部分节点故障时仍可提供服务发现能力。
• 健康监测:心跳机制实时剔除异常实例,避免流量路由至宕机节点。
• 集群部署:
# Nacos集群配置(3节点示例)
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.1.10:8848,192.168.1.11:8848,192.168.1.12:8848
namespace: prod
ephemeral: true # AP模式
• 心跳检测优化:
检测策略:
1. 客户端每5秒发送心跳包
2. 服务端连续3次未收到心跳则标记实例不健康
3. 30秒后自动摘除实例
• 跨机房容灾:Nacos节点分散部署在3个可用区。
• 容量规划:单个Nacos集群支撑10万级服务实例注册。
• 流量精细控制:按版本、标签将请求路由至特定服务实例。
• 无损发布:支持灰度发布新商品服务,降低上线风险。
• 路由规则配置:
# Nacos元数据路由规则
spring:
cloud:
gateway:
routes:
- id: product_route
uri: lb://product-service
predicates:
- Header=X-Tag, Gray # 灰度标签匹配
metadata:
version: v2
• 灰度发布流程:
1. 新版本服务部署至20%实例并打标Gray
2. 通过Header/X-Tag分流10%用户请求
3. 监控新版本服务错误率与延迟
4. 全量发布或回滚
• 优势:支持多维度路由(IP、用户ID、Header),灵活适配业务场景。
• 风险:需确保灰度标签传递全链路(通过OpenTelemetry Baggage)。
• 数据安全:防止数据库密码等敏感信息泄露。
• 合规要求:满足等保2.0等安全审计标准。
• 加密流程:
明文配置 → AES加密 → 密文存储 → 运行时解密
• KMS集成:通过阿里云KMS动态获取加密密钥。
• 生产配置示例:
# 加密数据库密码
spring:
datasource:
password: '{cipher}U2FsdGVkX1+Z4Z7v8J7w6j5T7K8J9L0Q1W2E3R4T5Y6U7I8O9P0'
public class DecryptPropertyProcessor implements EnvironmentPostProcessor {
@Override
public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) {
String encryptedPassword = env.getProperty("spring.datasource.password");
String decrypted = AESUtils.decrypt(encryptedPassword, kmsClient.getKey());
env.getPropertySources().addFirst(new MapPropertySource("decrypted",
Collections.singletonMap("spring.datasource.password", decrypted)));
}
}
• 环境隔离:通过Namespace隔离开发、测试、生产配置。
• 动态刷新:@RefreshScope注解支持配置热更新。
# 按服务分环境管理
spring:
cloud:
nacos:
config:
server-addr: 192.168.1.10:8848
namespace: ${spring.profiles.active}
group: ${spring.application.name}
选型背景:
• 行业验证:SkyWalking作为Apache顶级项目,广泛用于微服务监控(如阿里、腾讯生产环境)。
• 功能完备:支持自动拓扑发现、服务性能指标、慢服务检测、链路追踪等。
• 低侵入性:通过Java Agent字节码增强,无需代码改造。
对比优势:
特性 | SkyWalking | OpenTelemetry+Jaeger |
---|---|---|
部署复杂度 | 单一组件,开箱即用 | 需集成多个组件(Collector、Storage等) |
数据可视化 | 内置Dashboard,支持拓扑图、链路追踪 | 依赖第三方UI(如Jaeger UI) |
生产级特性 | 内置告警规则、服务依赖分析 | 需自行开发或集成外部工具 |
集群架构:
组件说明:
• OAP Server:负责接收、分析、存储追踪数据,支持横向扩展。
• Storage:可选H2(测试)、Elasticsearch(生产),本文选择ES集群。
• Web UI:提供可视化Dashboard,展示拓扑图、链路详情、性能指标。
步骤1:Agent下载与部署
# 下载SkyWalking Agent
wget https://archive.apache.org/dist/skywalking/java-agent/8.12.0/apache-skywalking-java-agent-8.12.0.tgz
tar -zxvf apache-skywalking-java-agent-8.12.0.tgz
# 启动服务时挂载Agent
java -javaagent:/path/to/skywalking-agent/skywalking-agent.jar \
-Dskywalking.agent.service_name=order-service \
-Dskywalking.collector.backend_service=sw-oap:11800 \
-jar order-service.jar
关键参数:
• agent.service_name
:服务名(需唯一)。
• collector.backend_service
:OAP Server地址。
# OAP Server配置(application.yml)
storage:
selector: elasticsearch
elasticsearch:
nameSpace: skywalking
clusterNodes: elasticsearch:9200
protocol: http
user: "elastic"
password: "changeme"
indexShardsNumber: 3
indexReplicasNumber: 1
优化建议:
• 分片策略:根据数据量调整分片数(如每日TB级数据需分片6-10个)。
• 保留策略:设置索引生命周期管理(ILM),保留最近30天数据。
# 控制追踪数据量,防止ES过载
agent:
sample:
n_per_3_secs: 10 # 每服务每秒最多10条追踪
buffer:
channel_size: 5000 # 内存队列容量
适用场景:
• 高频服务:支付服务等核心接口,采样率适当调高(如20%)。
• 低频服务:日志服务等非关键链路,采样率可降低至1%。
// 创建自定义Span(订单创建流程)
try (Scope scope = ContextManager.createLocalSpan("OrderCreateProcess")) {
// 业务逻辑
ContextManager.await().tag("order_id", orderId);
ContextManager.await().log("Create order start");
// 添加错误标记
if (error) {
ContextManager.await().error(new RuntimeException("Create failed"));
}
}
应用场景:
• 关键路径标记:标记订单创建、支付回调等核心业务Span。
• 异常监控:手动记录业务异常,触发告警。
实现原理:
• Agent自动上报:服务启动时注册元数据(服务名、实例IP)。
• 依赖分析:通过Span中的跨服务调用信息,自动绘制服务依赖图。
生产视图:
内置告警规则:
# OAP Server告警规则(alarm-settings.yml)
rules:
service_sla:
metrics-name: service_sla
op: "<"
threshold: 99.9 # 服务成功率低于99.9%触发
period: 10 # 统计周期10分钟
count: 1 # 触发次数
message: "Service {name} SLA 低于99.9%"
slow_endpoint:
metrics-name: endpoint_avg
op: ">"
threshold: 2000 # 平均响应时间>2秒
message: "端点 {name} 响应时间超过2秒"
告警通知:
• 支持Webhook、钉钉、邮件等通知渠道。
实现方案:
• JDBC插件:自动追踪SQL执行耗时、参数(需启用skywalking-plugin-jdbc
)。
• 慢SQL检测:标记执行时间>1秒的SQL,生成告警事件。
配置示例:
# Agent插件配置(agent.config)
plugin.jdbc.trace_sql_parameters=true # 记录SQL参数(需安全审核)
plugin.mysql.tracing_sql_parameters=true
• Agent参数调优:
# 调整JVM参数(高并发场景)
-Dskywalking.agent.cool_down_threshold=10000 # 缓冲队列阈值
-Dskywalking.agent.ignore_suffix=.jpg,.css # 忽略静态资源追踪
• 存储层优化:
• Elasticsearch分片预创建,避免动态分片引发性能抖动。
• 数据库耗时分析:
-- 慢SQL统计(MySQL)
SELECT * FROM performance_schema.events_statements_summary_by_digest
ORDER BY SUM_TIMER_WAIT DESC LIMIT 10;
• 链路火焰图:
Jaeger UI → 选择Trace → 查看Span耗时占比
• 问题:订单创建链路中,库存查询占整体耗时的60%。
• 解决方案:引入Redis缓存库存数据,耗时占比降至15%。
目标:保障服务间通信安全,防止数据越权访问
• 身份验证:服务间通信需验证双方证书,防止中间人攻击。
• 数据加密:TLS 1.3协议保障传输层安全。
# 生成CA根证书
openssl req -x509 -newkey rsa:4096 -keyout ca.key -out ca.crt -days 365
# 签发服务证书
openssl req -new -newkey rsa:4096 -keyout service.key -out service.csr
openssl x509 -req -in service.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out service.crt -days 180
server:
ssl:
key-store: classpath:keystore.p12
key-store-password: changeit
key-store-type: PKCS12
client-auth: need # 强制双向认证
• 证书轮换:每90天自动轮换证书,保留旧证书30天兼容期。
• 监控告警:检测证书过期时间(Prometheus Alertmanager)。
• Token生成:
String token = Jwts.builder()
.setSubject("user123")
.claim("roles", "admin")
.signWith(SignatureAlgorithm.HS256, secretKey)
.compact();
• 网关鉴权:
public class JwtFilter implements GatewayFilter {
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getHeaders().getFirst("Authorization");
Claims claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
exchange.getAttributes().put("userId", claims.getSubject());
return chain.filter(exchange);
}
}
• 密钥管理:通过Vault动态获取签名密钥。
• Token刷新:Access Token有效期30分钟,Refresh Token有效期7天。
目标:实现数据行级与字段级安全控制,防止越权访问
• 多租户隔离:自动在SQL查询中追加租户ID条件,实现数据隔离。
• 业务透明:开发人员无需手动处理租户ID,减少代码侵入。
public class TenantContext {
private static final ThreadLocal<String> currentTenant = new ThreadLocal<>();
public static void setTenantId(String tenantId) {
currentTenant.set(tenantId);
}
public static String getTenantId() {
return currentTenant.get();
}
}
@Intercepts({@Signature(type= Executor.class, method="update", args={MappedStatement.class, Object.class})})
public class TenantInterceptor implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
Object parameter = invocation.getArgs()[1];
if (parameter instanceof Criteria) {
Criteria criteria = (Criteria) parameter;
criteria.and("tenant_id").equalTo(TenantContext.getTenantId());
}
return invocation.proceed();
}
}
<configuration>
<plugins>
<plugin interceptor="com.example.TenantInterceptor"/>
plugins>
configuration>
优劣势:
• 优势:自动过滤数据,避免越权查询。
• 风险:需确保租户ID传递正确(如网关层解析JWT后设置上下文)。
• 隐私保护:敏感数据(如手机号、身份证号)在传输和存储前脱敏。
• 合规要求:满足GDPR等数据保护法规。
public class UserDTO {
@JsonSerialize(using = MobileSerializer.class)
private String mobile;
}
public class MobileSerializer extends JsonSerializer<String> {
@Override
public void serialize(String value, JsonGenerator gen, SerializerProvider provider) {
gen.writeString(value.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2"));
}
}
@Around("execution(* com.example..*Service.*(..))")
public Object logSensitiveData(ProceedingJoinPoint joinPoint) throws Throwable {
Object[] args = joinPoint.getArgs();
for (Object arg : args) {
if (arg instanceof User) {
((User) arg).setMobile(maskMobile(((User) arg).getMobile()));
}
}
return joinPoint.proceed();
}
生产级规则:
字段类型 | 脱敏规则 |
---|---|
手机号 | 138****1234 |
身份证号 | 320***************34X |
银行卡号 | 6222 **** **** 5678 |
目标:记录关键操作轨迹,支持事后追溯与合规审计
• 操作追溯:记录数据变更、删除等高危操作。
• 责任界定:通过操作人、时间、IP等信息明确责任。
@Aspect
@Component
public class AuditLogAspect {
@Autowired
private AuditLogService auditLogService;
@Pointcut("@annotation(com.example.audit.AuditLog)")
public void auditPointcut() {}
@Around("auditPointcut()")
public Object logAudit(ProceedingJoinPoint joinPoint) throws Throwable {
Object result = joinPoint.proceed();
AuditLog auditLog = new AuditLog();
auditLog.setOperation(joinPoint.getSignature().getName());
auditLog.setOperator(SecurityContext.getCurrentUser());
auditLog.setIp(RequestContext.getRemoteAddr());
auditLogService.save(auditLog);
return result;
}
}
{
"operation": "deleteOrder",
"operator": "user123",
"ip": "192.168.1.100",
"timestamp": "2023-10-05T14:30:00Z",
"parameters": {"orderId": "1001"}
}
PUT audit_logs
{
"settings": {
"number_of_shards": 5,
"number_of_replicas": 1
},
"mappings": {
"properties": {
"operation": {"type": "keyword"},
"operator": {"type": "keyword"},
"ip": {"type": "ip"},
"timestamp": {"type": "date"}
}
}
}
PUT _ilm/policy/audit_logs_policy
{
"policy": {
"phases": {
"hot": {"actions": {"rollover": {"max_size": "50gb", "max_age": "7d"}}},
"delete": {"min_age": "180d", "actions": {"delete": {}}}
}
}
}
关键能力:
• 实时查询:通过Kibana快速检索操作记录。
• 压缩存储:归档至S3后启用Glacier低频存储,降低成本。
阶段 | 验证内容 | 通过标准 |
---|---|---|
阶段1 | 行级权限拦截器生效性测试 | 未携带租户ID的查询返回空数据集 |
阶段2 | 审计日志记录完整性验证 | 关键操作日志100%写入Elasticsearch |
阶段3 | 日志归档策略验证 | 6个月前的日志自动从ES迁移至S3 |
• 审计日志丢失告警:
# Prometheus规则
- alert: AuditLogLoss
expr: increase(kafka_logs_delivered_total[5m]) < 100
labels:
severity: critical
annotations:
summary: "审计日志投递量异常 (当前值: {{ $value }})"
• 脱敏规则校验:定期扫描日志,检测未脱敏敏感字段。