You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP中优化推送通知CURL循环速度的技术问询

你的推送服务问题分析与优化方案,以及大厂推送系统实现思路

一、你的代码核心问题

  • 串行请求导致耗时叠加:循环里逐个发送请求,每个请求都要等响应返回才处理下一个,2000次请求的等待时间直接累加,这是耗时近5分钟的主要原因。
  • 未利用批量推送API:APNS和FCM都支持批量推送,你却单条发送,白白增加了请求次数和网络开销。
  • 同步操作拖慢速度:每次请求后都用echo输出结果,还有单条删除数据库记录的操作,这些同步IO会额外消耗时间。
  • 数据库操作低效:一次性拉取所有token,没有分批处理;删除无效token时单条执行,多次和数据库交互。
  • curl配置重复冗余:每次发送请求都重新设置所有curl选项,很多固定配置可以提前设置,减少重复操作。

二、针对性优化方案

1. 改用平台提供的批量推送API

这是最立竿见影的优化,直接把请求次数从几千次降到几次:

  • FCM批量推送:用registration_ids字段,一次最多传500个token,批量发送给安卓设备。
  • APNS批量推送:调用/3/device/batch端点,一次最多发送100条通知。

FCM批量推送代码示例

function sendFCMBatch($title, $body, $tokens) {
    $server_key = 'serverKey';
    $authKey = "key=" . $server_key;
    $payload = [
        'registration_ids' => $tokens,
        'notification' => [
          'title' => $title,
          'body' => $body
        ]
    ];

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => "https://fcm.googleapis.com/fcm/send",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($payload),
        CURLOPT_HTTPHEADER => [
            "Authorization: " . $authKey,
            "Content-Type: application/json"
        ],
    ]);

    $response = curl_exec($ch);
    $err = curl_error($ch);
    curl_close($ch);

    if ($err) {
        error_log("FCM批量推送错误: " . $err);
    } else {
        $responseData = json_decode($response, true);
        $invalidTokens = [];
        foreach ($responseData['results'] as $idx => $result) {
            if (isset($result['error']) && in_array($result['error'], ['InvalidRegistration', 'NotRegistered'])) {
                $invalidTokens[] = $tokens[$idx];
            }
        }
        if (!empty($invalidTokens)) {
            batchRemoveFromDatabase($invalidTokens);
        }
    }
}

APNS批量推送代码示例

function sendAPNSBatch($pushTitle, $pushBody, $tokens) {
    if (!defined("CURL_VERSION_HTTP2") || !(curl_version()["features"] & CURL_VERSION_HTTP2)) {
        error_log("无HTTP/2支持");
        return;
    }

    $batchPayload = [];
    foreach ($tokens as $token) {
        $batchPayload[] = [
            'aps' => [
                "alert" => [
                    "title" => $pushTitle,
                    "body" => $pushBody
                ],
                "sound" => "default",
                "badge" => 1
            ],
            'token' => $token
        ];
    }

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL => "https://api.push.apple.com/3/device/batch",
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($batchPayload),
        CURLOPT_SSLCERT => "apns.pem",
        CURLOPT_SSLCERTPASSWD => "",
        CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
        CURLOPT_HTTPHEADER => [
            "apns-topic: com.test",
            "Content-Type: application/json"
        ],
    ]);

    $response = curl_exec($ch);
    $err = curl_error($ch);
    curl_close($ch);

    if ($err) {
        error_log("APNS批量推送错误: " . $err);
    } else {
        $responseData = json_decode($response, true);
        $invalidTokens = [];
        foreach ($responseData as $item) {
            if (isset($item['status']) && $item['status'] != 200) {
                $invalidTokens[] = $item['token'];
            }
        }
        if (!empty($invalidTokens)) {
            batchRemoveFromDatabase($invalidTokens);
        }
    }
}

2. 优化数据库操作

  • 分批查询token:比如每次从数据库拉500条,避免一次性加载过多数据到内存。
  • 批量删除无效token:收集所有无效token,用一次SQL批量删除,减少数据库交互次数。
function batchRemoveFromDatabase($tokens) {
    global $dbh;
    if (empty($tokens)) return;
    $placeholders = implode(',', array_fill(0, count($tokens), '?'));
    $stmt = $dbh->prepare("DELETE FROM table WHERE token IN ($placeholders)");
    $stmt->execute($tokens);
    error_log("批量删除了 " . count($tokens) . " 个无效token");
}

3. 移除同步输出,改用日志记录

把代码里的echo改成error_log写入日志文件,避免每次请求都输出到浏览器,减少IO耗时。

4. 并行请求或异步处理

如果批量API还不够,可尝试用PHP多进程(如pcntl_fork)或者异步HTTP客户端(如Guzzle异步请求),同时发送多个请求,进一步压缩总耗时。

三、大厂推送系统的实现思路

像WhatsApp、Telegram、Gmail这类大厂能处理每秒数十亿推送,核心是靠分布式异步架构+极致的协议优化,大致分为几个层面:

  • 消息队列缓冲:所有推送请求先进入Kafka、RabbitMQ这类消息队列,削峰填谷,避免瞬间流量压垮后端。
  • 分布式推送集群:部署成千上万台推送服务器,通过负载均衡把请求分配到不同节点,每个节点负责一部分用户的推送。
  • 长连接复用:和APNS、FCM等服务商保持大量长期连接,避免每次请求都重新建立TCP连接和SSL协商,节省握手开销。
  • 智能路由与批量处理:缓存用户设备的推送网关地址,根据用户地理位置选择最近的网关;把同区域、同平台的推送请求合并批量发送。
  • 容错重试机制:对失败的推送自动重试(区分可重试和不可重试错误),同时有降级策略,高负载时优先处理重要推送。
  • 实时监控与动态调优:实时监控推送成功率、延迟等指标,动态调整集群规模和推送策略,保证系统稳定高效。

内容的提问来源于stack exchange,提问作者swifthing

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 19:33:29