swoole / swoole-src

🚀 Coroutine-based concurrency library for PHP
https://www.swoole.com
Apache License 2.0
18.42k stars 3.16k forks source link

swoole_http_request->rawContent() caused out of memory? #2056

Closed zacksleo closed 5 years ago

zacksleo commented 5 years ago

1. What did you do? If possible, provide a simple script for reproducing the error.

重写 Yii2 中的 request 组件中的 getRawBody 方法


public function getRawBody()
{
    return $this->swooleRequest->rawContent();
}

$requestComponent = [
    'class' => Request::className(),
    'swooleRequest' => $request,
];
$config['components']['request'] = isset($config['components']['request']) ? array_merge($config['components']['request'], $requestComponent) : $requestComponent;

$application = new \yii\web\Application($config);
var_dump($application->request->getBodyParams());

2. What did you expect to see?

request

POST /admin HTTP/1.1
Host: localhost
Content-Type: application/json
cache-control: no-cache
Postman-Token: c5cb07bd-49c5-43e4-bb52-bc9d41cc0ab1
{
    "hello":"world"
}------WebKitFormBoundary7MA4YWxkTrZu0gW--

output

string(20) "{ "hello":"world" }"

3. What did you see instead?

调用时出现 Allowed memory size of 1073741824 bytes exhausted (tried to allocate 1634692240 bytes

4. What version of Swoole are you using (show your php --ri swoole)?

4.2.3

swoole

swoole support => enabled
Version => 4.2.3
Author => Swoole Group[email: team@swoole.com]
coroutine => enabled
epoll => enabled
eventfd => enabled
signalfd => enabled
spinlock => enabled
rwlock => enabled
openssl => OpenSSL 1.0.2p  14 Aug 2018
zlib => enabled
mutex_timedlock => enabled
pthread_barrier => enabled

Directive => Local Value => Master Value
swoole.enable_coroutine => On => On
swoole.aio_thread_num => 2 => 2
swoole.display_errors => On => On
swoole.use_namespace => On => On
swoole.use_shortname => On => On
swoole.fast_serialize => Off => Off
swoole.unixsock_buffer_size => 8388608 => 8388608

5. What is your machine environment used (including version of kernel & php & gcc) ?

docker, php7.1, alpine,  
Linux version 4.9.93-linuxkit-aufs, 
gcc version 6.4.0 (Alpine 6.4.0)
twose commented 5 years ago

Swoole是常驻进程的, 传统框架或组件很容易出现全局变量或静态变量不断积累导致PHP内存达到上限, 应该和rawContent无关, 检查你是否清理了相关全局变量内存. 将传统框架和组件直接移植到swoole是危险重重的, 不建议这么做.

还有好像这个包长得不太对, 不符合HTTP规范

zacksleo commented 5 years ago

swoole 新的框架感觉都不成熟,另外这是实验性项目,从原有的框架上尝试进行迁移测试。哪里不符合规范?

https://github.com/zacksleo/yii2-swoole/blob/refactor-swoole/src/console/SwooleController.php#L144

zacksleo commented 5 years ago

类似问题如何进行排除,查找原因呢

zacksleo commented 5 years ago

完善了下代码,如下形式可以了

    private $_rawBody;

    /**
     * @inheritdoc
     */
    public function getRawBody()
    {
        if ($this->_rawBody === null) {
            $this->_rawBody = $this->swooleRequest->rawContent();
        }
        return $this->_rawBody;
    }

https://github.com/zacksleo/yii2-swoole/commit/f526e35e81814a9958b7e525aef0dc379676b8a5