网易首页 > 网易号 > 正文 申请入驻

隔壁工位的同事被裁了,他的KPI全划到了我名下

0
分享至

看到一个程序员吐槽:隔壁工位同事刚拿N+1离开,第二天 leader 就把对方 Q3 的目标全部划给了他,团队人数少了,总目标不变,他个人的目标直接变成原来的1.8倍。


这种“资源减少、吞吐目标不变”的场景,我在线上系统里也遇到过。业务不会因为机器少了就自动少发请求。问题是,一个原本按照固定容量设计的 Java 服务,如果实例缩容30%,流量不变,最先出问题的经常不是 CPU,而是线程池、连接池和下游调用一起进入排队状态。

之前有个订单聚合服务,接口需要并行查询商品、营销和库存。最初机器数量比较充足,为了降低接口 RT,代码直接使用线程池并发执行:

CompletableFuture priceFuture =
CompletableFuture.supplyAsync(
-> priceClient.query(skuId), executor);

CompletableFuture promoFuture =
CompletableFuture.supplyAsync(
-> promotionClient.query(userId, skuId), executor);

CompletableFuture stockFuture =
CompletableFuture.supplyAsync(
-> stockClient.query(skuId), executor);

CompletableFuture.allOf(
priceFuture, promoFuture, stockFuture
).join;

return assemble(
priceFuture.join,
promoFuture.join,
stockFuture.join
);

当时这么写没什么问题。单机流量不高,三个 RPC 平均耗时都在50ms以内,线程池配置也比较宽松:

new ThreadPoolExecutor(
32,
64,
60,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(1000),
new ThreadPoolExecutor.AbortPolicy
);

后来因为资源调整,实例从20台缩到12台,入口总流量基本没变化。第二天接口 P99 从300ms涨到2秒以上,偶尔还能看到 RejectedExecutionException 。

我第一反应是下游接口变慢了,因为聚合接口自己基本没有重逻辑。查了一轮链路,三个下游的耗时却都正常:

priceClient avg=42ms p99=81ms
promotionClient avg=55ms p99=103ms
stockClient avg=38ms p99=76ms


aggregateApi avg=311ms p99=2187ms

这就不对了。下游只跑几十毫秒,聚合层为什么能卡两秒?

继续看线程池指标,问题才暴露出来:

poolSize=64
activeCount=64
queueSize=873
completedTaskCount=18492031


poolSize=64
activeCount=64
queueSize=996
completedTaskCount=18492802

线程已经全部占满,队列也快满了。请求进来以后,三个 RPC 任务并没有马上执行,而是先进入 LinkedBlockingQueue 排队。

这里其实很容易误判。链路平台记录的 RPC 耗时通常从真正发起调用开始计算,任务在线程池里等待的500ms并不会算进 priceClient 的42ms,所以看起来下游完全正常。

可以给任务增加一个最简单的排队时间监控:

long submitTime = System.nanoTime;

executor.execute( -> {
long queueCost =
TimeUnit.NANOSECONDS.toMillis(
System.nanoTime - submitTime);

if (queueCost > 100) {
log.warn("executor queue delay={}ms", queueCost);
}

priceClient.query(skuId);
});

加完以后日志很快刷出来:

executor queue delay=327ms
executor queue delay=514ms
executor queue delay=891ms
executor queue delay=1243ms

问题到这里才算定位清楚:缩容之后单机入口 QPS 上升,每个请求又拆成三个异步任务,线程池实际承受的是入口流量的数倍。线程数没有同步调整,任务开始排队,排队又抬高接口 RT;RT 上升以后,在途请求继续增加,最后把队列也顶满。

当时有人提议把队列扩大。这是线上很常见的处理方式,因为 RejectedExecutionException 会立刻减少,但它只是把拒绝变成等待。

假设线程池稳定处理能力只有800 task/s,而高峰持续进入1000 task/s,每秒净积压200个任务。5000长度的队列只是允许它多积压25秒。

对HTTP接口来说,这些任务25秒以后即使执行也没意义,因为上游可能早就超时了。

所以我们没有扩大队列,而是先把线程池改成更明确的过载保护:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
48,
48,
0L,
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<>(200),
new ThreadFactoryBuilder
.setNameFormat("aggregate-rpc-%d")
.build,
new ThreadPoolExecutor.AbortPolicy
);

核心不是48这个数字,而是取消“超大缓冲区”的思路。线程池达到处理极限以后尽快暴露过载,不让请求在队列里无意义等待。

调用侧同时增加超时降级。营销数据允许缺失,就不能因为它拖死整个订单接口:

CompletableFuture promoFuture =
CompletableFuture.supplyAsync(
-> promotionClient.query(userId, skuId),
executor
).completeOnTimeout(
Promotion.empty, 120, TimeUnit.MILLISECONDS
).exceptionally(ex -> {
log.warn("promotion degraded, sku={}", skuId, ex);
return Promotion.empty;
});

库存属于核心数据,不能直接吞异常;营销信息则允许降级。三个并行任务不能使用完全相同的失败策略,否则所谓“异步并行”只是把三个下游的故障域一起带进来了。

只改线程池仍然不够,因为实例继续减少时,同样的问题还会回来。我们后来按照单实例能够稳定处理的并发量,在入口增加了并发限制:

privatefinal Semaphore permits = new Semaphore(180);

public OrderView query(OrderRequest request){
if (!permits.tryAcquire) {
thrownew ServiceBusyException(
"aggregate service overloaded");
}

try {
return doQuery(request);
} finally {
permits.release;
}
}

180不是拍脑袋配置,而是压测出来的。我们逐级增加并发,记录接口吞吐和P99:

Concurrency QPS P99
100 612 184ms
150 817 236ms
180 901 291ms
220 927 684ms
260 931 1437ms

并发从180增加到260,吞吐只增加30 QPS,P99却从291ms恶化到1.4秒。继续放请求进来已经不能明显提高处理量,只会制造更多排队,因此限流点最终放在性能曲线开始明显拐弯的位置附近,并预留了一部分安全余量。

回到开头那个案例,人少了,目标可以在表格里直接乘1.8;但系统资源少了,吞吐量不会跟着KPI重新计算。Java服务遇到这种情况,先把线程池队列、单机QPS、P99和下游超时翻出来,往往比单纯“加线程”更有用。

特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相关推荐
热点推荐
俄方反对日本入常,特朗普也罕见提“中美盟友”关系,高市很慌张

俄方反对日本入常,特朗普也罕见提“中美盟友”关系,高市很慌张

揽星戈
2026-10-03 02:19:14
邓亚萍直接开炮:有伤?不舒服?输球没有原因!这话你站谁!

邓亚萍直接开炮:有伤?不舒服?输球没有原因!这话你站谁!

宝哥精彩赛事
2026-10-02 17:09:59
霍启刚,高调发文!10月1日早上9点整

霍启刚,高调发文!10月1日早上9点整

东方不败然多多
2026-10-02 10:33:51
新首相决定对中国赔钱那一刻,全世界都看懂了:不能对华继续天真

新首相决定对中国赔钱那一刻,全世界都看懂了:不能对华继续天真

比利
2026-08-06 11:11:07
太憋屈!5块金牌,5张非洲脸:谁在羞辱亚洲体育?

太憋屈!5块金牌,5张非洲脸:谁在羞辱亚洲体育?

荆楚寰宇文枢
2026-09-30 22:26:52
遥遥领先!世界顶尖技术全球只有中国掌握,美国三顾茅庐却不得

遥遥领先!世界顶尖技术全球只有中国掌握,美国三顾茅庐却不得

心灵得以滋养
2026-10-02 04:41:34
亚运拿下7枚金牌、被复旦录取的“奇迹之子”张展硕,撕碎中产父母体育升学的幻觉…

亚运拿下7枚金牌、被复旦录取的“奇迹之子”张展硕,撕碎中产父母体育升学的幻觉…

阅读第一
2026-10-02 08:37:24
买台RTX 5090整机,先签保证不出境的文件

买台RTX 5090整机,先签保证不出境的文件

像素与芯片
2026-10-02 22:08:27
“隐身”两月不再隐忍,郭德纲发文隐喻境遇,评论区直接沸腾

“隐身”两月不再隐忍,郭德纲发文隐喻境遇,评论区直接沸腾

小撇说事
2026-10-01 04:46:42
金与正:韩方企图把朝鲜半岛局势再次拖入危险境地

金与正:韩方企图把朝鲜半岛局势再次拖入危险境地

新华社
2026-10-02 18:13:04
什么人买特斯拉?中国城市特斯拉销量排位:深圳第六,上海第二

什么人买特斯拉?中国城市特斯拉销量排位:深圳第六,上海第二

青史卷中人
2026-10-02 03:40:16
“入境即享” 外国游客沉浸式解锁中医药魅力

“入境即享” 外国游客沉浸式解锁中医药魅力

北青网-北京青年报
2026-10-02 18:10:03
官媒发文,林诗栋蒯曼真正关系藏不住了

官媒发文,林诗栋蒯曼真正关系藏不住了

乒乓乐园
2026-10-03 00:05:53
法国1-1意大利,奥利塞世界波破门,巴斯托尼救主,于帕染红

法国1-1意大利,奥利塞世界波破门,巴斯托尼救主,于帕染红

懂球帝
2026-10-03 04:46:34
他是国家一级演员,拍戏赚的钱都上交老婆,帅气儿子是他唯一心病

他是国家一级演员,拍戏赚的钱都上交老婆,帅气儿子是他唯一心病

娱圈办事处
2026-10-01 16:01:25
48岁李小冉俯拍写真火了!敢穿敢露,这状态谁看了不迷糊?

48岁李小冉俯拍写真火了!敢穿敢露,这状态谁看了不迷糊?

手工制作阿歼
2026-10-03 00:44:10
C罗前队友:C罗的行为不够尊重队友;身边人没有劝他走对的路

C罗前队友:C罗的行为不够尊重队友;身边人没有劝他走对的路

懂球帝
2026-10-02 13:46:15
我有种强烈预感,要有大事发生!9月29日央视新闻披露:

我有种强烈预感,要有大事发生!9月29日央视新闻披露:

叶老四
2026-09-30 08:41:19
风向彻底变了!大陆对台态度逆转:如今根本不怕美军介入

风向彻底变了!大陆对台态度逆转:如今根本不怕美军介入

叶老四
2026-07-15 19:26:00
东北彻底翻身?中俄砸重金开发这块宝地,你的家乡要迎来泼天富贵

东北彻底翻身?中俄砸重金开发这块宝地,你的家乡要迎来泼天富贵

史之铭
2026-10-03 02:47:46
2026-10-03 05:04:49
一口娱乐
一口娱乐
用心做娱乐,打造好铺子。
1336文章数 12389关注度
往期回顾 全部

头条要闻

李在明:若乌克兰拒不道歉 将采取进一步措施

头条要闻

李在明:若乌克兰拒不道歉 将采取进一步措施

体育要闻

30天30队·快船:被莱纳德挂在半空的未来?

娱乐要闻

潘玮柏老婆被猜怀二胎 中秋vlog露馅

财经要闻

珠宝黑马爆雷,老板全家跑路泰国!

科技要闻

“分手”15天后,华为与赛力斯签约新五年

汽车要闻

方程豹9月热销破4万 首款皮卡鲨鱼将于四季度上市

态度原创

房产
时尚
亲子
家居
本地

房产要闻

三亚楼市炸了!首个空中泳池平层+CBD独一份洋房同时爆出!

伊姐十一热推:电视剧《无可替代》;电视剧《雷霆令》......

亲子要闻

网传多地幼儿园男女比例失衡,男孩比女孩多3倍,网友说:以后性资源会出现巨大缺口!

家居要闻

2026建博会(广州) 公装联探展交流活动

本地新闻

中秋逛白塔寺,体验国医妙荟雅集

无障碍浏览 进入关怀版