我有一个整数 MySQL 列,每次查看页面时都会递增。SQL 查询如下所示:
UPDATE page SET views = views + 1 WHERE id = $id
当同一页面(相同的 id)每秒被查看多次(记录将锁定在 MySQL 中)并且查询会使 MySQL 停止运行时,我们开始遇到扩展问题。为了解决这个问题,我们一直在使用以下策略:
每次页面加载时,我们都会在 Memcache 中增加一个计数器,并将作业放入队列(Gearman)中,该队列将在后台(在 3 个工作机器中)更新 MySQL 中的计数器。简化的代码如下所示:
在页面视图中:
$memcache->increment("page_view:$id");
$gearman->doBackground('page_view', json_encode(array('id' => $id)));
在后台工作人员中:
$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}");
}
这运作良好。它允许我们减少对数据库的查询(因为我们在写入数据库之前在 memcache 中聚合视图)并且数据库写入发生在后台,而不是阻止页面加载。
不幸的是,我们又开始看到 MySQL 锁了。似乎非常活跃的页面仍在几乎同时运行,导致 MySQL 再次锁定。锁正在减慢写入速度并经常杀死我们的工人。这导致队列变得非常大,通常有 70k 多个“落后”作业
我的问题:下一步我们应该做什么来扩大规模?