如何为网站编写高效的计数器
Posted
技术标签:
【中文标题】如何为网站编写高效的计数器【英文标题】:How to write an efficient hit counter for websites 【发布时间】:2010-12-04 20:23:59 【问题描述】:我想编写一个点击计数器脚本来跟踪网站上图片的点击和原始 IP。每天的展示次数超过数十万,因此计数器每秒会增加很多次。
我正在寻找一种简单的自托管方法(php、python 脚本等)。我正在考虑使用 mysql 来跟踪这一点,但我猜有一种更有效的方法。有什么好的保持计数器的方法?
【问题讨论】:
【参考方案1】:一个引人入胜的主题。增加一个计数器,尽管它可能很简单,只是 必须 是一个事务...意思是,它可以锁定整个数据库比有意义的时间更长!-) 它很容易成为瓶颈整个系统。
如果您需要严格准确的计数但不需要它们立即更新,我最喜欢的方法是将可计数信息附加到日志中(根据需要经常切换日志以达到数据新鲜度的目的)。一旦日志关闭(其中包含数千个可计数的事件),脚本就可以读取它并更新单个事务中所需的所有内容 - 可能不直观,但比数千个单个锁要快得多。
还有一些非常快的计数器,它们仅在统计上是准确的——但既然你没有说这种不精确是可以接受的,我不打算更深入地解释它们。 p>
【讨论】:
大多数网络服务器都提供此日志。看我的回答。 @middus,当然,但我的意思是(即使您关心的内容没有被记录,或者您所在的主机不允许您访问日志)您仍然可以计算通过您自己的专用日志(处理此类日志也比一般日志快得多,因为您可以根据计数需求对其进行定制;您可以通过比一般日志更频繁地关闭计数日志来合理地经常更新数据库;等等)。 是的,你当然是对的。但是,在这种特定情况下,当您处理图像时,您将不得不通过某种脚本来传输所有流量,这是一个相当大的开销。 (至少我看不到更好的选择)。 @middus,更好的选择可能包括确保图像由单独的服务器进程提供(不难,通过适当地安排目录——它们通常需要在单独的 域 i> 无论如何,以避免无用的 cookie 开销)并为此目的配置该单独服务器的日志记录。但这更多地涉及服务器故障子线程;-)。【参考方案2】:您可以获取您的网络服务器的访问日志(Apache:access.log)并一次又一次地评估它(cronjob),以防您不需要在确切时刻手头的数据有人访问您的网站的时间。
通常,无论如何都会生成 access.log,其中包含请求的资源以及时间、日期和用户的 IP。这样您就不必通过 php 脚本来路由所有流量。精益,意味着计数机。
【讨论】:
【参考方案3】:毫无疑问,Redis 非常适合解决这个问题。它需要大约一分钟的时间来设置和安装,支持原子增量,速度非常快,有用于 python 和 php(以及许多其他语言)的客户端库,是持久的(快照、日志、复制)。
将每个计数器存储到自己的密钥中。那就干脆
INCR key
【讨论】:
【参考方案4】:有两种非常简单的方法:
-
从您的网络日志中批量解析。
通过beanstalkd 或gearmand 运行点击,并让工人以可控的方式完成艰巨的工作。
选项 1 适用于现成的工具。选项 2 只需要一点编程,但可以让您更接近实时更新,而不会导致您在流量高峰时摔倒(例如您会在直接 mysql 案例中发现)。
【讨论】:
【参考方案5】:如果准确性很重要,您可以使用 MySql 稍微慢一些...创建一个 HEAP / 内存表来存储您的计数器值。这些内存表非常快。您可以每隔一段时间将数据写入普通表。
根据应用引擎的想法,您可以使用 memcache 作为计数器的临时存储。增加内存缓存计数器比使用 MySql 堆表(我认为)要快。每五或十秒一次,您可以读取内存缓存计数器并将该数字写入您的数据库。
【讨论】:
【参考方案6】:不确定它是否适合您,但 AppEngine 是一个非常不错的构建平台。此处描述了一些可用于使用其 DataStore 和事务构建计数器的示例代码:http://code.google.com/appengine/docs/python/datastore/transactions.html。
【讨论】:
我们试图在应用引擎中存储大量的计数器,结果证明这在 CPU 时间上很昂贵。也就是说,它的成本是 $$。【参考方案7】:您可以使用Redis - 它是非常快速的键值存储,支持原子增量。如果需要 - 计数数据可以轻松地在多个服务器之间拆分。
【讨论】:
【参考方案8】:我做过非常相似的事情,规模相似(多台服务器、数百个域、每小时数千次点击),日志文件分析绝对是要走的路。 (它还检查命中率,按文件类型对它们进行加权,如果它们发出过多的请求,则在防火墙上将 IP 地址列入黑名单;它的预期目的是自动阻止坏机器人,不仅仅是一个计数器,而是计数它的重要组成部分。)
对网络服务器进程本身没有性能影响,因为它没有在那里做任何额外的工作,而且您可以通过每分钟/5 分钟/100 次点击/其他任何情况将定期更新的点击计数注入网站的数据库来轻松发布每次点击都必须锁定相关的行/表/数据库(取决于使用的锁定机制)。
【讨论】:
这听起来很棒,关于如何开始创建它的任何提示?用PHP能做到吗? @swt83:我用过Perl,但我的理解是PHP已经被扩展为可以在非web环境中运行,所以应该是可以的。对于一个简单的计数器,基本上只需设置一个 cron 作业以每隔一段时间运行一次,检查访问是否有新的命中(每次记录文件结束位置,以便下一次运行可以从哪里开始最后一个停止而不是重新处理整个日志),并根据您的喜好处理/总结它们。如果您希望它是实时的,请将其编写为tail -f
类型的监视器,该监视器在文件写入时从文件中读取(只需注意日志轮换)。【参考方案9】:
好吧,如果你碰巧走 PHP 路线,你可以使用 SQLite 数据库,但是 MySQL 是存储该信息的一种完全合理的方式,通常(至少从我所见)是如何完成的.
如果您不想将 IP 地址和任何其他信息存储在一个简单的数字 文本文件可以工作。
【讨论】:
我是 SQLite 和简单文本文件的忠实粉丝,但两者都不适合这项任务。假设不止一台服务器,不止一张图片,不止一张并发命中,等等......以上是关于如何为网站编写高效的计数器的主要内容,如果未能解决你的问题,请参考以下文章