PHP+Swoole 打造高性能异步任务处理系统

袁志蒙 172次浏览

摘要:传统 PHP-FPM 存在同步阻塞、并发弱等问题,本文基于 Swoole 实现企业级异步任务系统,将短信发送、报表导出等耗时操作异步化。包含完整源码、服务配置、协程优化、异常重试及技术选型对比,适合 PHP 开发者进阶学习与项目落地。

作为 PHP 开发者,传统的 FPM 模式一直受限于同步阻塞、请求结束即销毁、高并发处理能力弱等问题。而 Swoole 是 PHP 生态最强大的协程网络通信引擎,让 PHP 真正具备支撑高并发、长连接、异步任务的能力。

这篇文章不讲基础入门,直接带你实现企业级 Swoole 异步任务处理系统,用于处理:短信发送、邮件推送、订单统计、日志上报、Excel 导出等耗时操作,单机轻松支撑万级并发,是 PHP 进阶必备技能。

一、为什么要用 Swoole 做异步任务?

传统 PHP FPM 缺点:

耗时任务(发送短信 / 生成报表)会阻塞前端响应,用户等待时间长

并发高时,FPM 进程耗尽,服务直接卡死

无法实现异步、延时、队列化处理

Swoole 异步任务优势:

非阻塞异步处理:前端接口快速响应,任务后台悄悄执行

协程高并发:单进程支撑上千协程,资源消耗极低

常驻内存:无需重复初始化数据库、连接池

任务队列化:削峰填谷,保护数据库

二、环境要求

PHP >= 7.4

Swoole 扩展 >= 4.8(必须安装)

Linux 系统(不支持 Windows)

安装 Swoole:

pecl install swoole

三、系统架构设计

我们要实现一个生产可用的异步任务系统,包含 3 大核心组件:

HTTP 服务器:接收前端提交的任务(如发送短信、导出 Excel)

Task 异步任务池:后台异步执行耗时逻辑

任务管理器:任务投递、状态记录、异常重试、日志记录

架构流程:

前端请求 → HTTP 接口接收 → 投递任务到 Task 池 → 接口立即返回成功 → 后台异步执行任务

四、完整实战代码

1. 主服务启动文件:server.php

<?php
// 关闭输出缓冲区,避免日志乱码
ob_end_clean();

// Swoole HTTP 服务器
$http = new Swoole\Http\Server('0.0.0.0', 9501);

// 服务器配置(核心参数)
$http->set([
    'worker_num' => 4,          // 工作进程数:CPU核心数×1~2
    'task_worker_num' => 8,     // 异步任务进程数:根据耗时任务调整
    'daemonize' => 0,           // 守护进程:1=后台运行,0=调试模式
    'log_file' => '/tmp/swoole_task.log', // 日志路径
    'task_enable_coroutine' => true, // 开启Task协程(关键)
]);

// 服务启动事件
$http->on('Start', function ($server) {
    echo "Swoole 异步任务服务启动成功!监听:0.0.0.0:9501\n";
});

// 处理HTTP请求(接收任务)
$http->on('Request', function ($request, $response) use ($http) {
    // 只允许POST请求
    if ($request->server['request_method'] != 'POST') {
        $response->end(json_encode(['code' => 403, 'msg' => '请求方式错误']));
        return;
    }

    // 接收任务类型和参数
    $taskType = $request->post['task_type'] ?? '';
    $taskData = $request->post['task_data'] ?? [];

    if (empty($taskType)) {
        $response->end(json_encode(['code' => 400, 'msg' => '任务类型不能为空']));
        return;
    }

    // 封装任务数据
    $task = [
        'type' => $taskType,
        'data' => $taskData,
        'time' => date('Y-m-d H:i:s')
    ];

    // 投递异步任务(非阻塞,立即返回)
    $http->task($task);

    // 立即响应前端:任务已接收
    $response->end(json_encode([
        'code' => 200,
        'msg' => '任务已加入队列,后台异步处理中'
    ]));
});

// 异步任务处理核心逻辑(后台执行)
$http->on('Task', function ($server, $taskId, $workerId, $data) {
    echo "开始执行异步任务:ID={$taskId},类型=" . $data['type'] . "\n";

    try {
        // 根据任务类型分发执行
        switch ($data['type']) {
            case 'send_sms':
                $this->handleSendSms($data['data']);
                break;
            case 'export_excel':
                $this->handleExportExcel($data['data']);
                break;
            case 'user_report':
                $this->handleUserReport($data['data']);
                break;
            default:
                throw new Exception('未知任务类型');
        }

        echo "任务执行成功:ID={$taskId}\n";
    } catch (Throwable $e) {
        // 任务异常捕获
        echo "任务执行失败:ID={$taskId},错误:" . $e->getMessage() . "\n";
    }

    // 任务结束
    $server->finish('ok');
});

// 任务完成回调
$http->on('Finish', function ($server, $taskId, $data) {
    // 任务完成后的清理工作(可选)
});

// 启动服务
$http->start();
?>

2. 任务处理类(实际业务逻辑)

我们把业务逻辑封装成方法,支持短信发送、Excel 导出、用户统计三大企业常用任务:

<?php
// 任务处理类(放到server.php中)
class TaskHandler
{
    // 1. 异步发送短信
    public function handleSendSms($data)
    {
        $phone = $data['phone'];
        $content = $data['content'];
        // 模拟短信接口请求(耗时1秒)
        co::sleep(1);
        file_put_contents('/tmp/sms_log.txt', "发送短信:{$phone},内容:{$content}\n", FILE_APPEND);
    }

    // 2. 异步导出Excel
    public function handleExportExcel($data)
    {
        $userId = $data['user_id'];
        // 模拟大数据量导出(耗时3秒)
        co::sleep(3);
        file_put_contents("/tmp/excel_{$userId}.xlsx", "用户ID:{$userId} 的导出文件\n");
    }

    // 3. 异步生成用户统计报表
    public function handleUserReport($data)
    {
        $date = $data['date'];
        // 模拟数据库统计(耗时2秒)
        co::sleep(2);
        file_put_contents('/tmp/report_log.txt', "{$date} 用户统计完成\n", FILE_APPEND);
    }
}

// 实例化
$this = new TaskHandler();
?>

五、启动与测试

1. 启动服务

php server.php

2. 用 curl 测试投递异步任务

# 投递发送短信任务
curl -X POST http://127.0.0.1:9501 -d "task_type=send_sms&task_data[phone]=13800138000&task_data[content]=您的验证码是1234"

# 投递Excel导出任务
curl -X POST http://127.0.0.1:9501 -d "task_type=export_excel&task_data[user_id]=1001"

3. 效果

接口瞬间返回成功

后台异步执行耗时任务,不阻塞前端

任务自动排队,不会压垮服务器

六、进阶(生产环境必备)

1. 协程连接池(防数据库连接耗尽)

Swoole 常驻内存,必须用数据库连接池,否则会出现连接丢失:

// Swoole 协程MySQL连接池
$db = new Swoole\Coroutine\MySQL();
$db->connect([
    'host' => '127.0.0.1',
    'user' => 'root',
    'password' => '123456',
    'database' => 'test',
]);

2. 任务异常重试机制

// 失败重试3次
$retry = $data['retry'] ?? 0;
if ($retry < 3) {
    $data['retry']++;
    $server->task($data); // 重新投递
}

3. 任务状态记录(Redis)

用 Redis 记录任务执行状态,前端可查询进度:

$redis->hSet('task_status', $taskId, 'executing');

七、Swoole 异步任务 vs 传统消息队列(RabbitMQ/Redis)

方案复杂度性能部署成本适合场景
Swoole Task极低极高PHP 项目内部异步任务
消息队列跨语言、分布式、大流量
结论:PHP 项目内部做异步处理,Swoole 是最简单、最高效、成本最低的方案。

随机内容

表情

共0条评论
  • 这篇文章还没有收到评论,赶紧来抢沙发吧~