上个月接手了一个基础设施类项目,需求单上写得很简单:把视觉质检场景下的数据上报和结果查询服务从零新建出来,老板只给了一个方向——“并发要扛得住,吞吐要上得去”,于是项目代号就干脆叫了“新建并发吞吐”。真正动手前以为难点在于排队拍照推送、图片压缩、模型推理,做起来才发现,最难的部分全部集中在“新建系统时如何把并发模型和吞吐量预算一次想清楚”。
这篇文章打算记录这段时间从环境初始化到压测调优的完整过程,包括新建Linux用户、模块划分、线程池与锁的处理、Kafka削峰、并发压测方法,以及最后一批线上才暴露出来的坑。适合正在从零搭建高并发服务、或者系统压测一直卡在某个QPS上不去的同学看,不需要你有多深的框架经验,只要关心“为什么这么做”就能跟得上。
1. “新建并发吞吐”到底要解决什么问题
1.1 这个项目为什么叫这个名
业务上,我们需要在工厂车间里部署几十路工业相机,每个相机在检测到异常后会把缺陷图片和结构化结果回传到中心服务。现场不是只有一台相机在跑,而是多台同时触发、同时上传,到了换班或设备复检的时间段还会出现明显的高峰。过去的老系统基本是单机写文件加直连数据库,图片一多就开始不干活了,所以这次的核心诉求就一句话:从零新建一套能同时支撑“多路并发上报、高峰期数据入库、后续结果查询”的服务,而且吞吐量不能随着并发数上升而线性垮掉。
这类项目最怕的是把“并发”和“吞吐”当成两个模糊的口号。并发数、QPS、响应时间、吞吐量这几个名词大家都认识,但需求方和开发方脑子里理解的往往是不同模型。如果不把目标量化成具体数字,后面压测和调优就没有校验标准,排障时也会各说各话。
我们当时的做法是先拉了一次历史日志,统计出单日最高上报量、最集中的小时段、单路相机的平均触发间隔。经过一周统计,最终定出来的目标并不浮夸:系统要能支撑50路并发上报,接口峰值需要达到每分钟8000次写入,单张图片上传与结果写入的整体链路P99响应时间不超过500毫秒。这个数字后来成为所有架构和代码决策的衡量标尺。
1.2 并发数、QPS、RT、吞吐量:先把账算明白
因为是被标题“新建并发吞吐”招进来的项目,很多人误以为只要把并发数调大,吞吐量就自然上去了。但这里有个最容易混淆的关系:并发数只是“同时挂在线上的请求数量”,吞吐量是“单位时间内处理完的请求数量”,响应时间则是“单个请求从进到出花的时间”。它们之间有公式关联,但方向不完全一致。
系统里常用的一个简化换算公式是:
- 并发数 = QPS * 平均响应时间
- 吞吐量(每秒处理数) = 并发数 / 平均响应时间
所以我经常看到新同学在压测时拼命加大并发数,结果QPS不但没上去,响应时间直线飙升。原因很简单:当并发超过系统真实处理能力,请求全部挤在队列里等待,吞吐量被资源瓶颈卡住,RT被排队时间拉长,整个系统的体验反而更差。
对我们要承担的场景来说,需要的不是“极端情况下能同时挂几万个连接”,而是“每分钟到达的8000次写入能不能稳定消费完”。所以从第一天起,我就把项目真正关心的指标定义成了三条:入站QPS曲线、消息积压深度、全链路P99响应时间。所有架构选型和代码设计都围绕这三条来展开,后面陆续新建的功能模块也不会跑偏。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从新建一台机器到一个可扩展的服务:环境的几个硬约束
2.1 别用root,新建普通用户并把系统资源梳理清楚
新建项目的第一步通常是买机器、装环境,绝大多数人习惯拿root直接把环境一把梭装好。但在一个要长期承载高并发的服务上,我建议一开始就规规矩矩地新建独立运行用户。
操作上需要做的不多,但每一步都有它的作用:
bash复制useradd -m app
passwd app
mkdir -p /data/app /data/logs
chown -R app:app /data
看起来只是权限隔离,实际至少在三个地方为“并发高吞吐”保驾护航。第一,如果服务以普通用户运行,即使某个接口因为代码漏洞被外部命令注入,攻击者拿到的也只是一个受限账号,而不是整个服务器的root权限,这对暴露在公网的上报接口来说不是小事。第二,多个服务共用一个机器时,单独用户能把日志和临时文件隔离清楚,排查问题方便太多。第三,高并发服务常见的文件句柄上限是按用户维度设置的,用独立用户才能单独调优,不至于影响宿主机上的其他进程。
新用户建好之后,还要立刻看一遍系统层面的软硬限制。高并发服务通常涉及的资源无外乎文件句柄、线程数、进程数这几类,Linux默认值往往保守得可怕。以文件描述符为例,默认的1024对于单机几十路并发摄像头上传图片来说可能一会儿就耗光了。建议至少加到65535甚至更高。我一般会在 /etc/security/limits.conf 里针对运行用户配置:
code复制app soft nofile 1048576
app hard nofile 1048576
app soft nproc 65536
app hard nproc 65536
改完之后不是重启机器就算完,还要用 ulimit -n 确认当前会话是否加载新值。曾经遇到过配置写完没生效、压测一上连接数稍
