当前位置: 首页 > news >正文

Harness 中的动态批处理:合并多个轻量请求

Harness 中的动态批处理:合并多个轻量请求,让云原生控制平面性能提升3倍


引言

痛点引入

如果你负责过云原生DevOps平台、微服务控制平面或者大模型推理服务的性能优化,一定遇到过这样的窘境:

平台QPS刚刚突破10万,API网关的CPU就已经打满了,排查下来发现70%的请求都是小于1KB的轻量请求:比如agent上报状态、拉取任务、同步配置、健康检查……每个请求的业务逻辑处理耗时不到10ms,但HTTP握手、TLS协商、鉴权、链路追踪、上下文切换这些开销占了总耗时的80%。你加了机器、调了连接池、开了HTTP/2多路复用,性能只提升了20%,成本却翻了一倍。

这正是全球领先的DevOps厂商Harness在2022年遇到的真实场景:当时Harness的控制平面需要对接全球超过10万个部署代理(Delegate)、CI Runner和终端CLI,每个客户端每2秒就会发起3~5个轻量请求,高峰期QPS超过15万,P99延迟飙升到2s,大量客户端超时重发形成雪崩效应,多次出现小规模服务不可用。

解决方案概述

为了解决这个问题,Harness的架构团队引入了自适应动态批处理技术:在客户端侧自动聚合多个轻量请求为一个批请求,服务端侧统一处理后聚合响应返回,客户端再把响应分发给每个原始请求。和传统的静态批处理不同,这套方案会根据实时请求率、队列长度、延迟阈值自动调整批大小和等待窗口,既保证了吞吐量的提升,又不会出现延迟过高的问题。

上线后Harness公布的生产数据显示:

  • 控制平面API网关CPU使用率降低了47%
  • 整体吞吐量提升了3.2倍
  • P99延迟从2s降到了460ms,降低了77%
  • 数据库QPS降低了62%(得益于批处理内置的请求去重和缓存)

最终效果展示

我们可以先看一组对比测试数据:

指标单请求模式静态批处理(固定100ms窗口)动态批处理(Harness实现)
QPS支持上限1.2万2.8万3.8万
P99延迟(1万QPS)520ms310ms180ms
网关CPU使用率(1万QPS)72%38%27%
低峰期P99延迟(100QPS)120ms220ms140ms

可以看到动态批处理在高低峰场景下都表现优异,完美解决了轻量请求的性能痛点。


准备工作

环境/工具

如果要跟着本文动手实现或者测试动态批处理,你需要准备:

  • Python 3.9+ 版本
  • gRPC 相关依赖(pip install grpcio grpcio-tools
  • Harness免费账号(可选,用于体验生产环境的批处理效果:Harness注册地址)

前置知识

阅读本文你只需要具备以下基础知识,零基础也能看懂核心思路:

  • 基本的微服务架构概念
  • HTTP/gRPC通信的基本流程
  • 异步编程的基础概念

如果你想深入学习相关知识,可以参考:

  • gRPC官方文档
  • 云原生微服务设计模式

核心概念:什么是动态批处理?

批处理的本质

批处理的核心思想是合并多个独立请求的公共开销:不管是网络通信的握手、头部开销,还是服务端的鉴权、上下文初始化、数据库连接开销,都只需要执行一次,就能服务N个请求,当N越大时,平均每个请求的开销就越低。

静态批处理 vs 动态批处理

很多人对批处理的印象还停留在“固定窗口攒批”的静态批处理,比如每100ms或者每攒够100个请求就发送一次,这种方案在请求率稳定的场景下好用,但在云原生场景下请求率波动极大(比如上班时间QPS是下班时间的10倍),就会出现严重的问题:低峰期每个请求都要等满100ms,延迟翻倍;高峰期批大小超过上限,队列溢出,请求失败。

动态批处理就是为了解决这个问题诞生的:它会根据实时的运行指标自动调整批处理的参数,核心是在延迟约束下最大化吞吐量。我们可以通过下表直观对比两者的差异:

对比维度静态批处理动态批处理
触发条件固定时间窗口/固定批大小自适应根据请求率、队列长度、延迟阈值调整
批大小波动波动大,低峰期批大小远小于最大值波动小,始终保持在最优批大小区间
延迟P99波动大,低峰期延迟固定等于窗口大小,高峰期延迟飙升波动小,始终控制在预设的最大延迟阈值内
资源利用率低,低峰期浪费等待时间,高峰期队列溢出高,低峰期减小窗口降低延迟,高峰期增大窗口提升吞吐量
实现复杂度低,只要定时器+队列即可中高,需要监控指标、自适应算法、参数调优
适用场景请求率稳定、延迟不敏感的场景请求率波动大、对延迟和吞吐量都有要求的云原生场景

动态批处理和其他优化技术的对比

很多人会问:我已经用了连接池、HTTP/2多路复用,还要用动态批处理吗?答案是肯定的,它们的优化维度完全不同,可以叠加使用,我们通过下表对比:

技术请求合并粒度网络开销降低比例对延迟的影响实现复杂度适用场景
连接池连接复用,请求单独发送20%~30%(减少握手开销)降低10%~20%所有HTTP/gRPC通信场景
HTTP/2多路复用同一个连接并发多个请求,单独处理30%~40%(减少连接和头部开销)降低20%~30%低(只要开启HTTP/2即可)微服务之间通信、前端和后端通信
静态批处理多个请求合并为一个请求60%~80%低峰期增加延迟,高峰期降低延迟请求率稳定的离线场景
动态批处理多个请求合并为一个请求,自适应窗口70%~90%整体降低20%~40%中高云原生控制平面、DevOps平台、大模型推理等高QPS轻量请求场景

问题背景:Harness为什么需要动态批处理?

Harness的架构特点

Harness是一个一站式DevOps平台,提供CI/CD、混沌工程、Feature Flag、云成本管理等全链路能力,它的架构采用典型的控制平面+数据平面分离的设计:

  • 控制平面:部署在Harness的公有云或者客户的私有云里,负责存储配置、调度任务、统计数据、提供UI接口
  • 数据平面:部署在客户的本地环境、K8s集群里的Delegate(代理)、CI Runner、CLI等客户端,负责执行具体的部署、构建、测试任务

所有的数据平面客户端都需要和控制平面频繁通信:每2秒拉取一次待执行的任务、上报任务状态、同步最新的配置、上报健康状态,这些请求的共同特点是:payload极小(大多<500B)、QPS极高、延迟要求中等(P99<1s即可)

问题描述

2022年Harness的企业客户数突破2000家,活跃的Delegate数量超过10万个,高峰期QPS突破15万,出现了严重的性能问题:

  1. API网关CPU打满:60%的CPU消耗在处理TLS握手、HTTP头部解析、鉴权、链路追踪这些公共逻辑,真正的业务逻辑CPU占比不到30%
  2. 延迟飙升:P99延迟从正常的200ms涨到2s,大量客户端超时重发,形成雪崩效应,高峰期每秒有超过1万的超时请求
  3. 数据库压力大:大量相同的配置拉取请求反复查询数据库,数据库CPU使用率达到85%,经常出现慢查询
  4. 成本过高:为了支撑高峰期的流量,API网关的节点数从20个扩容到60个,每月云成本增加了3万美元

Harness的架构团队尝试了很多常规优化手段:开启HTTP/2多路复用、调大连接池、增加缓存、升级服务器配置,但最多只提升了25%的性能,远远达不到要求,最终他们决定自研自适应动态批处理方案。


系统设计:Harness动态批处理的架构

整体架构

Harness的动态批处理采用端侧+服务端协同的三层架构,我们用ER图展示核心实体的关系:

被聚合到

包含

调度生成

调整参数

对应

包含

CLIENT_REQUEST

BATCH

SUB_REQUEST

BATCH_SCHEDULER

ADAPTIVE_CONTROLLER

SUB_RESPONSE

BATCH_RESPONSE

整体架构分为三层:

  1. 客户端SDK层:嵌入在Delegate、CLI、CI Runner等所有客户端中,负责收集请求、自动攒批、发送批请求、分发响应给业务逻辑
  2. API网关层:负责接收批请求,统一做一次鉴权、日志、链路追踪,然后路由到对应的后端服务
  3. 服务处理层:负责解析批请求中的子请求,并行处理,聚合响应后返回,内置请求去重和缓存能力,降低后端和数据库的压力

核心交互流程

我们用流程图展示整个动态批处理的交互过程:

http://www.jsqmd.com/news/679489/

相关文章:

  • MyBatisPlus条件构造器避坑指南:为什么你的eq查询有时会漏数据?
  • 保姆级教程:用Python的data_downloader包搞定Sentinel-1精密轨道数据下载(含NASA账号配置)
  • 告别‘找不到磁盘’:用ESXi-Customizer-PS为任意品牌服务器定制带驱动的ESXi 6.7安装镜像
  • Tsukimi播放器技术深度解析:Rust与GTK4构建的现代化媒体中心架构
  • 收藏!2026年85%企业必做AI大模型应用,程序员/小白入门必看
  • VisionMaster脚本模块实战:用C#实现条码识别结果自动写入日志文件
  • 从‘仅追加’到‘伪更新’:深入拆解Elasticsearch Data Streams的底层机制与灵活操作
  • STM32 HAL库实战:PWM输出在写Flash时如何避免舵机抖动?一个真实案例的两种解法
  • 别扔!手把手教你用U盘和Telnet救活WD MyCloud Gen2变砖(保姆级图文教程)
  • 从一条CAN报文说起:深入理解J1939多帧传输(BAM/TP.DT)的底层逻辑与抓包分析
  • 全面掌控英雄联盟游戏体验:基于LCU API的智能自动化工具集深度解析
  • 收藏|2026最新版大语言模型(LLM)系统化学习路线,小白程序员都适用
  • DataGrip连接MySQL报错‘无效时区’?5分钟搞定配置并解锁它的SQL智能补全
  • CN3392 PFM 升压型双节锂电池充电控制集成电路
  • 强化学习核心算法与工程实践全解析
  • 2026年泥浆压滤机租赁排行:河道泥浆固化机/河道清淤压滤机/泥浆脱水机/湖泊清淤泥浆固化机/电厂脱硫专用压滤机/选择指南 - 优质品牌商家
  • Cadence IC617实战:手把手教你用Virtuoso仿真共源级放大器(含电阻负载分析)
  • 别再让IT团队管车了!聊聊车企搭建VSOC(车辆安全运营中心)必须独立的5个坑
  • 【电池-超级电容器混合存储系统】单机光伏电池-超级电容混合储能系统的能量管理系统附Simulink仿真
  • AI Agent Harness Engineering 辅助创意设计:从 Midjourney 到自主设计
  • 计算机毕业设计:Python农产品电商数据可视化分析大屏 Flask框架 数据分析 可视化 机器学习 数据挖掘 大数据 大模型(建议收藏)✅
  • VSCode集成ChatGPT提升开发效率全指南
  • 保姆级教程:在Ubuntu 20.04上搞定arm-linux-gnueabi交叉编译环境(含libmpfr.so.4报错解决方案)
  • CN3862 具有太阳能最大功率点跟踪功能的降压型 4A 两节锂电池充电管理集成电路
  • 别再只测距了!用HC-SR04+STM32做个智能防撞小车(附完整代码)
  • 别再死记硬背了!一张图帮你搞懂SRv6里那些‘End.X’、‘End.DT4’指令到底在干啥
  • 【电磁】两个不同介电常数的区域2D FDTD研究附Matlab代码
  • Buildroot启动报错‘/dev/console找不到’?手把手教你排查mdev与设备节点问题
  • 从AUTOSAR标准看VCU/MCU/BMS开发:为什么说软件定义汽车时代,架构先行?
  • 别再只盯着RSSI测距了!手把手教你用Python+蓝牙信标搭建一个简易的室内指纹定位系统