活力39282
在线时间13640 小时
阅读权限200
管理员
自由的灵魂
- 积分
- 107434
- 主题
- 5630
- 回帖
- 26661
- 注册时间
- 2003-4-10
- 最后登录
- 2026-10-2
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
[2026-05-29] [性能] [IndexNow异步推送] - 发帖/编辑卡顿问题修复
标签:IndexNow 异步队列 发帖卡顿 性能优化 CLI脚本
1、问题缘起
论坛用户在发帖和编辑帖子时出现严重卡顿,带图片的帖子耗时超过30秒。通过PHP慢日志定位到卡顿点位于 post_editpost.php 第540行的 curl_exec() 调用,目标地址为 https://api.indexnow.org/IndexNow。
进一步排查发现,post_newthread.php 和 post_editpost.php 中均嵌入了同步向 IndexNow 搜索引擎推送 URL 的代码。当 IndexNow API 响应缓慢或超时时,整个发帖/编辑流程被阻塞,直到 curl 请求超时(约30秒)才能继续执行。
相关子问题:
- 同步推送导致用户体验严重下降
- 无失败重试机制,一次超时即推送失败
- 缺少对推送状态的监控和日志
2、解决方案
(1)简要技术分析:
将同步推送改为异步队列模式:发帖/编辑时仅将URL写入队列表,由后台计划任务(Crontab)定期遍历队列并发送HTTP请求,实现发帖流程与推送流程的解耦。
(2)修改、新增文件列表:
| 操作 | 文件路径 | 说明 | | 修改 | /www/wwwroot/www.dianbo.org/source/include/post/post_newthread.php | 发帖时改为异步入队 | | 修改 | /www/wwwroot/www.dianbo.org/source/include/post/post_editpost.php | 编辑时改为异步入队 | | 新增 | /www/wwwroot/www.dianbo.org/api/indexnow_cli.php | 异步推送CLI处理脚本 | | 新增 | 数据库表 dx_common_indexnow_queue | 推送队列表 |
(3)关键代码段:
队列表结构:
- CREATE TABLE `dx_common_indexnow_queue` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `host` varchar(255) NOT NULL DEFAULT '',
- `key` varchar(255) NOT NULL DEFAULT '',
- `url` varchar(255) NOT NULL DEFAULT '',
- `dateline` int(11) NOT NULL DEFAULT '0',
- `status` tinyint(1) NOT NULL DEFAULT '0',
- `retry` tinyint(1) NOT NULL DEFAULT '0',
- PRIMARY KEY (`id`)
- ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
复制代码
发帖文件入队代码(post_newthread.php 第306-324行):
- // ========= IndexNow 异步推送(入队) =========
- $excluded_fids = array(71, 73);
- if (!in_array($_G['fid'], $excluded_fids)) {
- $indexnow_host = "https://www.dianbo.org";
- $indexnow_key = "XXXXXXXXXXXXXXXXXXXXXXXXXX";
- $indexnow_url = "https://www.dianbo.org/thread-" . ($tid ?: $_G['tid']) . "-1-1.html";
- DB::query("INSERT INTO dx_common_indexnow_queue (host, `key`, url, dateline, status, retry) VALUES (" .
- DB::quote($indexnow_host) . ", " .
- DB::quote($indexnow_key) . ", " .
- DB::quote($indexnow_url) . ", " .
- TIMESTAMP . ", 0, 0)");
- }
- // ========= IndexNow 推送结束 =========
复制代码
CLI 处理脚本(api/indexnow_cli.php 核心部分):
- $tasks = DB::fetch_all("SELECT * FROM dx_common_indexnow_queue WHERE status = 0 ORDER BY id ASC LIMIT 5");
- foreach ($tasks as $task) {
- $ch = curl_init();
- curl_setopt($ch, CURLOPT_URL, 'https://api.indexnow.org/IndexNow');
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_TIMEOUT, 10);
- curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
- 'host' => $task['host'],
- 'key' => $task['key'],
- 'keyLocation' => $task['host'] . '/' . $task['key'] . '.txt',
- 'urlList' => [$task['url']]
- ]));
- $response = curl_exec($ch);
- $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
- curl_close($ch);
- $status = ($http_code >= 200 && $http_code < 300) ? 1 : 2;
- DB::query("UPDATE dx_common_indexnow_queue SET status = '$status' WHERE id = '{$task['id']}'");
- }
复制代码
Crontab 任务:
- */5 * * * * /usr/bin/php /www/wwwroot/www.dianbo.org/api/indexnow_cli.php >> /dev/null 2>&1
复制代码
3、最终实现效果
| 指标 | 优化前 | 优化后 | | 发帖响应时间 | 30+ 秒 | 即时(<1秒) | | 编辑响应时间 | 30+ 秒 | 即时(<1秒) | | IndexNow 推送方式 | 同步阻塞 | 异步队列 | | 失败重试 | 无 | 支持(status=2 可重试) | | 推送监控 | 无日志 | 日志记录 data/log/indexnow_async.log | | 版块排除 | 支持(71、73) | 保留相同逻辑 |
4、重要技术沉淀(需更新到固化摘要)
建议在 env-base 分支中新增:
- 十八、IndexNow 异步推送方案(2026-05-29)
- 问题:同步 curl 请求 api.indexnow.org 超时导致发帖卡顿
- 解决:队列表 + CLI 脚本 + Crontab 异步处理
- 队列表:dx_common_indexnow_queue
- CLI脚本:/api/indexnow_cli.php
- Crontab:*/5 * * * * /usr/bin/php /www/wwwroot/www.dianbo.org/api/indexnow_cli.php
- 排除版块:71、73
- 日志位置:/data/log/indexnow_async.log
复制代码
踩坑点:
- CLI 脚本需要模拟 $_SERVER 环境变量,否则 Discuz! 核心初始化失败
- IN_DISCUZ 常量在 class_core.php 中已定义,CLI 脚本不应重复定义
- 使用 DB::quote() 对插入值进行转义,防止SQL注入
5、进一步优化可能性
- 图片本地化插件异步化:当前转贴图片仍为同步下载,可参照此方案改为队列处理
- 百度推送异步化:发帖时同步推送百度的代码同样可改为异步队列
- 队列监控面板:在论坛后台增加队列状态查看功能,便于运维
|
|