我们将一款 APP 的后端,部署在一台独立的服务器上,部署完毕后,对后端程序进行了并发量测试。 测试的目的是: 在并发请求下,监控后端程序的各项性能参数。 找到后端程序的瓶颈,为接下来的接口优化,以及服务器硬件升级,提供数据支持。
服务器端配置:单核 CPU,1G 内存,1MB 带宽。 测试电脑:MacBook Pro,OS 10.10.2,i5 4 核处理器,内存 16G。 本次测试均在公司内部进行,WIFI 使用 work_5G。 由于使用 IP 和 Port 直接请求,响应速度会比走域名解析稍微快一些。 每次并发测试,均持续 60 秒,间隔 3~5 分钟测试一组。
APP 首页接口:http://IP:Port/homepages 访问频率最高,后端逻辑涉及:框架内部逻辑(HTTP,Route,Controller),Databse(Model,SQL) 和 Cache。 Hello world 接口:http://IP:Port/homepages/hello 只涉及框架内部逻辑。
抽取几组比较有代表性的数据,汇总截图如下:
并发量为 10 时,50%的请求在 500 毫秒以内处理完成,最耗时请求小于 1000 毫秒,用户还能够忍受。
后端程序,每秒处理请求数的最大值,与每次请求的处理时间,以及后端的 worker 数有关。 理论上,每个 worker 瞬时只能处理一个请求。遇到耗时的请求,将阻塞后续请求。
并发数超过 130 时,后端程序在成功处理 120 至 200个请求后,将停止响应请求。 AB 测试终止,错误信息为:apr_socket_recv: Connection reset by peer (54)
统计工具检测到,首页接口的请求处理情况,如下图:
由统计数据可知,请求平均耗时 113 毫秒。
最耗时部分为:ActiveRecord 即 Model + SQL 部分,占比 41.8%。后续将着重优化,增加读数据 Cache。
其次,是框架处理 HTTP 请求和响应部分 Rack,占比:31.7%。
从测试数据上看,在并发量为 10 时,平均响应时间为 133 毫秒。
可见框架内部处理 HTTP 请求的性能,还是非常慢的。
统计数据,如下图:
请求耗时比例如下:
QueryCache:23.9%,Rails 框架特性,实则为了加速请求而设计
NewRelic: 12.5%,性能监控逻辑,后期移除
Routing:10.18%,HTTP 路由匹配和分发,后续将研究优化
Rack::Logger: 8.8%,日志部分
HTTP:9.4% Ruby:34.4% Database:46.8% Cache:9.4%Ruby + Database,占比超过 80%,因此,是将要着重优化的环节。
在密集的请求测试下,服务器端的硬件数据统计如下:
CPU 监控数据:CPU 使用率在 25%,负载接近单核的饱和运行。 带宽 监控数据:入流量和出流量稳定在 1000 Kb/s,峰值均超过 1MB/s 内存 监控数据:平稳状态下使用率:62%,峰值:86%【备注】阿里云的监控数据,与 zabbix 的统计,稍微有些出入。感觉阿里云界面好看,zabbix 的数据更靠谱!
1. Ruby 非常耗内存:4 个 instances(1 Master + 4 Workers),占用 640 MB 的内存。 2. Rails + Grape 的 Web 架构,框架内部处理 HTTP 请求比较慢。 3. 访问量大的情况下,内存和带宽在 Ruby 的环境下,最容易成为瓶颈
1. 升级内存至 2G; 2. 参照 NewRelic 的监控数据,优化最耗时接口(大于 500ms 的接口); 3. 优化缓存处理机制,增加接口读数据的缓存。
1. 升级 Ruby 的版本,提升 GC 的处理性能; 2. 寻找替换 Unicorn 的 Web Server,要支持:低内存消耗、高并行处理; 3. 调整 Rails/Grape 内部处理 HTTP 机制,提升处理速度; 4. 升级服务器硬件配置,增加负载均衡。
2015-02-09