记录大量点击次数到MySQL数据库的最佳实践

39

好的,这是关键。假设我的未来 PHP CMS 需要每天处理 500k 访问者并将它们全部记录在 MySQL 数据库中(referrer、ip 地址、时间等)。这意味着我需要每分钟插入 300-500 行数据并更新 50 行。主要问题是每次有人打开页面时,脚本都会调用数据库以插入新行。

我的问题是,是否有任何方法可以首先在本地缓存传入的点击量(最好的解决方案是什么,apc、csv...?),然后每隔 10 分钟将它们定期发送到数据库?这是一个好的解决方案吗?对于这种情况,最佳实践是什么?


1
另外,在那个大表格上跟踪唯一访客(按IP地址)的最佳方法是什么? - livelygreen
SELECT DISTINCT ( ip ) FROM access_log - genesis
10个回答

21

每天500k的请求只相当于每秒5-7个查询。如果每个请求的服务时间为0.2秒,则几乎没有同时查询,所以不用担心。
即使用户数增加五倍,一切也应该正常运作。
你可以使用INSERT DELAYED并调整mysql。
关于调整:http://www.day32.com/MySQL/ - 这里有一个非常有用的脚本(它不会改变任何设置,只是向你展示如何优化设置)。

你可以使用memcache或APC先将日志写入其中,但使用INSERT DELAYED MySQL将几乎完成同样的工作,并且做得更好 :)

请不要使用文件进行这种操作。数据库会比PHP更好地提供锁定服务。编写有效的互斥量并不那么轻松,因此让数据库(或memcache、APC)来完成这项工作。


+1 对于更完整的答案和关于INSERT DELAYED的讨论。 - Kevin Peno

17

经常使用的解决方案:

您可以在memcached中实现一个计数器,每次访问都会加一,并在累计到100(或1000)个点击时向数据库推送更新。


4
使用内存缓存而不是文件缓存(如其他回答中所述)速度快得多!+1 - Matthieu Napoli

4
我们通过在每个服务器上本地存储CSV文件,然后设置每分钟的cron作业将条目推送到数据库中来实现此操作。这样做是为了避免需要高可用性的MySQL数据库 - 数据库应该能够轻松处理那么多插入操作而不出问题。

3
将它们保存到基于目录的数据库(或扁平文件,取决于情况),然后在特定时间使用PHP代码将它们插入/更新到您的MySQL数据库中。您的PHP代码可以使用Cron定期执行,因此请检查您的服务器是否具有Cron,以便您可以设置计划,例如每10分钟一次。
请查看此页面:http://damonparker.org/blog/2006/05/10/php-cron-script-to-run-automated-jobs/。某些代码已经编写在云端并准备供您使用 :)

文件crontab.php无法在页面http://damonparker.org/blog/2006/05/10/php-cron-script-to-run-automated-jobs/下载。 - xuesong
尝试寻找其他脚本吧 :) 网络上有成千上万的脚本。 - user743234

2

一种方法是使用Apache访问日志。您可以使用cronolog实用程序和Apache一起获得相当好的日志记录。Cronolog将处理大量行的存储,并且可以根据容量、天数、年份等进行旋转。使用此实用程序将防止Apache遭受日志写入。

然后,正如其他人所说,使用基于cron的作业来分析这些日志,并将您想要的任何汇总或原始数据推送到MySQL中。

您可以考虑使用专用数据库(甚至是数据库服务器)进行写入密集型作业,并进行特定设置。例如,您可能不需要InnoDB存储并保持简单的MyIsam。您甚至可以考虑使用另一个数据库存储(如@Riccardo Galli所说)。


2
如果您一定要直接登录到MySQL,请考虑使用两个数据库。其中一个专门用于快速插入数据,这意味着除了可能的自增主键之外没有其他键。另一个数据库则将所有需要查询的内容都添加索引,以便查询速度更快。可以通过定时任务将插入数据库中的数据复制到只读数据库中,从而实现最佳效果。唯一的缺点是您可用的统计数据只能与上一次“复制”运行时的数据相同。

2

我之前看到过一个系统,它会将数据记录到每个Web服务器的本地磁盘上的一个平面文件中(如果使用多处理器,请只进行原子追加),然后通过守护进程或定时任务周期性地异步写入数据库。

这似乎是当前最优解决方案;如果审计数据库宕机,您的Web应用程序仍然可用,并且如果由于任何原因数据库变慢,用户也不会遭受低性能的影响。

唯一需要注意的是,确保对这些本地生成的文件进行监控 - 如果堆积了大量文件,则表示存在问题,否则您的Ops工程师可能不会注意到。


0

如果需要进行大量写操作并处理此类数据,您可能会发现mongodb或couchdb更适合。


为了进行明智的报告,您需要使用SQL。这并不是“高写入操作次数”。尝试在XXXdb(将XXX替换为您最喜欢的NoSQL)中进行GROUP BY查询。 - MarkR

0

由于INSERT DELAYED仅受MyISAM支持,因此对于许多用户来说这不是一个可选项。

我们使用MySQL Proxy来延迟执行与特定签名匹配的查询。

这将需要一个自定义的Lua脚本; 示例脚本在此处, 和 一些教程在此处

该脚本将实现一个队列数据结构用于存储查询字符串,并进行模式匹配以确定要推迟哪些查询。一旦队列达到一定大小,或经过一定时间,或发生任何事件X,查询队列将被清空,因为每个查询都会发送到服务器。


0

你可以使用Beanstalk或IronQ来实现队列策略


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接