9

我正在尝试使用以下查询跟踪 MySQL DB 中的综合浏览量:

"UPDATE $table SET pageviews = pageviews + 1 WHERE page_id = 1"

这适用于中低流量。但是,在高流量下,对 DB 的持续写入会导致高读/写争用并最终导致 DB 崩溃。

我已经阅读了 Stackoverflow 和其他地方的几个 QA,其中建议使用 MongoDB 作为替代方案。但是,该选择不可用,我必须坚持使用 MySQL。此外,我无法控制引擎——MyISAM 或 InnoDB(由于基于行的锁定而不是表,InnoDB 性能更好,就像 MyISAM 的情况一样)。

考虑到上述情况,在不破坏数据库(在数据库或其他东西中)的情况下,跟踪网页浏览量的最佳方法是什么?我真的很感激提供代码片段作为起点的答案(如果可能的话)。

顺便说一句,我正在使用 PHP。

更新:@fire 在这里有一个很好的解决方案。但是,它需要使用 memcache。我正在寻找无需特定基础设施即可轻松实现的东西。这是针对可以在不同托管环境中虚拟使用的模块。转念一想,我想到的是某种基于 cookie 或文件日志的实现。我不确定这种实施在实践中如何运作。任何进一步的投入都非常受欢迎。

4

3 回答 3

16

我会使用 memcached 来存储计数,然后将其与 cron 上的数据库同步...

// Increment
$page_id = 1;
$memcache = new Memcache();
$memcache->connect('localhost', 11211);

if (!$memcache->get('page_' . $page_id)) {
    $memcache->set('page_' . $page_id, 1);
}
else {
    $memcache->increment('page_' . $page_id, 1);
}

// Cron
if ($pageviews = $memcache->get('page_' . $page_id)) {
    $sql = "UPDATE pages SET pageviews = pageviews + " . $pageviews . " WHERE page_id = " . $page_id;
    mysql_query($sql);
    $memcache->delete('page_' . $page_id);
}
于 2012-11-29T15:16:54.010 回答
1

我会考虑使用您可用的最快的写作引擎收集原始点击:

INSERT INTO hits (page_id, hit_date) VALUES (:page_id, CURRENT_TIMESTAMP)

...然后运行一个定期进程,可能是一个 cron 命令行脚本,它将每小时或每天计算并存储您需要的页数摘要:

INSERT INTO daily_stats (page_id, num_hits, day)
SELECT page_id, SUM(hit_id)
FROM hits
WHERE hit_date='2012-11-29'
GROUP BY page_id

(查询只是示例,请根据您的需要进行调整)

另一个典型的解决方案是很好的旧日志解析,用你的 web 服务器的日志提供一个像 AWStats 这样的脚本。

澄清:我的第一个建议与@fire 的建议非常相似,但我没有涉及存储细节。关键是要以最快的方式延迟繁重的处理和最少量的原始信息。

于 2012-11-29T15:26:02.207 回答
0

您尚未指定此表的读取或写入速率。如果您将索引保持在绝对最小值并且行大小很小,MySQL 通常可以保持良好状态。带有页 ID 和计数器列的表在大多数情况下应该非常快。

InnoDB 也应该没问题。如果系统在繁重的写入活动期间崩溃或断电,MyISAM 可能会以最坏的方式爆炸,它不会被记录在日志中并且不能总是被恢复。InnoDB 更加健壮。

为了从 InnoDB 获得最大性能,您需要根据标准指南调整您的服务器并积极地对其进行基准测试以确保您做对了。每个操作系统都有其怪癖。有时,由于设置不正确,您可能会错过两倍的性能提升。

如果您的跟踪数据库很小,您可能希望创建一个由 RAM 磁盘支持的实例并将其复制到另一个具有常规 HD 的服务器。由于您期望非常高的写入活动,如果您可以在系统崩溃等最坏的情况下承受少量数据丢失,您可以简单地mysqldump定期对该数据库进行快照。转储内存支持的数据库甚至有一百万行应该只需要一分钟,并且不会由于 MVCC 而中断写入。

于 2012-11-29T15:51:55.607 回答