雙十一大促是怎么做MySQL熱點數據高效更新的?
MySQL的熱點數據更新問題,一直都是行業內的一個難題,對于秒殺場景至關重要。一旦處理不好,就可能會導致數據庫被打垮。
通常來說,對于熱點問題,都是選擇使用Redis來抗,比如秒殺場景借助他的單線程高并發能力來做預扣減。
常規方案
但是,引入Redis又會帶來數據不一致的問題,進而會導致超賣和少賣,如果一定要在MySQL這個層面上,抗住高并發的熱點數據并發更新,有什么方案呢?拿庫存扣減舉例
1、庫存拆分,把一個大的庫存拆分成多個小庫存,拆分后,一次扣減動作就可以分散到不同的庫、表中進行,降低鎖粒度提升并發。
優點:實現較簡單
缺點:存在碎片問題、庫存調控不方便
2、請求合并,把多個庫存扣減請求,合并成一個,進行批量更新。
優點:簡單
缺點:適用于異步場景,或者經過分析后認為可以合并的場景
3、把update轉換成insert,直接插入一次占用記錄,然后異步統計剩余庫存,或者通過SQL統計流水方式計算剩余庫存。
優點:沒有update,無鎖沖突
缺點:insert時控制不好容易超賣、insert后剩余庫存不好統計
企業級方案
除了上面這三個方案外,重點介紹一個很多大公司在用的,扛了618/雙11等大促的高并發的秒殺的方案。
那就是改造MySQL
主要思路就是,針對于頻繁更新或秒殺類業務場景,大幅度優化對于熱點行數據的update操作的性能。當開啟熱點更新自動探測時,系統會自動探測是否有單行的熱點更新,如果有,則會讓大量的并發 update 排隊執行,以減少大量行鎖造成的并發性能下降。(另外我出了一份Java面試寶典,類似的方案有很多)
也就是說,他們改造了MySQL數據庫,讓同一個熱點行的更新語句,在執行層進行排隊。這樣的排隊相比update的排隊,要輕量級很多,因為他不需要自旋,不需要搶鎖。
這個方案的好處就是開發不需要做額外的事情,只需要開啟熱點檢測就行了。缺點就是改造MySQL數據庫有成本。不過現在很多云上數據庫都支持了。
效果如何?
比如阿里云的數據庫在做過改造之后,就做過單行熱點數據更新測試。
本示例中,分別使用兩個實例進行測試(高可用版和三節點企業版),規格碼為rds.mysql.st.v52和mysql.st.12xlarge.25。
- 實例版本:MySQL 5.7
- 實例規格:90核720GB(獨占物理機型)
- 實例系列:高可用版和三節點企業版
- 實例存儲類型:本地盤
- 實例模板:高性能參數模板
測試數據為單表,表內100行記錄。表結構如下:
CREATE TABLE `sbtest1`
(
`id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT
,`k` INT(10) UNSIGNED NOT NULL DEFAULT '0'
,`c` CHAR(120) NOT NULL DEFAULT ''
,`pad` CHAR(60) NOT NULL DEFAULT ''
,PRIMARY KEY (`id`)
,KEY `k_1` (`k`)
)
ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT
CHARSET=utf8 MAX_ROWS=1000000
對id=100的記錄進行并發更新,SQL如下:
UPDATE sbtest1 SET k=k+1 WHERE id=100
測試的Lua腳本如下:
pathtest = string.match(test,"(.*/)")
if pathtest then
dofile(pathtest .."common.lua")
else
require("common")
end
function thread_init(thread_id)
set_vars()
end
function event(thread_id)
local table_name
table_name ="sbtest".. sb_rand_uniform(1, oltp_tables_count)
rs = db_query("begin")
rs = db_query("update /*+commit_on_success rollback_on_fail target_affect_row(1) */ sbtest1 SET k=k+1 WHERE id=100")
rs =db_query("commit")
end
測試結果
實例類型 | 單行記錄更新峰值(TPS) |
RDS高可用版 | 1.2萬 |
RDS三節點企業版 | 3.1萬 |
參考資料:
騰訊云數據庫MySQL熱點更新:
https://cloud.tencent.com/document/product/236/63239
阿里云數據庫Inventory Hint:
https://www.alibabacloud.com/help/zh/apsaradb-for-rds/latest/inventory-hint