我想计算一个页面的访问者数量,类似于stackoverflow对每个问题的“视图”所做的事情。
当前解决方案只是递增InnoDB表的字段:
UPDATE data SET readers = readers + 1, date_edited = date_edited WHERE ID = '881529' LIMIT 1
这是页面上最昂贵的查询,因为它正在执行写操作。
这个问题有更好的解决方案吗?像stackoverflow这样的高流量网站如何处理这个?
我正在考虑使用内存引擎写一个表,并且每隔一分钟就将该内容写入一个innodb表。
e.g:
INSERT INTO mem_table (id,views_new)
VALUES (881525,1)
ON DUPLICATE KEY UPDATE views_new = views_new+1
然后我会每分钟运行一次cron作业来更新InnoDB表:
UPDATE data d, mem_table m
SET d.readers = d.readers + m.readers_new
WHERE d.ID = m.ID;
DELETE FROM mem_table;
不幸的是,复制并不是很好,应用程序正在使用MySQL Galera Cluster。
提前感谢您提出任何建议。
答案 0 :(得分:0)
通过启动单独的线程来更新计数器,有很多方法可以降低即时性能。如果你有大量的并行用户(你的命中计数器的这么多并行更新),建议使用排队机制来防止锁定(就像你的内存表一样)。您的队列将具有写入和读取,因此您必须考虑表和数据设计。
替代方法是将与该文章相关的计数器保存在单独的文件中。这可以防止具有命中计数器的单个表上的拥塞,或者如果将其保留在为文章提供服务的表中:该文章表上的高锁等待时间(导致所有类型的前端错误)。将数据保存在单独的文件中并不能让您深入了解网站上的整体匹配,但为此您可以使用像awstats这样的日志图形工具。
答案 1 :(得分:0)
如果您可以在一个语句中将100 INSERTs
/ UPDATEs
一起批处理,则可以以10倍的速度运行它。 (存在lock_wait_timeout
和/或死锁的风险。)
如果您构建MEMORY
表并在电源故障时丢失排队的数据,该怎么办?我认为这个应用程序没问题? (如果没有,你有更大的问题。)
您的客户是什么?他们可以在触摸数据库之前排队吗?
我喜欢ping一对表来将数据暂存到数据库中。客户端写入一个表;连续运行的作业(不是cron作业)正在使用另一个表。当后者完成插入/更新时,它会使用单个原子RENAME TABLE
交换表,以便客户端无视。 My Staging Table blog进一步详细讨论了这一点。它解释了如何避免遇到的复制问题。
另一个提示。不要将计数和日期放在主表中。将它们放在“并行表”('垂直分区')中。这减少了复制的庞大程度,减少了对其他处理的干扰。
对于Galera,使用一对非复制表(建议没有索引的MyISAM)。让连续运行的作业在一个地方运行,循环通过3个节点。如果你有3个工作岗位,那么他们就有几种方式可能会相互绊倒。
如果无法跟上,则需要对数据进行分片。 (这就是大人们迟早会做的事情。)