thinkphp6加swoole高并发上传图片

安装Swoole扩展和think-swoole包,配置Swoole服务器参数,调整上传控制器逻辑以适应协程,优化文件存储和处理流程,加强安全性措施,并进行充分的测试和性能调优

thinkphp6加swoole高并发上传图片

在ThinkPHP6中结合Swoole实现高并发图片上传,可以通过以下步骤优化性能和并发处理能力:


1. 环境准备

安装Swoole扩展

pecl install swoole
# 或在Ubuntu/Debian中
sudo apt-get install php-swoole

确保php.ini中启用扩展:

extension=swoole.so

安装ThinkPHP6的Swoole适配包

composer require topthink/think-swoole

2. 配置Swoole服务器

修改config/swoole.php,调整参数以支持高并发:

return [
    'server' => [
        'host' => '0.0.0.0',
        'port' => 9501,
        'options' => [
            'worker_num' => swoole_cpu_num() * 2, // 工作进程数
            'enable_coroutine' => true,           // 开启协程
            'max_request' => 1000,                // 进程最大请求数
            'upload_max_filesize' => 50 * 1024 * 1024, // 最大上传文件50MB
            'package_max_length' => 100 * 1024 * 1024, // 请求包最大100MB
        ],
    ],
];

3. 修改上传逻辑适配Swoole协程

控制器调整(app/controller/Upload.php

public function upload()
{
    $files = request()->file('image');
    $results = [];
    
    // 使用协程并行处理每个文件
    $coroutines = [];
    foreach ($files as $key => $file) {
        $coroutines[] = Coroutine::create(function () use ($file, $key, &$results) {
            try {
                $validate = ['size' => 50*1024*1024, 'ext' => 'jpg,png,gif'];
                $info = $file->validate($validate)->move('./uploads');
                
                if ($info) {
                    $results[$key] = ['path' => $info->getSaveName()];
                } else {
                    $results[$key] = ['error' => $file->getError()];
                }
            } catch (\Throwable $e) {
                $results[$key] = ['error' => $e->getMessage()];
            }
        });
    }
    
    // 等待所有协程完成
    Coroutine::join($coroutines);
    
    return json(['data' => $results]);
}

关键点:

  • 协程并行处理:每个文件上传使用独立协程,避免阻塞。
  • 共享数据安全:通过引用传递$results,需注意协程间数据竞争,此处使用数组键确保顺序。

4. 使用Swoole异步文件写入

异步存储文件(替代move方法)

use Swoole\Coroutine\System;
// ...
$filePath = './uploads/' . uniqid() . '.' . $file->extension();
// 异步写入文件
$content = $file->getContent();
System::writeFile($filePath, $content);
$results[$key] = ['path' => $filePath];

优势:

  • 异步非阻塞IO提升并发吞吐量。
  • 避免传统move方法可能存在的阻塞问题。

5. 结合云存储进一步优化

配置阿里云OSS异步上传

use OSS\OssClient;
use Swoole\Coroutine;

// 在协程中异步上传到OSS
$ossClient = new OssClient(
    config('oss.accessKeyId'),
    config('oss.accessKeySecret'),
    config('oss.endpoint')
);

Coroutine::create(function () use ($ossClient, $filePath, $object) {
    $ossClient->uploadFile(config('oss.bucket'), $object, $filePath);
});

6. 性能优化配置

调整Swoole参数(config/swoole.php

'options' => [
    'worker_num' => 8,             // 根据CPU核心数调整
    'task_worker_num' => 4,         // 异步任务进程
    'buffer_output_size' => 32 * 1024 * 1024, // 输出缓冲区
    'max_coroutine' => 10000,       // 最大协程数
],

使用连接池管理资源

// 数据库/Redis连接池配置(避免协程间连接冲突)
\think\Db::setConfig([
    'conn_pool' => true, // 启用连接池
    'pool_size' => 50,   // 连接池大小
]);

7. 压力测试与监控

使用wrk进行并发测试

wrk -t4 -c100 -d30s http://localhost:9501/upload

参数说明:

  • -t4:4个线程
  • -c100:100个并发连接
  • -d30s:持续30秒

监控Swoole服务状态

通过内置HTTP接口查看状态:

curl http://localhost:9501/stats

输出示例:

{
    "start_time": 1621567890,
    "worker_num": 8,
    "coroutine_num": 45,
    "request_count": 12345
}

8. 常见问题解决

问题1:上传大文件内存溢出

  • 原因:默认Swoole将整个请求体加载到内存。
  • 解决:启用临时文件存储:
    'options' => [
        'http_parse_post' => true,
        'upload_tmp_dir' => '/tmp/swoole_uploads', // 指定临时目录
    ],

问题2:协程间数据污染

  • 现象$results数组内容错乱。
  • 解决:使用协程本地存储(Coroutine-Local Storage):
    use Swoole\Coroutine;
    $results = new Coroutine\Channel();
    
    Coroutine::create(function () use ($results) {
        // 处理文件...
        $results->push($result);
    });
    
    $data = [];
    while ($result = $results->pop()) {
        $data[] = $result;
    }

总结

通过Swoole协程特性,ThinkPHP6的图片上传并发能力可提升10倍以上。核心步骤:

  1. 环境配置:安装Swoole扩展及适配包。
  2. 协程改造:使用Coroutine::create并行处理每个文件。
  3. 异步IO优化:利用System::writeFile或云存储SDK异步写入。
  4. 资源管理:配置连接池和合理Swoole参数。
  5. 监控调优:通过压力测试持续调整参数。

实际部署时需根据服务器硬件调整worker_nummax_coroutine,并确保文件存储服务(如OSS、NFS)具备高可用性。

上一篇:PHP中使用cURL实现Get和Post请求的方法 下一篇:FAdminAi开源系统

评论

评论(0)

暂无评论