gpt4 book ai didi

php - 在 MySQL 中缩放递增计数器(用于跟踪页面浏览量)

转载 作者:可可西里 更新时间:2023-11-01 06:37:53 25 4
gpt4 key购买 nike

我有一个整数 MySQL 列,每次查看页面时该列都会递增。 SQL 查询看起来像这样:


更新页面 SET views = views + 1 WHERE id = $id

当同一页面(相同 ID)每秒被查看多次(记录会锁定在 MySQL 中)并且查询会使 MySQL 停止运行时,我们开始遇到扩展问题。为了解决这个问题,我们一直在使用以下策略:

每次页面加载时,我们都会在 Memcache 中增加一个计数器,并将一个作业放入队列 (Gearman) 中,该队列将在后台更新 MySQL 中的计数器(在 3 个工作机器中)。简化的代码如下所示:

在页面 View 中:

$memcache->increment("page_view:$id");
$gearman->doBackground('page_view', json_encode(array('id' => $id)));

在后台 worker 中:

$payload = json_decode($payload);
$views = $memcache->get("page_view:{$payload->id}");
if (!empty($views)) {
$mysql->query("UPDATE page SET views = views + $views WHERE id = {$payload->id}");
$memcache->delete("page_view:{$payload->id}");
}

这很有效。它允许我们减少对数据库的查询(因为我们在写入数据库之前聚合内存缓存中的 View )并且数据库写入发生在后台,不会阻止页面加载。

不幸的是,我们又开始看到 MySQL 锁了。似乎非常活跃的页面几乎同时运行,导致 MySQL 再次锁定。锁正在减慢写入速度并经常杀死我们的 worker 。这导致队列变得非常大,通常有 7 万多个作业“滞后”

我的问题:下一步我们应该做什么来扩展它?

最佳答案

我对 Gearman 了解不多,所以我可能是错的。

每次递增计数器时,您都在排队一个 gearman 任务。我想只有当 $memcache->increment 的结果为 1 时才将任务入队会更好。我的理由是下一次更新将在 gearman 任务清除 page_view 后到达:$i,您不会有很长的 gearman 任务队列渴望更新数据库中的这个新值。这应该使您的代码独立于您的更新率,并限制 gearman 选择新任务的速度(希望足够慢)。在一个完美的世界中,你可以让 gearman 延迟这个任务 ~1s。这将确保您仅以 1 qps 的速率更新此计数器。

独立于 gearman,如果您可以接受较慢的 READ 并假设您使用的是 InnoDB,则可以对这个计数器进行分片。

要做到这一点,只需添加一个分片列并使其成为主键的一部分,例如

CREATE TABLE page (
id INTEGER,
shard INTEGER,
views INTEGER,
PRIMARY KEY (id, shard)
)

当您更新此计数器时,随机选择 1 - 10 之间的分片。当您读取它时,对您要读取的 id 的所有分片求和。这将使读取速度慢 10 倍,但它可以让您在写入时扩展 10 倍。 (当然不一定是10个,你可以随便选一个。)

关于php - 在 MySQL 中缩放递增计数器(用于跟踪页面浏览量),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14617321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com