如何仅在log.txt更新时刷新页面区块 避免聊天室服务因高频刷新崩溃
问题根因
你原方案的核心问题是每2秒全量刷新页面,每次请求都需要触发PHP解析、读取整个log.txt、返回完整页面内容,单用户每秒都会产生多次高开销请求,在线人数上涨后服务器CPU和磁盘IO很快被打满,自然会崩溃。
最低改造成本方案:HEAD请求轻量轮询
该方案不用改后端逻辑,仅调整前端代码即可,服务器压力可以直接降低90%以上:
<html style='background-color:#202020; color:#FFFFFF;'> <head> <!-- 移除自动刷新meta标签 --> </head> <body> <div id="chatLog"></div> <script> let lastModified = null; const chatLogEl = document.getElementById('chatLog'); async function checkUpdate() { try { // 仅请求响应头,不获取文件内容,开销极低 const headRes = await fetch('./log.txt', { method: 'HEAD' }); const currentModified = headRes.headers.get('Last-Modified'); // 仅当文件修改时间变化时才拉取完整内容 if (currentModified !== lastModified) { const contentRes = await fetch('./log.txt'); chatLogEl.textContent = await contentRes.text(); lastModified = currentModified; } } catch(err) {} } // 页面加载先拉取一次内容 checkUpdate(); // 每2秒检查一次更新,绝大多数请求仅传输几十字节的响应头 setInterval(checkUpdate, 2000); </script> </body> </html>
进阶优化方案:增量拉取接口
如果能改后端代码,可以新增一个轻量接口进一步降低开销:
- 新增
get_new_log.php后端接口:
<?php $logPath = './log.txt'; $lastFetchTime = isset($_GET['last_time']) ? intval($_GET['last_time']) : 0; $currentMtime = filemtime($logPath); header('Content-Type: application/json'); if ($currentMtime > $lastFetchTime) { echo json_encode([ 'update' => true, 'content' => file_get_contents($logPath), 'time' => $currentMtime ]); } else { echo json_encode(['update' => false]); } ?>
- 前端调整请求逻辑,仅当有更新时才接收内容,无更新时接口仅返回十几字节的响应,开销更低。
最优性能方案:SSE服务器主动推送
完全避免无意义的轮询请求,服务器发现文件更新后主动推送给前端,同等配置下可承载的在线人数是轮询方案的10倍以上:
- 前端代码:
<html style='background-color:#202020; color:#FFFFFF;'> <body> <div id="chatLog"></div> <script> if (window.EventSource) { const source = new EventSource('./sse_push.php'); source.onmessage = e => { document.getElementById('chatLog').textContent = e.data; }; } </script> </body> </html>
- 新增
sse_push.php后端接口:
<?php header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); header('Connection: keep-alive'); $logPath = './log.txt'; $lastMtime = filemtime($logPath); while (true) { $currentMtime = filemtime($logPath); if ($currentMtime > $lastMtime) { $content = file_get_contents($logPath); echo "data: $content\n\n"; ob_flush(); flush(); $lastMtime = $currentMtime; } sleep(1); } ?>
额外优化建议
- 给log.txt配置Web服务器静态缓存规则,直接由Nginx/Apache处理静态文件请求,不用走PHP解析,性能提升更明显
- 聊天记录量大时建议拆分存储,不要全部存在单个txt文件中,避免单文件过大导致读取IO过高
- 发送消息的逻辑可以配套做简单的去重校验,避免重复写入相同内容
内容的提问来源于stack exchange,提问作者Adi B.
相关产品推荐
相关产品推荐

