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
相关产品推荐
相关产品推荐

