1. 项目背景与核心价值
在分布式系统架构中,我们常常面临这样的矛盾:一方面需要通过限流工具(如Sentinel)保护系统不被突发流量击垮,另一方面又需要全链路追踪工具(如SkyWalking/Zipkin)来定位问题。但传统模式下,被限流的请求往往直接从入口处被拒绝,导致后续链路完全丢失,给问题排查带来巨大困难。
这个项目要解决的正是这个痛点。通过将Sentinel与SkyWalking/Zipkin深度集成,我们能够:
- 完整记录被限流请求的"生前轨迹"
- 分析哪些类型的请求更容易被限流
- 区分系统过载和恶意攻击的不同模式
- 为容量规划提供数据支撑
2. 技术方案设计
2.1 整体架构设计
核心思路是在Sentinel的BlockException处理环节植入追踪逻辑:
code复制请求进入 → Sentinel限流检查 → 触发限流 →
记录当前Span信息 → 构造虚拟链路 →
上报至追踪系统 → 返回限流响应
2.2 关键集成点
2.2.1 Sentinel适配层
java复制public class TracingBlockExceptionHandler implements BlockExceptionHandler {
@Override
public void handle(HttpServletRequest request,
HttpServletResponse response,
BlockException e) throws Exception {
// 获取当前追踪上下文
ContextSnapshot snapshot = ContextManager.capture();
// 创建虚拟span
AbstractSpan span = ContextManager.createEntrySpan("sentinel_block", snapshot);
span.tag("rule", e.getRule().toString());
span.tag("type", e.getClass().getSimpleName());
// 记录原始请求信息
span.tag("http.method", request.getMethod());
span.tag("http.url", request.getRequestURL().toString());
// 上报并返回标准限流响应
span.errorOccurred();
ContextManager.stopSpan();
response.setStatus(429);
response.getWriter().print("Too many requests");
}
}
2.2.2 追踪系统适配
对于SkyWalking需要实现ISpan接口,Zipkin则需要转换为Brave的Span模型。这里以SkyWalking为例:
java复制class SkyWalkingSpanAdapter implements ISpan {
private final AbstractSpan delegate;
public void tag(String key, String value) {
delegate.tag(key, value);
}
public void log(Throwable t) {
delegate.log(t);
}
}
3. 实现细节与避坑指南
3.1 上下文传递的陷阱
在异步限流场景下,直接使用ThreadLocal存储的追踪上下文会丢失。必须显式传递:
java复制// 错误示例
executor.submit(() -> {
// 这里获取不到上下文!
handleBlockRequest();
});
// 正确做法
ContextSnapshot snapshot = ContextManager.capture();
executor.submit(() -> {
try (Scope ignored = snapshot.attach()) {
handleBlockRequest();
}
});
3.2 采样率控制
被限流请求可能数量巨大,需要动态采样:
java复制// 基于QPS的智能采样
if (blockQps.get() > 1000 && random.nextDouble() > 0.1) {
return; // 只采样10%
}
3.3 虚拟链路构造
为保持链路完整性,需要补全各服务节点:
java复制void buildVirtualTrace(AbstractSpan span, HttpServletRequest request) {
span.setComponent(SENTINEL_COMPONENT);
span.setLayer(SpanLayer.PROXY);
// 从Header中恢复上游信息
String upstreamService = request.getHeader("X-Upstream-Service");
if (upstreamService != null) {
span.tag("upstream.service", upstreamService);
}
}
4. 生产环境配置建议
4.1 Sentinel配置
properties复制# 启用自定义Block处理器
sentinel.web.servlet.block-page-handler=com.your.pkg.TracingBlockExceptionHandler
# 限流规则示例
sentinel.flow.rule.api[0].resource=/api/v1/orders
sentinel.flow.rule.api[0].count=100
sentinel.flow.rule.api[0].grade=1
4.2 SkyWalking Agent配置
properties复制# 开启Sentinel插件
plugin.sentinel=default
# 采样率配置
agent.sample_n_per_3_secs=-1 # 全采样
agent.force_sample_error=true # 强制采样错误
5. 典型问题排查
5.1 追踪信息丢失
现象:SkyWalking中看不到限流记录
检查:
- 确认采样率配置
- 检查Span是否正确调用finish()
- 验证上下文传递是否完整
5.2 性能影响
当QPS>5000时可能出现:
- 解决方案:
- 增加采样过滤
- 改用异步上报
java复制
executor.submit(() -> { tracingClient.report(span); });
6. 数据分析应用
通过收集的限流追踪数据,可以:
- 绘制热点限流API排行榜
- 分析限流时间分布规律
- 关联日志定位具体异常
sql复制-- 示例分析查询
SELECT
operation_name,
COUNT(*) as block_count,
AVG(duration) as avg_latency
FROM traces
WHERE tags['type'] = 'FlowException'
GROUP BY operation_name
ORDER BY block_count DESC
这种集成方案在电商大促场景中尤为有用。某次618大促期间,我们通过分析限流链路发现,80%的限流集中在商品详情页的推荐模块调用上,最终通过服务拆分将峰值容量提升了3倍。