在數(shù)據(jù)庫高并發(fā)場景下,死鎖大家或多或少都遇到過,但是很多時(shí)候沒有很重視,通過各種奇奇怪怪的方法避免了。最近使用Spark更新數(shù)據(jù)導(dǎo)致一次死鎖,特意學(xué)習(xí)一下鎖的問題。
1. 鎖分類體系
MySQL鎖可從多個(gè)維度進(jìn)行分類:
按粒度:全局鎖、表級鎖、頁級鎖、行級鎖
按屬性:共享鎖(S鎖)、排他鎖(X鎖)
按狀態(tài):意向鎖(IS/IX鎖)
按算法:記錄鎖、間隙鎖、臨鍵鎖
按并發(fā)策略:樂觀鎖、悲觀鎖
2. 主要的鎖
全局鎖:主要用于全庫邏輯備份場景,通過鎖定整個(gè)數(shù)據(jù)庫確保備份數(shù)據(jù)的一致性
表級鎖:可通過命令顯式加鎖,或隱式通過元數(shù)據(jù)鎖(MDL)實(shí)現(xiàn),常見于DDL操作或低并發(fā)查詢場景,通過鎖定整張表維護(hù)數(shù)據(jù)完整性
行級鎖:通過索引對特定數(shù)據(jù)行進(jìn)行加鎖(記錄鎖/間隙鎖/臨鍵鎖),特別適用于高并發(fā)OLTP系統(tǒng),通過細(xì)粒度鎖控制提升并發(fā)性能
樂觀鎖:基于數(shù)據(jù)版本號(Version)機(jī)制實(shí)現(xiàn),在讀多寫少場景中,通過版本號控制實(shí)現(xiàn)樂觀并發(fā)控制,避免鎖競爭
悲觀鎖:悲觀鎖是由數(shù)據(jù)庫自己實(shí)現(xiàn)了的,在寫操作頻繁場景中,通過鎖定資源防止并發(fā)沖突,確保數(shù)據(jù)一致性
3. 出現(xiàn)鎖的場景
在使用spark更新數(shù)據(jù)的時(shí)候,發(fā)現(xiàn)任務(wù)有報(bào)錯(cuò),報(bào)錯(cuò)消息是鎖相關(guān)的,特意留意了一下,大體意思是觸發(fā)了寫鎖,有一個(gè)task在寫數(shù)據(jù)的時(shí)候數(shù)據(jù)庫報(bào)錯(cuò)無法寫入。
出現(xiàn)的原因:因?yàn)閟park的task是并發(fā)執(zhí)行的,任務(wù)有多個(gè)并行度的情況下,寫入的task也是并發(fā)執(zhí)行的,意思就是同時(shí)又很多個(gè)寫入的事務(wù),而且寫入的操作是批量寫入,手動提交事務(wù),這就導(dǎo)致了有task任務(wù)提交的時(shí)候剛好有其他的task在操作同一條數(shù)據(jù)。
解決方案:最簡單的解決方案就是將spark中的操作數(shù)據(jù)庫前的結(jié)果mappartitions為一個(gè),避免并發(fā)更新;另外一種方案就是單條數(shù)據(jù)更新,自動提交事務(wù),這種情況下基本很難遇到鎖
最后還需要注意,更新語句的條件中的字段一定要有索引,否則全表掃描是很慢的。





暫無評論,快來評論吧!