百万 QPS 不是洪水猛兽:高流量服务的采样、聚合与可视化,咱得这么干!

简介: 百万 QPS 不是洪水猛兽:高流量服务的采样、聚合与可视化,咱得这么干!

百万 QPS 不是洪水猛兽:高流量服务的采样、聚合与可视化,咱得这么干!

大家好,我是 Echo_Wish。
今天咱聊一个很多同学一想到就头皮发麻的话题——百万 QPS 服务的追踪与可观测性建设。

不少人一听“百万 QPS”就以为要上最贵的监控方案,卖房买服务器那种。
其实不用这么夸张。高流量不是问题,不会监控才是问题

尤其是分布式追踪(tracing),如果你还想着给每个请求都打 span,那我劝你先深呼吸三秒。百万 QPS 给你打 span?那你的链路追踪系统会直接变成链路“阻塞”系统。

今天我就跟大家掰开揉碎讲清楚:百万 QPS 下,我们到底该如何做采样、如何做聚合、又如何把它可视化?

放心,全是接地气的干货,不讲那些论文式的废话。


一、为什么百万 QPS 不能全量追踪?

举个例子:

一个请求链路产生 10 个 span。
如果你有 1,000,000 QPS。

那么你要写入的 Span 数量是:

1,000,000 × 10 = 10,000,000 spans per second

10M span/s?

别闹了,那不是 tracing,这是 DDoS tracing backend。
你的 Jaeger、Tempo、Zipkin、SkyWalking 全得跪。

所以高流量服务的追踪,第一条原则:


【原则 1:永远不要全量存储请求链路】

要做的是:

✔ 合理的采样
✔ 高效的聚合
✔ 有意义的可视化

千万别犯那种“领导要全量链路”这种天真错误。


二、采样策略:不是乱抽样,而是“有目的地抽样”

采样是百万 QPS 下的灵魂操作,采样做得好,一切都顺;做不好,就是噩梦。

这里我给大家三个大厂常用的采样策略。


采样策略 1:固定比率采样(概率采样)

比如你只取万分之一:

import random

def should_sample(rate=0.0001):
    return random.random() < rate

if should_sample():
    print("trace this request")

适用于:

  • 稳态流量大
  • 请求类型单一
  • 主要看整体健康情况

缺点:异常请求不一定采集到。


采样策略 2:基于规则的采样(Rule-based Sampling)

根据 URL、业务类型、用户等级等分类采样:

def should_sample(path):
    if path.startswith("/pay"):
        return True
    if path.startswith("/user/query"):
        return random.random() < 0.001
    return random.random() < 0.0001

适用于:

  • 某些接口更关键
  • 有些业务要精准监控
  • 请求种类繁多

采样策略 3:基于异常采样(智能采样)——大厂标配

比如:

  • 请求耗时 > 200ms
  • 返回 5xx
  • 业务错误码出现
  • 限流命中
  • CPU/RT 背压上升
def should_sample_on_error(status, latency):
    if status >= 500:
        return True
    if latency > 0.2:
        return True
    return random.random() < 0.001

这类采样策略能确保异常一定能采集

这是百万 QPS 下最重要的一点:


【高流量服务不追踪正常请求,只追踪异常请求】

全量采样 = 杀死你的追踪系统。


三、聚合策略:从“请求级别”变成“指标级别”

有了采样,下一步是聚合数据。

百万 QPS 的服务如果你想看平均耗时、P99 延迟,你肯定不能拿采样后的请求直接算平均值——这会偏得一塌糊涂。

那么怎么办?

答案是:


【把请求“聚合成指标”,而不是直接查看每条请求】

聚合常见的三个策略:


策略 1:直方图聚合(Histogram)

prometheus 大量使用。

每个请求按延迟区间计数:

request_latency_seconds_bucket{
   le="0.01"} 242  
request_latency_seconds_bucket{
   le="0.02"} 1024  
request_latency_seconds_bucket{
   le="0.05"} 18318  
request_latency_seconds_bucket{
   le="0.1"} 110293  
request_latency_seconds_bucket{
   le="+Inf"} 1000000

优点:

  • 能计算 P90、P95、P99
  • 百万 QPS 下易扩展
  • 对可视化非常友好

策略 2:基于 Sketch 的近似聚合(DDSketch)

Datadog、Kafka Streams、DataSketches 都在用。

特点:

  • 空间复杂度低
  • 可以误差控制
  • 百万 QPS 也不压力

Python 示例:

from datadog.dogsketch import DDSketch

sketch = DDSketch()

for latency in latencies:
    sketch.add(latency)

print(sketch.get_quantile_value(0.99))

这类 sketch 适合追踪延迟、包大小、队列长度等高频指标。


策略 3:基于 Trace 聚合的“Span 分组统计”

比如你可以对某个接口统计:

  • Span 数量
  • 平均耗时
  • 错误占比
  • 下游依赖耗时分布

示例(伪代码):

stats = {
   }

for span in spans:
    key = span.operation
    if key not in stats:
        stats[key] = {
   "count": 0, "error": 0, "latency": []}

    stats[key]["count"] += 1
    stats[key]["latency"].append(span.duration)

    if span.status >= 500:
        stats[key]["error"] += 1

这种的关键思路:


**你不是为了查“每个请求发生了什么”,

而是为了查“整个系统发生了什么”。**


四、百万 QPS 的可视化策略:你需要的是“大盘”,不是“显微镜”

这一点是很多团队最容易翻车的地方。

高流量服务的可视化要遵循一个原则:


【大盘看健康,采样看异常,回溯看细节】

换句话说:

  • 健康情况:靠指标(Prometheus/Grafana)
  • 异常请求:靠采样 Trace(Jaeger/Tempo)
  • 深度排查:靠回溯某个异常请求

你不要把所有 trace 都画出来,那会像看“蚯蚓满天飞”。

下面我给你一个最实用的大盘布局逻辑:


大盘 1:请求流量 & 错误率

  • QPS
  • HTTP Status 分布
  • 业务错误码分布
sum(rate(request_total[1m]))
sum(rate(request_5xx_total[1m]))

这图最好永远放左上角。


大盘 2:延迟直方图(P99、P999)

重点盯:

  • RT 突升
  • P99 波动
  • 长尾延迟变长

这往往等于下游有问题。


大盘 3:慢请求样本(Trace 列表)

✓ 按耗时排序
✓ 按错误优先
✓ 按业务接口分组

这通常是“定位问题的入口”。


大盘 4:依赖拓扑图(Service Map)

高流量微服务必备:

  • 谁调用了谁
  • 哪个链路拖慢整体
  • 下游哪个节点延迟暴涨

可视化示例(OpenTelemetry + Tempo)就是那类“气泡图”。


五、我踩坑总结(血泪教训版)

多年运维经验总结几点给你,绝对能少走弯路:


1. 千万不要把 trace 当作指标使用(会延迟偏差)

Trace 是抽样的。
指标才是全量的。


2. 千万不要采样过低,否则“异常看不到”

普遍问题:

  • trace rate=0.0001
  • 异常 QPS 大约 5 QPS
  • 你一天能抓到一条异常 trace 就不错了

这根本不够查问题。


3. 千万不要只采样成功请求

这是“看什么是什么,一点都不监控”的典型错误。


4. 聚合一定要做直方图,而不是平均值

平均值 = 谎言制造机。


5. 千万不要把所有 trace 都展示在一个大图上

那不是 tracing,那是艺术创作。


六、最后想说一句:高流量不是问题,“可观测性不科学”才是问题

百万 QPS 听起来很猛,但本质上:

  • 流量是数据
  • 数据是规律
  • 规律是可以被测量、聚合、可视化的

可观测性建设不是为了做“炫酷大屏”,
是为了:

✔ 让系统稳
✔ 让问题可查
✔ 让值班工程师不再被叫醒

目录
相关文章
|
3月前
|
运维 安全 API
当安全事件不再“靠人吼”:一文带你搞懂 SOAR 自动化响应实战
当安全事件不再“靠人吼”:一文带你搞懂 SOAR 自动化响应实战
286 10
|
3月前
|
存储 运维 安全
别再把 Collector 当黑箱:OpenTelemetry Collector 拓展与自定义处理器实战指南
别再把 Collector 当黑箱:OpenTelemetry Collector 拓展与自定义处理器实战指南
267 14
|
3月前
|
缓存 运维 应用服务中间件
《Nginx在嵌入式场景的高效配置与运维逻辑》
本文聚焦边缘节点、嵌入式设备等资源受限场景,分享轻量型Nginx的部署配置实践与技术思考。核心围绕“按需构建、精准适配”理念,打破传统全量部署思维,通过依赖精简、模块取舍实现资源极致利用。搭建环节聚焦系统选型与依赖管控,优先适配轻量操作系统并清理冗余组件;配置环节以场景为导向,针对静态资源服务、请求转发等不同需求优化参数,平衡功能与性能;运维阶段强调动态适配与持续清理,保障长期高效运行。文章深入探讨轻量部署的底层逻辑,传递“工具价值源于场景适配”的技术思维,为资源敏感环境下的Nginx应用提供实用解决方案与独特视角,助力技术人突破资源限制实现高效服务支撑。
125 5
|
域名解析 负载均衡 架构师
Nginx极简入门(六)配置Nginx负载均衡,提高系统并发性能!
前面讲了如何配置Nginx虚拟主机、如何配置反向代理。Nginx最主要的功能就是反向代理和负载均衡。今天要说的是如何配置nginx和tomcat实现反向代理。
Nginx极简入门(六)配置Nginx负载均衡,提高系统并发性能!
|
3月前
|
安全 Java 微服务
更优雅的条件分支:Java 17 Switch表达式实践
更优雅的条件分支:Java 17 Switch表达式实践
159 29
|
3月前
|
安全 Java API
Java日期处理完全指南(新手也能轻松掌握的Java时间格式化与日期API教程)
教程来源https://www.vpshk.cn/本文介绍Java 8引入的java.time包,详解LocalDateTime、LocalDate等类的使用,涵盖获取当前时间、格式化、解析字符串及日期运算,助你轻松掌握现代Java日期处理方法,适合初学者快速上手。
|
JavaScript 搜索推荐 Android开发
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
512 8
【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
|
Cloud Native Java Nacos
Consul 留给你的时间不多了
Consul 留给你的时间不多了
655 86
|
Prometheus Cloud Native Java
OpenTelemetry: 经得起考验的工具
OpenTelemetry: 经得起考验的工具
2446 2
|
Web App开发 JavaScript 前端开发
解决DevTools failed to load SourceMap Could not load content for .js.map HTTP error code 404 问题
解决DevTools failed to load SourceMap Could not load content for .js.map HTTP error code 404 问题
1922 0

热门文章

最新文章