Mysql InnoDB 如何做數(shù)據(jù) 非停機遷移?
如何確保備份的庫歉备、表是同一邏輯時間點傅是?
比如,轉(zhuǎn)賬操作蕾羊,同時更新兩條數(shù)據(jù)喧笔,沒有使用事務(wù),一條成功后龟再,另一條成功前做備份书闸。
比如,余額表利凑,訂單表兩個表的操作浆劲。
- mysql 全局鎖。
- 全局視圖哀澈。(MVCC Read View)
Mysql 線程問題
Mysql 的連接池是否等價于線程池牌借?
Mysql建立連接后,同時提交多個sql日丹,是并行還是串行走哺?是否有數(shù)量限制?并發(fā)場景是否會導(dǎo)致等待超時哲虾?
Mysql 鎖問題
表鎖 MetaData Lock
除了對數(shù)據(jù)的表鎖外丙躏。還有對表結(jié)構(gòu)的表鎖。
在需要對線上環(huán)境表結(jié)構(gòu)進行調(diào)整時束凑,如何安全的執(zhí)行晒旅?
在一個正在執(zhí)行的事務(wù)中間(未提交前),執(zhí)行表結(jié)構(gòu)調(diào)整(加MDL寫鎖)汪诉。此時废恋,是否能夠加成功谈秫?如果成功,事務(wù)中后續(xù)對表的操作結(jié)果會如何鱼鼓?如果不能說明原因拟烫。
答:此時能夠加鎖成功(加鎖MDL寫鎖),但是會阻塞迄本,導(dǎo)致后續(xù)其他客戶端的讀操作也同步進入阻塞(因為存在MDL寫鎖)硕淑。這種情況與ReentrantReadWriteLock情況一致。
那么如何避免這個問題呢嘉赎?
- 避免使用長事務(wù)置媳。如果正在執(zhí)行的事務(wù)一直沒有提交,后續(xù)的MDL讀公条、寫操作一直阻塞拇囊,導(dǎo)致資源占用過多。
- 為MDL寫鎖增加時間限制靶橱,類似與tryLock(overTime)寥袭,超時自動釋放。
行鎖&事務(wù)的順序
假如現(xiàn)在有這么一個場景:用戶用賬戶余額買了一個商家的物品抓韩。
在這個場景中纠永,我們要做三個事情,1. 扣減用戶賬戶余額谒拴。2. 增加商家賬戶余額 3. 生成一條訂單記錄。
通常我們會使用事務(wù)來保證三個操作的原子性涉波。那么英上,是否有思考過到底如何才能達到性能最優(yōu)呢?
試想啤覆,我們?nèi)齻€操作中苍日,容易產(chǎn)生沖突(鎖等待)的地方可能只有操作2,增加商家賬戶余額窗声。比如相恃,商家在大促時,可能有N多的用戶同時購買笨觅,對用戶扣減拦耐,新增訂單這兩個操作來說,其實就不存在鎖等待問題见剩。因此杀糯,我們可以使用,1苍苞、3固翰、2或者3、1、2的順序骂际,先執(zhí)行兩個不存在等待的操作疗琉,哪怕在最后異步出現(xiàn)互斥,導(dǎo)致等待歉铝,也能確保對事務(wù)執(zhí)行時間影響最小盈简。
死鎖&死鎖檢測
還是以上邊 用戶購買商家物品為例,在大促時犯戏,有可能出現(xiàn)數(shù)據(jù)庫服務(wù)cpu使用率100%送火,每秒執(zhí)行事務(wù)數(shù)量還不到100的情況。這種情況其實就有可能是死鎖檢測導(dǎo)致的先匪。
死鎖的概念就不多描述了种吸。
那么什么是死鎖檢測呢?
我們知道解決死鎖的方式之一就是確保加鎖的順序一致呀非,避免互相等待坚俗。但是對于數(shù)據(jù)庫來說,很難去保證岸裙。所以Innodb 提供了死鎖檢測功能猖败,在對數(shù)據(jù)加鎖時,會發(fā)起死鎖檢測降允,如果存在沖突恩闻,則回滾一個事務(wù)確保其他事務(wù)執(zhí)行,這種機制能有效避免死鎖(Mysql死鎖等待超時時間為50s)所以默認也是開啟的剧董,但同時幢尚,這個檢測也會帶來額外的性能消耗。
如果翅楼,同一時間有1000個事務(wù)加鎖尉剩,那么檢測就需要判斷100W次,性能可想而知毅臊,并發(fā)帶來的成本急劇增加理茎。因此可能出現(xiàn)掛掉的情況。
那么應(yīng)該如何處理呢管嬉? 高級的直接改數(shù)據(jù)庫源碼皂林,控制存儲引擎并發(fā)數(shù)量。
InnoDB結(jié)構(gòu)
Buffer Pool 大小調(diào)到最大 是否等同于Redis宠蚂?
不同維度的東西不好拿來做比對式撼。
首先,Buffer Pool 作為緩存求厕,首要解決的問題是減少磁盤IO著隆,減少隨機寫磁盤的性能消耗扰楼。讀只是其附加價值。
相對于Redis本身就是為了高性能的讀取來說美浦,本質(zhì)就不一樣弦赖。而且Redis還對存儲結(jié)構(gòu)做了較多的設(shè)計,比如動態(tài)字符串浦辨,Hash表蹬竖,壓縮列表,跳表流酬。
不過總體而言币厕,Buffer Pool設(shè)置的足夠大,確實對于查詢性能來說會提升不少芽腾。
Buffer Pool & Change Buffer
Change Buffer 作為 Buffer Pool的一部分旦装,他的空間來自于Buffer Pool√希可以通過 參數(shù) innodb_change_buffer_max_size 來設(shè)置占比阴绢。
Change Buffer 的作用主要體現(xiàn)在,如果我們要對一個數(shù)據(jù)進行更新操作艰躺,假如這個數(shù)據(jù)不在Buffer Pool中那么可能會有兩種情況呻袭。一種是加載到Buffer Pool再執(zhí)行更新,另一種就是直接使用Change Buffer 將更新操作記錄在Change Buffer 中腺兴,后續(xù)由線程刷到磁盤中(過程怎么保證下一步再討論)左电。
什么時候可以使用Change Buffer
使用Change Buffer 的條件時非唯一索引,表中有唯一索引字段页响,在新增數(shù)據(jù)時券腔,需要校驗唯一索引字段是否重復(fù),此時就不能使用Change Buffer拘泞,需要去磁盤讀取并校驗。如果非唯一索引此時可以直接使用Change Buffer 提升性能(唯一索引還有必要用么枕扫?陪腌?)。
唯一索引的使用還是有必要的烟瞧,在一些場景中诗鸭,新增完數(shù)據(jù)可能會立刻需要查詢(更新當(dāng)前頁面),這種時候参滴,如果能夠使用唯一索引還是使用唯一索引比較好强岸。非唯一索引雖然會將更新動作直接記錄到Change Buffer 中,但是 在執(zhí)行查詢該數(shù)據(jù)時砾赔,會觸發(fā)Merge操作蝌箍,等同于Buffer Pool 的刷臟青灼。因此,這種情況妓盲,反而多了維護Change Buffer的資源消耗(有點想干掉Change Buffer 了T硬Α!C醭摹)弹沽。當(dāng)然對于,日志筋粗、操作記錄這種不需要立刻查詢的場景還是非常友好的策橘。
Change Buffer & Redo Log
一個更新操作在寫入Change Buffer 后仍然需要在事務(wù)提交時,寫Redo Log娜亿。因此持久化操作還是靠Redo Log保證丽已。我們知道,Redo Log雖然保證了持久化暇唾,但是一般用于故障恢復(fù)促脉。對于寫磁盤數(shù)據(jù)頁還是由后臺線程對Buffer Pool執(zhí)行刷臟來完成。那么策州,Change Buffer 中的數(shù)據(jù) 何時才會"刷臟"寫入Buffer Pool呢瘸味?有以下幾個條件:
- 內(nèi)存空間不足時
- 后臺線程定期執(zhí)行
- Redo Log寫滿時
- 數(shù)據(jù)庫正常關(guān)閉時
- 訪問這個數(shù)據(jù)頁時
Buffer Poll 持久化
Buffer Pool 數(shù)據(jù)需求持久化到磁盤。時機有四種:
- 內(nèi)存空間不足時
- Redo Log寫滿時
- 后臺線程定期執(zhí)行
- 數(shù)據(jù)庫正常關(guān)閉時
這四種够挂,前兩種旁仿,會對mysql性能產(chǎn)生影響。
內(nèi)存不足時(Buffer Pool沒有額外的內(nèi)存加載要操作的數(shù)據(jù))孽糖,需要淘汰一些數(shù)據(jù)(內(nèi)存淘汰)枯冈,再去加載要操作的數(shù)據(jù),此時會抖一下办悟,拖慢一些速度尘奏。
Redo Log寫滿時,影響就比較大病蛉,因為無法進行寫操作了炫加,必須要執(zhí)行刷臟了(磁盤IO),因此我們要避免Redo Log寫滿這種操作铺然。那如果要避免俗孝,就需要提升 3、4情況的刷臟效率魄健。而刷臟效率設(shè)置 通過參數(shù) innodb_io_capacity 可以靈活的配置赋铝,這個參數(shù)其實就是告訴mysql我這臺服務(wù)器性能怎么樣,你按照這個設(shè)置來控制刷臟速度沽瘦。如果一臺高性能機器革骨,innodb_io_capacity 設(shè)置了一個很低的值农尖,那么Mysql刷臟效率也會很低。
另外 還需要再提一個參數(shù)苛蒲,innodb_flush_neighbors卤橄,這個參數(shù)控制刷臟時是否連帶著旁邊的臟頁也給刷新掉(連坐), 8.0 以后這個配置默認是關(guān)閉的臂外。因此8.0以前窟扑,一次刷臟有可能引發(fā)一場血案。
Mysql 索引問題
為什么有時候會選錯索引
比如 表 t 有 id漏健、a嚎货、b兩個字段,a蔫浆、b字段均有索引殖属。 插入10W條數(shù)據(jù) (1,1,1)(2,2,2)...
查詢語句: select * from t where a > 0 and a < 1000 and b > 1000 and b < 5000 order by b;
此時 明顯走 a 索引會 性能最佳,但是 explain 時發(fā)現(xiàn)瓦盛,選擇了 b 索引 原因就是 order by 字段導(dǎo)致 優(yōu)化器認為洗显,排序的性能消耗 要比 掃描更多行數(shù)據(jù) 代價更高。
為什么正確使用了索引還是會存在慢查
表被鎖住原环,導(dǎo)致查詢等待鎖釋放出現(xiàn)慢查挠唆。
RR隔離級別下,MVCC版本鏈太長嘱吗。開啟事務(wù)后玄组,對數(shù)據(jù)查詢之前存在大量的修改變更。