加入收藏 | 设为首页 | 会员中心 | 我要投稿 航空爱好网 (https://www.ikongjun.com/)- 混合云存储、媒体智能、AI行业应用、应用程序集成、办公协同!
当前位置: 首页 > 服务器 > 系统 > 正文

Linux与Windows服务器选型的5大性能陷阱

发布时间:2026-11-09 08:04:08 所属栏目:系统 来源:DaWei
导读:  上周三下午四点十七分,客户后台突然开始报502——不是间歇性的,是整片服务挂掉,连健康检查端口都收不到响应。我切到跳板机,top一开,load平均值二十来分钟没下来过,但CPU利用率死死卡在12%。我原以为是Nginx upstream超

  上周三下午四点十七分,客户后台突然开始报502——不是间歇性的,是整片服务挂掉,连健康检查端口都收不到响应。我切到跳板机,top一开,load平均值二十来分钟没下来过,但CPU利用率死死卡在12%。我原以为是Nginx upstream超时或后端Java进程僵死,结果ps aux一看,三个java进程都在跑,堆内存用了一半,线程数正常,GC也没频繁触发。


文章配图,仅供参考

  可就是不接请求。telnet localhost 8080通,curl -I http://localhost:8080 返回200,但只要走反代(nginx监听80转发到8080),立刻timeout。查access_log,所有请求停在“-”状态;查error_log,只有一行:“upstream timed out (110: Connection timed out) while reading response header from upstream”。我们改过nginx的proxy_read_timeout,从60秒拉到300秒,没用;换过keepalive_timeout,也没用;甚至把nginx进程杀光重起,第十一次启动之后,第五个worker又开始卡住——你盯着它,它就动一下,你不盯,它下一秒就挂住。


  然后我翻出三天前上线的变更清单:就一条——把原先跑在Windows Server 2019上的那台API网关,迁到了一台新的Linux服务器上,内核5.15,CentOS Stream 9,glibc 2.34。配置文件几乎一模一样,除了把路径里的C:\\inetpub\\ 改成 /var/www/,把Windows的service脚本换成systemd unit。其余全照搬。我们测过压测,三千并发,TPS 1700,latency平均48ms——当时觉得稳了。


  直到周三。直到第五次重启nginx worker后,我在strace -p那个卡住的worker pid里,看到它卡在accept4()系统调用上,再往下翻三百行,全是重复的epoll_wait(7, [], 128, -1),空等。而第七个fd——那个监听socket——的socket选项里,SO_RCVBUF被设成了262144字节。我查了下,这值是从nginx.conf里proxy_buffer_size继承来的?不对,proxy_buffer_size根本不管这个……等等,我翻了眼nginx源码注释,才发现——哦,对,nginx在调用listen()之前,会自动根据系统的net.core.somaxconn值放大一下backlog,而CentOS Stream 9默认把somaxconn设成了4096,但我们的应用层代码在init时硬编码了listen(sockfd, 128)……也就是说,Linux这边的连接队列长度,被内核截断了两次:一次是应用自己写的128,一次是内核用4096又给压回128。而Windows那边呢?我们当初在IIS上跑的时候,没改过任何队列参数,默认是动态的,而且哪怕accept队列满,TCP SYN包也能被缓存进SYN队列里好一阵——这点我早忘了,我原以为现代OS都差不多。


  (那天我泡了杯速溶咖啡,水温不够,粉沉底了,喝第三口才搅匀)


  后来是老张——就在隔壁工位、负责DBA和OS的——凑过来扫了眼strace输出,说了一句:“你listen那句写死了128?Windows上你没这么干吧?”我愣住。他指了指我三年前在GitLab上提的一个merge request,标题写着“修复Windows平台accept队列阻塞”,commit里果然加了#ifdef _WIN32,把listen第二个参数改成SOMAXCONN……但那次没动Linux分支。我们上线单子里写了“配置一致性”,可没人提代码里藏着个# ifdef。


  所以五个性能陷阱?我数不清,也不信真有五个。就这一个——当开发写死listen()的backlog,而OS行为又因平台分裂,你不会在压测里发现,不会在日志里报错,它就蹲在那儿,在流量高峰第七次涌来时,安静地把你整个链路掐成502。它不崩溃,不报错,不上监控告警,就让worker进程挂在epoll_wait里,像睡着了一样。而运维看CPU低、内存够、网络通,第一反应是“是不是前端问题”……其实不是。是那个被编译掉了的#ifdef,躺在Git历史里,没人想起要grep。


  (我的键盘右下角粘了块胶带,是去年贴USB转接头留下的,现在发黄卷边)


  有谁碰到过这个吗

(编辑:航空爱好网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!