问题描述:
在公司有做一个node中间层负责 merge多个后端接口返回给前端调用,现在有一情景,需要分7次请求某个后端接口,一次请求6个id,这7次可以并发请求,
单纯压测后端接口(6个id的情况),qps可达7000,node中间层代理后 qps降到了 220左右, 去掉了其他影响条件,只是单纯的并发请求7次接口,qps也只有280左右,
cpu占用率 高达80%,内存占用不高,应该只有socket创建产生的内存,几十M左右。
使用strace 跟踪进程,发现是
futex跟读写操作占cpu使用较高
使用pstack分析结果:
C++较弱,看样子是在创建序列化JSON对象。
问题条件: 1.打印这7次并发请求的时间,发现最后一次请求的时间 远大于前6次,应该是响应时间过长导致qps上不去, 做了以下优化:agent的maxSocket设置为3000,keepalive为true,减少tcp握手浪费的时间,使用tcpdump抓包,确实没有了tcp握手这一步,时间有一点点减少 2. 单个接口(批量6个id请求后端接口)时间为 20ms左右,但是并发七个 请求 就变成了 1500ms+了 (忽略该条件,重新验证时间差不多)
令人头秃的疑问: socket在资源足够的情况下理论上是可以无限创建的,这意味着request请求可以无限发起,而且node本身是异步的,网络io不需要阻塞等待,可以继续发起下一次req,如果下一个事件循环中res返回了,再进行处理。 即使是由于node事件监听这块的性能有损耗,不能无限发起,现在的情况 也太低了, 应该到1000qps左右才算正常,(参照后端接口7000的并发)
希望cnode 里的node大佬给咱解释一下这个问题。 以上测试 都是在单纯的并发7个请求并返回给前端的情况,中间层无额外处理逻辑。 拜谢~~
问题补充: 框架使用的是简化版的egg,基于koa的,请求包用的是request,并未对 http请求做额外的封装 补充一: 重新验证了同时发6次,7次的情况,日志里记录的时间 差不多,没有较大差异, 使用process.hrttime()记录的,应该比较准
代码补充二:
一直在测试,把代码搞得比较丑陋,大家将就看, 1,2 分别是切割出 长度为3和4的数组,每个数组的item是 6个视频id组成的字符串,我要去后端请求这6个id的数据 下面的promiseAll是请求接口的操作,promise.all 里面 就是request请求,没做任何其他的事情 然后把数据返回。 以上
补充三 论坛里应该不止我们一家 把node 用在生产环境做中间层, 大家应该也会遇到这样的问题,还请 大佬指教 或者说一下自己的使用经验, 是不是 node本身的性能就这样? 我觉得还是蛮值得探讨一下的
问题关闭结论: 真是很尴尬啊,测试同学的压测集群 跟我们测试机以及后端接口不是一个 运营商,属于跨机房调用了, 当时说的7000qps的压测数据 是 测试同学压测 后端同机房同运营商接口 的数据, 压测我们中间层接口的时候,变成夸机房了,所以 这个7000qps是不准的, 刚才在测试集群上 压 跨机房的 后端接口 qps大概3800左右,我在我的测试机上ab测试压 后端接口也是3800,在测试机上压本机接口127,0,0,1这个 qps 为430左右,乘以7算下来与后端的接口qps大致相当,所以node做接口转发是没问题的,node的性能以及http socket以及time_wait并不是本次的性能瓶颈。 错的是我。 幸好及时发现了这个问题,还是感谢社群大佬的解答,这个问题暂时不删了,希望能给犯了相同错误的同学一点警示。 拜谢~~~