我有一个包含数百万个网址的网站。每次单击URL时,都会更新与该URL对应的数据库行,指示该点击的时间戳。我想,使用其他列肯定,但不需要为每次点击插入不同的行,估计此URL接收的每小时点击次数。一些想法包括存储一些时间戳,这些时间戳与最近的第二,分钟,15分钟和小时间隔对齐(但这个想法对我来说很模糊,实际上如何得到我们想要的东西),或者更令人讨厌的序列化解决方案在某种序列化行中“记录”时间增量。
虽然一种天真的方法建议测量当前点击与最后一次点击之间的时间以确定一个速率,但如果以非常一致的速率点击链接,那么这只会产生有用的估计。实际上,链接可能会在一分钟内收到一连串的点击,而对于另一个链接则没有任何影响。
我不想明确记录每次单击的原因只是为了使数据库不会每小时有数千个额外的INSERT语句(以及超过一个小时的数据的相应DELETE),或者替代我不需要启动额外的存储系统(tokyo tyrant,grepping apache logs等)来记录这些点击。
答案 0 :(得分:4)
如何将计数器存储在memcached中,由URL键入,以及数据库中的last_counter_reset_time
?
Memcached有一个轻量级的原子incr
操作。在每个请求上调用它。定期重置计数器,更新last_counter_reset_time
。
我不是memcached的老手,但我想有很多方法可以确保所有网址的计数器都保持缓存状态。没有持久性,因此您可能随时丢失计数器,但偶尔会丢失此类数据。
答案 1 :(得分:3)
您是否尝试过其他方法,例如外部统计服务?也许谷歌分析?它可以为您提供您正在寻找的信息,而不会给您的服务器带来任何额外负担。
答案 2 :(得分:1)
你有没有理由忽视apache访问日志的处理?它们确实具有时间戳并由服务器自动创建的优点,并且相当轻便。然后,一个相当简单的perl或awk脚本可以保留日志的运行摘要,以便进行简单的解析。
答案 3 :(得分:0)
首先,为什么要保留时间戳?您可以通过在数据库中为每个URL设置一条记录来保持确切的计数,并且每次单击时只增加一个计数。
如果负载太大,我认为下一个最明显的答案是统计抽样。选择一个时间片,比如十分钟。对于每个十分钟切片,选择一个URL。计算该网址的点击次数。假设该十分钟的速率是一致的并乘以常数以得到任何所需时间段的估计速率。然后在接下来的十分钟切片中选择一个不同的URL。等
实际上,您可以一次计算多个URL而不会使服务器负担过重,因此您可以选择一些方便数量的URL,十个或一百个,或者系统可以处理的任何内容。
您还需要考虑一天中的时间。如果您的大多数用户都在加利福尼亚州,那么当太平洋时间下午4:00采样的网址可能会比在凌晨4:00采样时获得更高的点击次数。因此,您希望以一种方式循环访问URL,以确保当您返回到给定的URL时,它会在您第一次对其进行采样时处于不同的时间。如果您的用户均匀分布在整个世界,这不是问题,但这听起来不太可能。
答案 4 :(得分:0)
这可能不是一个实际的解决方案,但由于你要求“聪明”的方式,here是一个问题的学术研究,这不是你的问题,但可能会被调整。 “被引用者”列表中的一些论文可能更接近。
答案 5 :(得分:0)
如果您想要精确计数,Redis是完成此任务的理想选择。它与memcached的速度大致相当,但提供了持久性。持久性基于分叉和顺序写入磁盘,因此它避免了在数据库中保留此类信息的高负载。
如果您想要一种非常简单的方法:只需以非偏向的方式丢弃样本,(即log_request(foo) if rand(1) < 0.1
以取样10%的流量)。您将丢失所访问的网址上的任何信号,而不是您所采用的比率,但如果您最感兴趣的是高度访问的URL,则可以非常简单和有效。
在上述方案中有更复杂的变化,你更新计数器的概率是计数增长时的课程(然后在阅读时通过概率函数适当地加权计数器),这是一种重要的抽样形式的重要性抽样。这些几乎一样简单,并且更好地保留了分布尾部的数量。
啊,对不起,我现在从评论中看到你在一段时间后的费率。我用于此的方法基本上与采样/计数器相同,只是存储一些时间段(即每小时)的单个计数器。为了保持长期存档具有更长时间段(每日,每周)的附加汇总表,批处理作业从细粒度(每小时)表填充,允许您从细粒度表中删除旧数据。
RRDTool是这个想法的更通用的实现,并且几个OSS监控解决方案使用它。