LNMP高并发性能优化使AB测试RPS超过500
首先要给大家说明以下几点:
- 1.篇幅和时间有限,本篇着重讲实战,理论部分交给超链接
- 2.本人水平有限,希望大家不吝赐教
- 3.现在是一个
CPU
过剩的时代,或者说是一个非常强悍的CPU
带着它坑逼的队友们(io
总线,内存,缓存,硬盘,Linux
,多进程模型,脚本语言,网络带宽)去超神 - 4.默认情况下使用的是
2核/4G
ECS
开始着手优化之前我就明显感觉到这个问题稍稍的超出了我的能力范围,但是没关系啊,先看看大家是怎么做的。
我要处理的问题有个非常洋气的名字c10k
,c10k
实际上瓶颈往往出在io
和内文切换,参考。epoll
很熟悉嘛,nginx
已经做好了,咱也甭操心了。协程也甭考虑了,有本事你把fpm
的代码用协程给重构了。那问题就简单多了,优化io
就成为了。
一、优化前奏
在优化之前务必开启以下日志:
# nginx 日志
nginx access.log error.log
# PHP 日志
php error.log
fpm error.log slow.log
开始优化之前用ab
压力测试发现rps
很低,这时候nginx
输出日志提示连接数过多。参考基友的文章LNMP中web高并发优化配置以及配置详解 (这货钱多、活好、风骚男同志赶紧加他)做了比较基础的优化后nginx
处理能力小幅上升。这时候rps
依旧不是很乐观:46
。敲个top
命令看了下cpu
才占用64%
!!!为啥cpu
跑不满就就到瓶颈了???这个问题很诡异啊——那是因为你不懂linux
(top命令详解)。刷新了我的三观,us
不是used
,而是user
的意思。是user
占用cpu64%
的时间片。id
是0也就是说cpu
已经跑满了。让人感觉不可思议的是si
占用了9%
左右,sy
占用了27%
左右。
这让人感觉很不爽啊,就像是辛辛苦苦干了一个月36%
的薪水都不属于自己的!
- si:软中断占用百分比
- sy:内核空间占用CPU百分比
很明显嘛,内文切换。这个要优化fpm模型咱就暂时不讨论了,如果你真想在这方面优化,继续往下看,下面讨论。
二、优化io&将mysql独立出去
很明显嘛,内文切换。这个要优化fpm模型咱就暂时不讨论了,如果你真想在这方面优化,继续往下看
实际上我没有做特殊的io优化,没达到那个量级嘛!我们公司现在的并发能达到1k足以。然后我就开了台io优化过的ecs+ssd。然后把mysql独立出去使用RDS+读写分离。然后rps就上升到468左右了,注意哦!还没加负载均衡。给我马哥烧柱香吧。
个人建议如果条件允许不要自己搭mysql读写分离,水很深,你买阿里云RDS的钱远远少于你请一个高级php的钱。下面我着重讲解一下为啥我非要用io优化+ssd。这就要看你对computer science有多深入的了解了。感谢我大学在cs上打下了不错的基础,然后去翻linux内核的书的时候让我可以轻松点进入状态。
三、扯点Linux内核
1.首先你需要了解的是虚拟内存
这是个很扯的问题呀,每个进程都有4G的内存空间去存对象、变量和数据之类的。而且是放在硬盘上。让人感觉更扯是内存不直接参与运算,直接参与运算的只有寄存器。cpu
总要把数据拉倒寄存器里把,总待有个桥之类的东西实现这个功能吧——这个东西叫io总线
2.io总线。
有限的时间我只查到了IBM PowerPC
的cpu
一共只有65536
个8bit
的io
总线。现在你终于知道nginx
的worker_rlimit_nofile
为啥要设置65535
了吧,我猜测要留一个给系统中断用。这也是为啥linux
的最大文件打开数是65535
。
千军万马过65536
个独木桥。
这也是为啥会有层出不穷的io
复用模型的出现。
其实后面兜了不少圈性能提升不明显。由于公司使用的是一个非常蛋疼的框架,微擎(简称we7
)。多次给高层建议重构无果,最终只能硬着头皮优化了。在这里顺便提醒大家一句:千万不要不要以为php
简单就动不动自己动手写个框架,因为你很难有机会像开源框架一样接受市场的考验,你更难有开源社区那么多有热情的志愿者不断贡献代码去迭代。
我简单拿we7
和tp5
对比了一下。发现tp5
在优化完nginx cgi
连接超时以后表现的很稳定ab
测试下几乎不会有Failed
。但是we7
只要超过1000
的用户并发就会不断的报以下三个错误:
2017/12/25 09:37:03 [error] 22582#0: *16081 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 10.26.68.75, server: www.medianewvisual.com, request: "GET /h5/index.php?c=insurance_drawtest&d=StarDraw&i=1 HTTP/1.0", upstream: "fastcgi://127.0.0.1:9001", host: "medianewvisual.com"
2017/12/25 09:37:03 [error] 22582#0: *16081 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 10.26.68.75, server: www.medianewvisual.com, request: "GET /h5/index.php?c=insurance_drawtest&d=StarDraw&i=1 HTTP/1.0", upstream: "fastcgi://127.0.0.1:9001", host: "medianewvisual.com"
2017/12/25 09:46:31 [error] 22581#0: *233603 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 10.26.68.75, server: www.medianewvisual.com, request: "GET /h5/index.php?c=insurance_drawtest&d=StarDraw&i=1 HTTP/1.0", upstream: "fastcgi://127.0.0.1:9001", host: "medianewvisual.com"
这个其实是考验一个框架的功力。我简单看了一下we7
源码,数据库连接全是胡扯,就一个pdo
对象做了单例(php
的单例只能做到Java
单例的20%
)。完全没有连接池的概念。再仔细看看ab
的结果
这也就难怪请求越多死的越多了。更可怕的是一个错误溢出消耗的cpu
资源是正常的完整请求的三倍。
3.高级优化思路
大致看了tp5
的源码,tp5
是有数据库连接池。但是对于没有常住内存进程的php
来说,然并卵啊。相比较而言Java
就做的比较好,参考c3p0
数据库连接池原理。假使就想用php
复用mysql
连接池呢?可以使用swoole
来实现。如果你仅仅做到了这一步,我觉得还不够。可以参考redis
的pipeline
设计一个缓冲池批量给mysql
服务器同步数据。如果再配合上swoole
的异步io
就更好了。
fpm
是使用进程模型做计算密集处理的。以前在看python
的协程、线程和进程的时候有“io密集型用协程,计算密集型用进程”的说法。线程切换能占用近1/3
的cpu
确实很可怕。如果fpm
能用协程模型实现着实能提高很高的效率。另外一条路子个人认为也是php
未来的一个趋势——jit
技术。难道只有我一个人觉得既然nginx
都已经做了多worker
、io复用
、请求排队这些操作了,fpm
岂不是很多余吗?未来一定会有人用php
实现一个和OpenRest
类似的东西。
在很大的请求量下,频繁的写入日志(nginx log
)也是一个很头疼的问题。同样的nginx
应该提供一种批量写入日志/延迟写入日志的技术。这点我没有验证,不知道nginx
或者Tengine
有没有实现类似的功能。!
转自原文:记一次LNMP优化过程
-
laravel中distinct()的使用方法与去重 2017-09-11
-
Laravel将view缓存为静态html,laravel页面静态缓存 2021-10-09
-
[ laravel爬虫实战--基础篇 ] guzzle描述与安装 2017-11-01
-
[ 配置教程 ] 在ubuntu16.04中部署LNMP环境(php7+maridb且开启maridb远程以及nginx多域名访问 )并配置laravel环境 2017-07-18
-
laravel11如何启用routes/api.php无状态路由 2025-03-06
热门文章
-
laravel11如何启用routes/api.php无状态路由 2025-03-06
-
oppo手机默认浏览器urlscheme 2025-02-13
-
mysql如何给运营人员添加只有查询权限的账号 2024-12-02
-
Mac 安装mysql并且配置密码 2024-11-20
-
阿里云不同账号(跨账号)ECS服务器同地域如何实现免费内网互通? 2024-11-12
更多相关好文