首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 文章點擊統計快取方案:檔案緩衝 + 定時批次寫入資料庫

     編輯:PHP 相關知識

高流量下每篇文章每次點擊都 `UPDATE hits=hits+1` 會拖垮 MySQL。本方案採用「記憶體/檔案快取累積 → 定時批次同步資料庫」,大幅降低資料庫寫入壓力。

核心架構

  1. 點擊請求:JS 埋點 `` 或動態頁 `include`。
  2. 快取層:`log/click_log.txt` 存儲 `文章ID|累積點擊數`,每行一筆。
  3. 檔案鎖:`flock(LOCK_EX)` 保證併發寫入安全。
  4. 定時同步:讀取 `log/last_update.txt` 上次同步時間,超過閾值(預設 1800 秒)觸發批次 `UPDATE`。

完整實作代碼 (click.php)

<?php
error_reporting(E_ALL);
$ROOT_PATH = '../';
include_once($ROOT_PATH . "include/config.php");

$update_time = 1800; // 同步間隔(秒)
$article_id = (isset($_GET['article_id']) && is_numeric($_GET['article_id']) && $_GET['article_id'] > 0)
    ? intval($_GET['article_id']) : 0;

if ($article_id > 0) {
    $filename = $ROOT_PATH . 'log/click_log.txt';
    $d_ary = [];

    // 讀取現有快取
    if (file_exists($filename)) {
        $content = file_get_contents($filename);
        if ($content) {
            foreach (explode("\n", $content) as $line) {
                list($id, $hits) = explode('|', $line);
                if (is_numeric($id) && is_numeric($hits)) $d_ary[$id] = $hits;
            }
        }
    }

    // 累加點擊
    $d_ary[$article_id] = ($d_ary[$article_id] ?? 0) + 1;

    // 寫回快取 (帶檔案鎖)
    $s = '';
    foreach ($d_ary as $k => $v) $s .= "$k|$v\n";
    $fp = fopen($filename, "w");
    if (flock($fp, LOCK_EX)) {
        fwrite($fp, $s);
        flock($fp, LOCK_UN);
    }
    fclose($fp);
    @chmod($filename, 0777);

    // 定時同步邏輯
    $last_update = intval(@file_get_contents('../log/last_update.txt'));
    if (($last_update + $update_time) < time()) {
        require_once("adodb.inc.php");
        $db = NewADOConnection($DB_TYPE);
        $db->Connect($DB_HOST, $DB_USER, $DB_PASS, $DB_DATABASE);

        $content = file_get_contents($filename);
        if ($content) {
            foreach (explode("\n", $content) as $line) {
                list($id, $hits) = explode('|', $line);
                if (is_numeric($id) && is_numeric($hits)) {
                    $db->Execute("UPDATE article SET hits=hits+$hits WHERE id=$id");
                }
            }
        }

        // 清空快取、更新同步時間
        file_put_contents($filename, '');
        file_put_contents('../log/last_update.txt', time());
        @chmod('../log/last_update.txt', 0777);
        $db->Close();
    }
    exit();
}
?>

初始化部署

  1. 建立 `log/` 目錄可寫權限。
  2. 建立 `log/last_update.txt` 內容:當前 Unix 時間戳(如 `1155163400`)。
  3. `click_log.txt` 初始為空或預填 `文章ID|點擊數`。

優化建議

  • 快取改用 **Redis Hash** (`HINCRBY article:clicks {id} 1`):原子操作、無鎖、高效能、支援集群。
  • 同步觸發改為 **Crontab + 獨立 Worker** 執行,避免用戶請求卡在同步邏輯。
  • 批次 `UPDATE` 改用 `CASE WHEN` 合併單條 SQL:`UPDATE article SET hits = CASE id WHEN 1 THEN hits+10 WHEN 2 THEN hits+5 END WHERE id IN (1,2)`。
  • 加入異常重試與監控告警,防止快取檔損壞導致資料遺失。

此方案以極低成本解決「寫入放大」問題,是中小型站點升級前的最佳過渡架構。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved