欢送来到「我是真的狗杂谈世界」,关注不迷路

背景

最近一个我的项目上线前QA对压测后果不是很称心(并且示意之前的我的项目压测后果也都不现实),于是我在上线后(上线前是必定来不及了)开始了一轮性能测试、排查和优化,记录一下整个过程。

思考过程

根底信息

QA同学提供的压测环境与论断:


  • 施压侧:

    • 并发度100~300;
    • 继续运行120~300秒;

  • 被压侧:

    • 单正本资源1C2G;
    • 正本数1~4;

  • 后果体现:

    • CPU:单正本100%(但有时呈现某正本100%,其余正本60~80%左右);
    • 内存:单正本15~20%(但有时呈现某正本高至50%)
    • QPS:单正本100~120;
    • 响应耗时:Avg(487~596ms);50TH(19~27ms);90TH(1867~3099ms);95TH(2409~3902ms);99TH(4460~7002ms);MAX(8589~13298ms);

外围问题

对于性能、压测等相干概念可参考「Foundation 11.性能是什么」

  • QPS体现较低;
  • CPU占用过高,很快被打满;
  • 响应耗时存在大量(90TH以上)过高;
以后这三者是有关联的,以后看来单个申请对于CPU资源需要较高,导致在小并发下CPU资源已占满;
随着并发度增高,零碎通过频繁调度来调配CPU资源,调度磨损减少(用于解决业务逻辑的比例升高);
因而CPU占用过高也会肯定水平连累响应耗时、QPS体现。

狐疑方向

  • 硬件性能:之前有发现压测环境后果较比生产环境低,且两侧环境为独立的集群,因而狐疑两侧集群节点自身硬件性能差别较大;
  • 执行过程:因为是PHP FPM模式下运行的服务,FastCGI处理过程、PHP代码解释执行过程等都可能造成CPU资源的占用、耗时;
  • IO阻塞度:业务逻辑中简单(屡次)同步阻塞申请(三方HTTP接口、MySQL、Redis)较比简略(少次)会造成申请响应须要工夫变长,升高QPS;
  • 短连资源:整个服务对三方HTTP接口、MySQL、Redis都采纳的短连,连贯仅在申请周期内复用,申请完结后开释,对于连贯的频繁创立销毁也会占用CPU资源、耗时;
  • 框架磨损:新版开发框架投入使用后没有太关注性能磨损问题,实践上这块肯定会存在磨损,只是水平和要害磨损点问题。

排查办法

(尽量)管制其余变量放弃雷同的状况下,针对要排查的环节、对象进行多组压测比照,记录并剖析得出结论。

实际与论断

定位基准

因为QA提供的论断看起来存在很多不稳定性,因而我决定在压测环境上基于该我的项目先进行一波测试,作为后续比照、剖析、钻研等排查工作的基准。

第一波测试

资源状况程序状况接口复杂度并发度QPSAVG50TH90TH95TH99THMAXCPU(峰值)
2C2GPHP-FPM7.4+OPcache新框架+健康检查2980------80
2C2GPHP-FPM7.4+OPcache新框架+健康检查2490------90

从第一波测试记录数据(因为QPS体现已产生过于不稳固景象了,其余数据就临时没有关注和记录)很容易发现,除了我管制住的变量外,肯定还存在一个我没发现的变量影响了压测体现;
而这两次测试存在的变量只有两个:

  • 测试工夫:因为压测服务做了串行管制(同一个工夫点只能最多一个压测工作执行),上述两波测试是在不同的工夫点进行的。
  • 被测正本:因为压测环境须要很多配置老本,没有别离配置两套压测环境,上述两波测试之间进行了利用正本重建(从新构建了服务)。

为了进一步排查上述两个变量,我每次屡次重建正本,每次重建正本后进行相隔一段时间的多组压测,景象如下:

  • 雷同正本(不重建正本)中的体现是稳固的(如果是500高低则始终是500高低,如果是1000高低则始终是1000高低),甚至到第二天仍旧是稳固的;
  • 不同正本(重建正本)时的体现会产生稳定(比方500变成1000,1000变500),但也不是每次重建都必然产生稳定切换。

基于上述景象,根本能够排除工夫差别,而狐疑正本调度到的节点的硬件或其余基础设施的差别导致;
我将此问题报告给服务器基础设施团队后帮助排查定位,最终发现压测环境4个节点其中1个节点的CPU基频在1.5~3.5GHz之间动静稳定(失常4个节点都应该是3.5GHz);


在他们解决问题的同时,我管他们要了一个独立节点来持续我的测试,前面所有资源将依照下述形容:

  • 新节点:代表管他们要来的独立节点,性能自身很差,2C体现还不如原节点1C好;
  • 原节点:代表除CPU异样节点之外的压测环境节点(实践上与生产环境节点性能仍有差距);
  • X号正本:代表正本重建,雷同的X代表正本未通过重建;原节点有意义(因为压测环境节点仍旧会有一些轻微差别),新节点无意义(就只有一个节点);
  • 健康检查:代表业务上一个接口间接返回,没有业务逻辑和三方申请;
  • 简略逻辑:代表业务上一个接口蕴含一个MySQL查问;
  • 简略逻辑*x:代表业务上一个接口蕴含x个雷同的MySQL查问;
  • 简单逻辑:代表该我的项目业务实在逻辑(一个接口蕴含2~8次MySQL、Redis、HTTP接口申请等);

持续测试

资源状况程序状况接口复杂度并发度QPSAVG50TH90TH95TH99THMAXCPU(峰值)
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查11625.6366682031
1C2G;原节点;1号正本PHP-FPM7.4+OPcache新框架+健康检查14961.63222221780
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+健康检查14841.67222313873
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查55268.666740471686100
1C2G;原节点;1号正本PHP-FPM7.4+OPcache新框架+健康检查56606.432272772300100
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+健康检查56246.9237378900100
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查2046241.7479393951858100
1C2G;原节点;1号正本PHP-FPM7.4+OPcache新框架+健康检查2053036.3239696972402100
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+健康检查2050938.1139697981715100
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查50371129.51022002032982023100
1C2G;原节点;1号正本PHP-FPM7.4+OPcache新框架+健康检查50472104.121001951972023056100
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+健康检查50446110.3100197199297182794

  • 新节点在并发1~5之间达到CPU100%,QPS最高体现也在这之间达到(实践上会略高于526),体现的确很拉垮。。。
  • 原节点在并发1~5之间达到CPU100%,QPS最高体现也在这之间达到(实践上会略高于660/624)。
  • CPU未打满时,随着并发度提高,QPS、CPU占用率也随之增长,响应耗时保持稳定;
  • CPU打满后,随着并发度提高,QPS先稳固后逐渐升高,响应耗时逐渐增大。

PHP8&Jit

资源状况程序状况接口复杂度并发度QPSAVG50TH90TH95TH99THMAXCPU(峰值)
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查18311.131117181915830
2C2G;新节点;0号正本PHP-FPM8.0+OPcache新框架+健康检查18411.04111718198830
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查18211.211171819167438
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查528715.67134248571682100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache新框架+健康检查529015.6612424858171100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查528815.87124248591730100
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查2027270.67941031071921740100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache新框架+健康检查2027370.5941031071932081100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查2027271.34941031071921807100
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查50239200.042003023984971998100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache新框架+健康检查50251195.911993023954892105100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查50249197.182003023964922183100
2C2G;新节点;0号正本PHP-FPM7.4+OPcache新框架+健康检查100216454.7940379790112002664100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache新框架+健康检查100225438.3140474689611932542100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查100222444.76407744.989210992443100

  • PHP8.0较比7.4在业务代码不动的状况下(基于7.4及之前语法)没有间接的性能晋升;
  • CPU耗费大头不在opcache转machine code环节(想想也是);
  • PHP8.0+Jit目前无奈带来并发和性能体现的晋升。

IO梗塞次数

资源状况程序状况接口复杂度并发度QPSAVG50TH90TH95TH99THMAXCPU(峰值)
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查11562.71666819830
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑1979.72101011132735
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑*517512.5812131416160727
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简单逻辑18211.211171819167438
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查55089.09684148165399
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑529715.68104451602046100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑*5528216.5113344353180998
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简单逻辑528815.87124248591730100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查2045142.9289394961843100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑2027570.91941011041911740100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑*52026972.79921011051881809100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简单逻辑2027271.34941031071921807100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查50386126.521031992022961989100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑50247197.51992993034042079100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑*550246200.261992983014002067100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简单逻辑50249197.182003023964922183100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+健康检查100357273.75292399473.655102089100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑100233424.724026026978972389100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简略逻辑*5100226438.53403604699852.982417100
2C2G;新节点;0号正本PHP-FPM8.0+OPcache+JIt新框架+简单逻辑100222444.76407744.989210992443100

  • 逻辑中不同水平的IO会导致单次申请的响应耗时减少,但对CPU的占用率影响较小;
  • 申请响应耗时高阻塞IO较比低阻塞IO广泛减少;
  • 并发度未将CPU打满时,高阻塞IO较比低阻塞IO的QPS体现要低;
  • 当并发度晋升将CPU打满后,高阻塞IO较比低阻塞IO的QPS体现简直统一

PDO长连贯

资源状况程序状况接口复杂度并发度QPSAVG50TH90TH95TH99THMAXCPU(峰值)
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+短连11396.5656615211240
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+长连12074.233449133745
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+短连22417.33561233107783
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+长连23564.6234622106091
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+短连527416.3756674861722100
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+长连542710.333967731293100
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+短连2026573.1993103196302177888
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+长连2039349.311297100103174295
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+短连50253195.05198300398599.79191488
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+长连50345142.96102200202300213692
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+短连100241401.153976017051203.1264499
1C2G;原节点;2号正本PHP-FPM7.4+OPcache新框架+简略逻辑+长连100325303.062994965017012205100

网络连接资源复用较比不复用在以后业务特点下能带来:

  • 晋升35~55%QPS;
  • 升高25~37%响应耗时。

框架截断

资源状况程序状况接口复杂度并发度QPSAVG50TH90TH95TH99THMAXCPU(峰值)
1C2G;原节点;3号正本PHP-FPM7.4+OPcache入口文件间接返回2065052.72112681774100
1C2G;原节点;3号正本PHP-FPM7.4+OPcache入口文件解析完申请2059562.72111691832100
1C2G;原节点;3号正本PHP-FPM7.4+OPcache引入主动加载之后2043413.61112772108100
1C2G;原节点;3号正本PHP-FPM7.4+OPcache加载我的项目配置之后2022788.161286891101100
1C2G;原节点;3号正本PHP-FPM7.4+OPcache加载底层配置之后2084923.0429494951867100
1C2G;原节点;3号正本PHP-FPM7.4+OPcache注册全副申请接口之后2063030.9729596971899100
1C2G;原节点;3号正本PHP-FPM7.4+OPcache健康检查残缺解决2051637.623969798187877

磨损次要产生环节:

  • 引入主动加载(composer autoload);
  • 加载我的项目配置;
  • 加载底层配置。

优化方向

短连改长连

将申请MySQL、Redis的连贯模式改成长连贯,将连贯周期由申请级别延长至FPM过程级别,以此缩小连贯创立销毁操作升高CPU占用、缩小响应耗时晋升性能整体体现。


但思考到:

  • MySQL、Redis连接数将简直与FPM开启的Work过程数量统一;
  • 多我的项目、多组共用MySQL、Redis;
  • 短连模式下,QPS过高反而会带来本地端口用尽的问题(具体见本文最初)。

决定临时不采纳此计划。

缓存我的项目与底层配置

将原先每次申请都读取多个ini配置文件并解析构造革新成初始化时读取并解析而后回写为php数组文件:

  • 防止config map的性能影响(原先这些ini配置都是通过config map挂载进我的项目);
  • 节俭ini配置解析老本(php文件间接借用php自身opcache、jit优化就足够)。

我将这个优化做到了新框架的后续版本中,并且压测验证:

资源状况程序状况接口复杂度并发度QPSAVG50TH90TH95TH99THMAXCPU(峰值)
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+不缓存配置14801.6222222077
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+缓存配置17051.051122177579
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+不缓存配置26192.55222352526100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+缓存配置210831.54112262275100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+不缓存配置56596.82272772409100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+缓存配置510604.36122722335100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+不缓存配置2053037.0939697982398100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+缓存配置2097020.1829394952601100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+不缓存配置50469105.58100196198231.992799100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+缓存配置5094652.229098991032901100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+不缓存配置100415239.432023944005983000100
1C2G;原节点;4号正本PHP-FPM7.4+OPcache新框架+健康检查+缓存配置100920107.891001951992892609100

缓存配置较比不缓存对没有连贯和阻塞IO的逻辑能带来:

  • 晋升46~121%QPS;
  • 升高34~54%响应耗时;
  • 并发度越高,成果越显著(在可接受的并发度范畴内)。

我也对带上不同水平业务逻辑的场景进行了测试;

简略逻辑下缓存配置较比不缓存能带来:

  • 晋升9~14%QPS;
  • 升高9~12%响应耗时;

简单逻辑下缓存配置较比不缓存能带来:

  • 晋升4~17%QPS;
  • 升高5~14%响应耗时;

换运行模式

如果后面两者都不可用或者不能满足需要的时候,能够思考更换以后这种FPM的运行模式,改用Cli+异步模型:

  • 天生能够应用MySQL、Redis、HTTP等连接池技术,又不须要当心连接数过多的问题;
  • 进一步缩小代码解释执行过程的耗费,Opcache和Jit技术能够进一步发挥作用;
  • 异步搭配yield/Fiber,或是swoole封装的异步库充分利用CPU,晋升单接口响应效率。

但这样无疑是存在较高的老本和危险的:

  • 现有的框架、库包都是基于同步阻塞封装的,异步可能带来并发争竞隐患;
  • FPM同步阻塞模型就义肯定性能带来的是开发效率和门槛的劣势,如果换成异步模型,对开发人员和业务无疑会带来更高的门槛和危险;
  • 相似swoole+异步协程其实简直都相当于换了大半个语言了。

整体论断

  • 目前1C2G在压测环境个别的逻辑都能够达到250甚至更高了,临时满足咱们的业务需要(更高的性能体现能够通过扩大副原本实现);
  • 还有很多的优化计划和空间,但思考到团队目前的状况和计划的老本与危险,临时不发展这类计划。

短连单正本QPS过高的问题

以后的零碎设置为:

  • 本地可用客户端端口范畴:32768~60999
  • time wait状态疾速回收和重用:没有权限,但依据景象察看应该是60s

当我调大CPU资源为2C压测一个简略逻辑(每个申请会创立一个MySQL连贯,申请完结就被动close连贯)时,QPS达到500高低,但最初几秒会呈现本地端口用尽的问题。