带宽打满:Java 后端最容易忽略的慢请求元凶

带宽打满:Java 后端最容易忽略的慢请求元凶

Scroll Down

上周排查一个商品列表接口:P99 1.8s,代码 50ms,DB 30ms,CPU 35%——横向加了实例,单节点出口带宽规格没升,还是慢。

最后发现是出站带宽打满了,利用率 96%。响应体在发送队列里排队,客户端才觉得卡。

这类问题 Java 后端不罕见,排查清单里却常漏「带宽」这一项。


一、带宽打满是什么

带宽 = 单位时间内网络能传多少数据,云主机常见上限按 Mbps(兆比特/秒)卖。

Mbps ÷ 8 = MB/s
100Mbps  → 12.5 MB/s
200Mbps  → 25 MB/s

打满 = 出站流量长期顶到上限。这时 CPU、内存、DB 可能都很闲,QPS 却上不去——瓶颈在出口带宽,不在业务代码。

上线前可以粗算天花板:

理论最大 QPS ≈ 带宽(MB/s) ÷ 单次响应体(MB)

100Mbps、单次响应 200KB → 大约 62 QPS。再优化代码也突破不了这条线。


二、Java 开发里哪些写法容易踩坑

场景 典型写法 为什么危险
列表一次吐全量 findAll() 单次响应 MB 级
实体整包返回 关联集合全塞 JSON 字段膨胀
应用层中转文件 Controller 读 OSS 写回响应 文件字节走 ECS 出口
同步导出大表 百万行 Excel 直出 长连接 + 大 payload
微服务传大 DTO Feign/Dubbo 整对象 内网带宽也会满
JSON 不压缩 明文传输 体积多 70% 左右

误区 1:只有下载文件才会占带宽。普通 REST 接口,响应体大 + QPS 高,照样能把 100Mbps 打满。

误区 2:图片链接不就是字符串吗?200 条纯 URL 一般也就 几十 KB,单靠字符串很难打满带宽。体积往往出在:

  • 图片是对象:urlthumbUrl、宽高、排序……
  • 列表项还带了描述、规格、SKU 等字段

「首屏 20 条、详情再拉剩余」——多数时候是按需加载,不一定是在救带宽。算不算带宽问题,用 响应体大小 × QPS 估一下,接近上限才算。


三、怎么确认是带宽而不是代码

四条里命中三条,就该查带宽:

  1. CPU / 内存 / DB 指标正常
  2. 服务端逻辑耗时不长,客户端却觉得慢
  3. 云监控「外网出带宽利用率」持续 > 80%
  4. 压测 QPS 到某个值后不再涨

Linux 上看流量:

iftop -i eth0    # 需安装,网卡名按环境替换
nload eth0

云控制台:阿里云 ECS → 网络监控 → 流出带宽;腾讯云 → 外网出带宽利用率。


四、Java 侧怎么改

4.1 响应体做减法

// 别这样:一次全量
@GetMapping("/users")
public List<UserVO> list() {
    return userService.findAll();
}

// 分页 + 列表专用 VO
@GetMapping("/users")
public Page<UserListVO> list(@RequestParam(defaultValue = "0") int page) {
    return userService.pageList(page, 20);
}

列表 VO 只留展示字段;详情接口再拿完整数据。

4.2 文件字节别过应用层

静态资源走 CDN / OSS,Java 返回链接即可。下面这种会把 ECS 出口带宽吃光:

@GetMapping("/download/{id}")
public void download(@PathVariable Long id, HttpServletResponse resp) throws IOException {
    byte[] data = ossClient.getObject(bucket, key);
    resp.getOutputStream().write(data);
}

4.3 开 Gzip

server:
  compression:
    enabled: true
    mime-types: application/json,application/xml,text/html,text/plain
    min-response-size: 1024

JSON 一般能压掉六成以上体积。

4.4 日志别打大对象

log.info("订单详情:{}", order);           // 别这样
log.info("订单创建成功 orderId={}", order.getId());  // 够用

高 QPS 接口避免 INFO 级别输出整对象。

4.5 大导出异步化

提交任务 → 返回 taskId → 后台生成文件上传 OSS → 客户端从 OSS 拉。别在 HTTP 连接里同步吐百万行。

架构层:CDN 扛静态、多实例分摊出口、限流防突发;带宽不够再升规格——最直接,也最贵。


五、排查怎么落地

单次响应 ~2MB(20 张原图信息 + 长描述),200Mbps 理论 QPS 只有十几个。改成分页列表 VO(~80KB)+ CDN + Gzip 后,P99 降到 180ms,带宽利用率 30% 以下。

排查顺序:业务耗时 → DB → CPU/内存 → 带宽。瓶颈不在代码上,就别在代码里死磕。


六、总结

  1. 先算带宽 ÷ 响应体 得到 QPS 上限,心里有个数。
  2. 再看监控:逻辑和 DB 都正常、客户端却慢,查流出带宽。
  3. 先减 payload:分页、精简 VO、CDN、Gzip——多数情况比升计算规格管用。

参考