-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在 Swoole\Coroutine\Http\Server 中的 http server 使用 sendfile 在高并发时会导致 PHP 假死并且内存泄露 #5329
Comments
ulimit -n查看一下文件符数量 |
是 65536 之前排查的时候特意改了,但是还是没有用处 |
我没法复现这个问题,麻烦提供一份可复现的代码 <?php
$http = new Swoole\Http\Server('127.0.0.1', 9501);
$http->on('start', function ($server) {
echo "Swoole http server is started at http://127.0.0.1:9501\n";
});
$http->on('request', function ($request, $response) use ($http) {
$response->header('Content-Type', 'application/octet-stream');
$response->header('Content-Disposition', 'attachment; filename=recvfile.txt');
$response->sendfile('/home/output.txt');
});
$http->start(); 也可以strace -p 查看当前进程 |
因为现在是生产环境,只能快速重启解决,我尝试在 staging 复现一下吧 |
|
你分发的文件有多大 |
大概在50MB以内 |
是在正常运行的时候吗?那我直接从生产环境里面截取一部分好了 |
这是假死前的 strace 记录,看看有没有帮助
|
另外还有一点就是假死的时候PHP内存占用大约为1G,在使用ab 2000并发 sendfile20mb文件 压测确实会达到如此内存,不知道是否是内存的问题 |
可能是客户端没关闭连接,这些连接占用了内存了吧 |
你这边看看能不能提供一个可复现的代码,我这边看看 |
我尝试复现一下,主要是只有生产环境才会,我自己可能没办法复现 |
|
我测试了一下,这个应该不是内存泄漏,更有可能是因为php的内存管理机制会将小的内存块保留起来不还给操作系统。 |
好的,我晚点再压测一下 |
@Mxmilu666 怎么样,可以吗 |
依然还会,我在实际测试一下 |
Swoole\Timer::tick 设置了60秒 |
可以设置1秒的时间间隔 |
@Mxmilu666 怎么样,如果还是不行的话试试异步http server |
好的,但是我用协程http server是因为我还要上报信息,外面还有逻辑,我再尝试一下吧 |
@NathanFreeman 复现了,具体代码如下: $server = new Server(0.0.0.0, 4000, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server->set([
'ssl_cert_file' => './cert/'.$this->cert,
'ssl_key_file' => './cert/'.$this->key,
'open_http2_protocol' => true,
]);
$server->handle('/', function ($request, $response) {
$code = 200;
$response->header('Content-Type', 'application/octet-stream');
$response->header('Content-Disposition', 'attachment; filename=test');
$response->sendfile('./20');
if(!isset($request->server['query_string'])){
$url = $request->server['request_uri'];
}
else{
$url = $request->server['request_uri']."?".$request->server['query_string'];
}
echo(" Serve {$code} | {$request->server['remote_addr']} | {$request->server['server_protocol']} | {$url} | {$request->header['user-agent']};") ;
});
echo("Start Http Server on {$this->host}:{$this->port}");
$server->start(); 这段代码为一个 class 在 Coroutine 中运行 压测命令
php几乎会占满系统的所有内存,看起来不像是php的内存管理机制 服务器配置12核6g |
|
有用到jemalloc吗 |
你看看你的内存是否增长到一个固定的值就不再增长了。压测的时候传输的文件也会占用内存,调小一下文件的大小看看那会不会出现这个问题。试试用wrk压测看看 |
@NathanFreeman 如图 CPU100% 但是 php 已经停止运行了 |
|
我考虑用异步尝试一下了,话说有考虑在异步 http server 加入 handle 吗 |
你PHP占用CPU100%是不是ab压测还没结束 |
这是正式环境,我没压测,正常跑就假死了 |
还是要strace -p长时间执行看看php进程忙碌在哪一步 |
我 strace -p 一个小时试试 |
或者 |
或者pidstat -p 1 5看看是哪里的CPU用的多 |
#$server = new Server(0.0.0.0, 4000, SWOOLE_PROCESS, SWOOLE_SOCK_TCP | SWOOLE_SSL);
$server = new Server(0.0.0.0, 4000, true); 协程服务端构造函数这里有问题 |
这个我早上排了,我改了还是一样的,现在的构造函数是: $this->server = $server = new Server($this->host, $this->port, true);
$server->set([
'ssl_cert_file' => './cert/'.$this->cert,
'ssl_key_file' => './cert/'.$this->key,
'heartbeat_check_interval' => 60, // 表示每60秒遍历一次
]); |
array(
'heartbeat_idle_time' => 600, // 表示一个连接如果600秒内未向服务器发送任何数据,此连接将被强制关闭
'heartbeat_check_interval' => 60, // 表示每60秒遍历一次
); 心跳加上 |
有个协程客户端在用recv接受数据,但是这个方法是升级成websocket协议才有用。 |
这是 websocket 服务,用来上报数据的,但是明明已经升级了? |
我再看看 |
看一下协程客户端返回的错误码吧 |
你也可以按一下向下的方向键,回车看看第一个函数的父函数是谁 |
好的,等问题再次出现我再试试,麻烦了 |
你的代码是怎么使用协程客户端的 |
你现在CPU100%,可以用perf top -g -p采样看看进程在做什么 |
我是用协程客户端的 ws 造了一个 socket.io 的轮子来连接主控 |
目前还没有假死,等假死了我再看看 |
@Mxmilu666 怎么样,可以了吗 |
解决了,因为我使用了 while(true) 来获取recv() 当外部 close 时会导致还在循环 recv() 导致无限重连 |
感谢大佬耐心解答我的问题 |
Please answer these questions before submitting your issue.
What did you do? If possible, provide a simple script for reproducing the error.
我使用 Http\Server 搭建了一个简单的文件分发服务器,在大约2000连接数的时候PHP假死并且top显示php进程占用CPU100%
What did you expect to see?
在高并发环境下不会假死
What did you see instead?
在大约2000连接数的时候PHP假死并且top显示php进程占用CPU100%
What version of Swoole are you using (show your
php --ri swoole
)?php --ri swoole:
uname -a
&php -v
&gcc -v
) ?uname -a:
php -v:
gcc -v:
在假死后strace -p没有出现任何信息
我稍微长时间strace了一下php,需要可以提供假死前的记录
The text was updated successfully, but these errors were encountered: