首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫

MySQL 高並發計數器設計:從單行熱點到分桶隨機更新的演進實戰

     編輯:MySQL 資料庫相關知識

問題背景

文章點擊數、商品瀏覽數、廣告曝光數等計數器場景,典型特徵:極高寫入並發、讀多寫少、允許最終一致性。單行更新導致熱點鎖爭用,嚴重限制吞吐。

方案演進

階段 0:單表單行(反模式)


CREATE TABLE article (
    id INT PRIMARY KEY,
    title VARCHAR(200),
    view_count BIGINT DEFAULT 0
);
-- UPDATE article SET view_count = view_count + 1 WHERE id = 123;

所有並發聚焦同一行 → 行鎖排隊 → 吞吐上限極低。

階段 1:拆分計數器表(仍單行熱點)


CREATE TABLE article_view (
    article_id INT PRIMARY KEY,
    view_count BIGINT DEFAULT 0
);

分離熱點欄位,但 UPDATE article_view SET view_count = view_count + 1 WHERE article_id = 123 仍是單行熱點,鎖爭用未解。

階段 2:分桶隨機更新(核心優化)


CREATE TABLE article_view (
    article_id INT NOT NULL,
    bucket TINYINT UNSIGNED NOT NULL COMMENT '分桶 0-99',
    view_count BIGINT DEFAULT 0,
    PRIMARY KEY (article_id, bucket)
) ENGINE=InnoDB;
  • 每篇文章 100 個桶(bucket 0-99)
  • 寫入時:bucket = FLOOR(RAND() * 100) 隨機選一桶更新
  • 讀取時:SELECT SUM(view_count) FROM article_view WHERE article_id = 123

單條 UPSERT 實現(原子性)


INSERT INTO article_view (article_id, bucket, view_count)
VALUES (123, FLOOR(RAND()*100), 1)
ON DUPLICATE KEY UPDATE view_count = view_count + 1;

無需應用層 SELECT 判斷,ON DUPLICATE KEY UPDATE 保證原子性。

桶數選擇權衡

小流量 3-5 桶足矣,避免過度設計。

進階優化

  • 讀端快取:Redis 緩存聚合結果,定期(如每分鐘)同步回 MySQL 或直接由 Redis 計數、MySQL 持久化
  • 異步寫入:應用層批次累積 → 定時刷入 DB(Kafka/消息佇列解耦)
  • 分區表:按 article_id Hash 分區,物理隔離熱點
  • ClickHouse / Apache Doris:OLAP 引擎原生支援高基數計數,查詢毫秒級

避坑指南

  • RAND() 種子問題:Statement-based Replication 下 RAND() 導致主從不一致,必須用 Row-based Binlog 或應用層生成隨機數
  • ON DUPLICATE KEY UPDATE 會觸發 AUTO_INCREMENT 增長(若有隱藏主鍵),無實質影響但需知曉
  • 極端熱點單文章:考慮獨立計數服務(Redis INCR + 定時落盤)

小結

高並發計數器核心模式:分桶隨機寫 + 聚合讀。INSERT ... ON DUPLICATE KEY UPDATE 單條語句解決原子性。桶數 100 起步,配合 Redis 快取讀端,支撐百萬級 QPS。權衡點:寫入分散 vs 讀取聚合成本 vs 儲存放大,按實際流量動態調整。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
桶數寫入並發度讀取聚合開銷儲存空間適用場景
10低極低小日 PV < 10萬
100高低中日 PV 10萬-1000萬(推薦起步)
1000極高中大日 PV > 1000萬