日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > 数据库 >内容正文

数据库

研发协同平台数据库死锁处理及改进

發(fā)布時(shí)間:2023/12/4 数据库 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 研发协同平台数据库死锁处理及改进 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

源寶導(dǎo)讀:數(shù)據(jù)庫(kù)死鎖是高并發(fā)復(fù)雜系統(tǒng)都要面臨課題,處理死鎖問(wèn)題沒(méi)有一招制敵的標(biāo)準(zhǔn)方法,需要具體問(wèn)題具體分析。本文將基于研發(fā)協(xié)同平臺(tái)遇到的死鎖案例,介紹從監(jiān)控、分析到處理的完整過(guò)程和經(jīng)驗(yàn)總結(jié)。

一、背景

? ? ? 研發(fā)協(xié)同平臺(tái)使用的技術(shù)棧大體是.NET Core + EFCore + SQLServer, 周邊還有一些第三方組件, 如Redis、Jenkins、Gitlab、Sonar。整體技術(shù)架構(gòu)又分為前臺(tái)服務(wù)(rdc_service)、調(diào)度服務(wù)(rdc_service)、更新服務(wù)(rdc_upgrade)。其中更新服務(wù)面向所有終端用戶的服務(wù)器,用于客戶產(chǎn)品更新;調(diào)度服務(wù)作為后臺(tái)作業(yè),定時(shí)對(duì)客戶的服務(wù)器進(jìn)行巡檢,發(fā)現(xiàn)異常服務(wù)器時(shí)通知客戶;客戶和客戶服務(wù)器的數(shù)量數(shù)以萬(wàn)計(jì),接口請(qǐng)求量較大,更新服務(wù)和調(diào)度服務(wù)都是對(duì)客戶及其服務(wù)器數(shù)據(jù)操作,兩者之間難免會(huì)有數(shù)據(jù)上的交際,這樣一來(lái),死鎖就有了可乘之機(jī),本文重點(diǎn)介紹研發(fā)協(xié)同平臺(tái)對(duì)死鎖的監(jiān)控和解決方案。

二、死鎖監(jiān)控

? ? 在早期SQL Server中,通過(guò)跟蹤標(biāo)志1204/1222,可以在數(shù)據(jù)庫(kù)錯(cuò)誤日志中捕獲的死鎖信息。跟蹤標(biāo)志1204會(huì)報(bào)告由死鎖所涉及的每個(gè)節(jié)點(diǎn)設(shè)置格式的死鎖信息。跟蹤標(biāo)志 1222 會(huì)設(shè)置死鎖信息的格式,順序?yàn)橄劝催M(jìn)程,然后按資源。可以同時(shí)啟用這兩個(gè)跟蹤標(biāo)志,以獲取同一個(gè)死鎖事件的兩種表示形式。

? ? 下面的示例顯示啟用跟蹤標(biāo)志 1204 時(shí)的輸出。在此示例中,節(jié)點(diǎn) 1 中的表為沒(méi)有索引的堆,節(jié)點(diǎn) 2 中的表為具有非聚集索引的堆。節(jié)點(diǎn) 2 中索引鍵在發(fā)生死鎖時(shí)正在進(jìn)行更新。

? ? 在工作負(fù)載密集型系統(tǒng)上使用跟蹤標(biāo)志1204和1222可能會(huì)導(dǎo)致性能,為了解決這一問(wèn)題,自 SQL Server 2012 (11.x) 起,SQL Server提供了xml_deadlock_report 擴(kuò)展事件 (xEvent),來(lái)幫助研發(fā)人員更加便捷高效的監(jiān)測(cè)及排查死鎖。下圖展示了在擴(kuò)展事件中可以捕獲的deadlock相關(guān)事件:

? ? 在擴(kuò)展事件啟用后,當(dāng)數(shù)據(jù)庫(kù)發(fā)生死鎖時(shí),SQL Server會(huì)自動(dòng)將導(dǎo)致死鎖的相關(guān)會(huì)話數(shù)據(jù),以XML的形式保存下來(lái),下圖展示了研發(fā)協(xié)同平臺(tái)近期監(jiān)控到的死鎖記錄:

三、死鎖分析

? ? 隨機(jī)查看幾個(gè)死鎖日志,所有的記錄均屬于同一場(chǎng)景:進(jìn)程1持有表CustomerServer行A的排他(X)鎖,需要申請(qǐng)表Customer行B的共享(S)鎖,而進(jìn)程2剛好持有Customer行B的排他(X)鎖,且正在向CustomerServer表行A申請(qǐng)更新(U)鎖。眾所周知,排他(X)鎖和更新(U)鎖完全互斥,故兩個(gè)進(jìn)程陷入了相互等待的僵局。下圖1展示了死鎖發(fā)生時(shí)兩個(gè)進(jìn)程的相關(guān)數(shù)據(jù),圖2則顯示了雙方在資源上面的爭(zhēng)用情況。

? ? 除非某個(gè)外部進(jìn)程斷開(kāi)死鎖,否則死鎖中的兩個(gè)事務(wù)都將無(wú)限期等待下去。SQL Server 數(shù)據(jù)庫(kù)引擎死鎖監(jiān)視器定期檢查陷入死鎖的任務(wù)。如果監(jiān)視器檢測(cè)到循環(huán)依賴關(guān)系,將選擇其中一個(gè)任務(wù)作為犧牲品,然后終止其事務(wù)并提示錯(cuò)誤。其他任務(wù)就可以完成其事務(wù)。

? ? 另外需要注意的是:死鎖經(jīng)常與正常阻塞混淆。事務(wù)請(qǐng)求的資源被其他事務(wù)鎖定時(shí),發(fā)出請(qǐng)求的事務(wù)一直等到該鎖被釋放。除非設(shè)置了 LOCK_TIMEOUT,否則 SQL Server 事務(wù)不會(huì)超時(shí)。擁有鎖的事務(wù)完成并釋放鎖后,發(fā)出請(qǐng)求的事務(wù)將獲取鎖并繼續(xù)執(zhí)行,所以該事務(wù)是被阻塞,而不是陷入了死鎖。

? ? 默認(rèn)情況下,SQL Server 數(shù)據(jù)庫(kù)引擎選擇運(yùn)行回滾開(kāi)銷最小的事務(wù)的會(huì)話作為死鎖犧牲品。此外,用戶也可以使用 SET DEADLOCK_PRIORITY 語(yǔ)句指定死鎖情況下會(huì)話的優(yōu)先級(jí)。

3.1、死鎖業(yè)務(wù)場(chǎng)景

? ? 進(jìn)一步分析死鎖報(bào)告,可以直觀的看到涉及死鎖的兩個(gè)進(jìn)程來(lái)至3臺(tái)服務(wù)器,這里我們假定是服務(wù)器A、B、C。3臺(tái)服務(wù)器分別屬于進(jìn)程1調(diào)度服務(wù)(服務(wù)器A)、進(jìn)程2更新服務(wù)(服務(wù)器B、C)。調(diào)度服務(wù)是一組后臺(tái)作業(yè)任務(wù)的集合,其中有同時(shí)訪問(wèn)表Customer\CustomerServer的任務(wù)只有一個(gè),即客戶服務(wù)器狀態(tài)同步作業(yè):掃描系統(tǒng)中所有客戶的服務(wù)器,只要客戶服務(wù)器未按照約定上報(bào)信息,則認(rèn)為其離線,將離線狀態(tài)同步至客戶表(Customer)和客戶服務(wù)器表(CustomerServer),并給客戶對(duì)應(yīng)的負(fù)責(zé)人發(fā)送郵件。該作業(yè)每分鐘執(zhí)行一次,每次作業(yè)任務(wù)耗時(shí)50s,執(zhí)行時(shí)間過(guò)長(zhǎng)可能是導(dǎo)致頻繁死鎖的原因之一。

? ? 通過(guò)死鎖報(bào)告中的服務(wù)器信息可以快速的定位到進(jìn)程1的業(yè)務(wù)場(chǎng)景,那么進(jìn)程2則需要其他工具來(lái)幫助我們定位。進(jìn)程2更新服務(wù)是一組API集合,供用戶更新客戶環(huán)境的相關(guān)業(yè)務(wù),其中涉及Customer\CustomerServer兩張表的操作非常多,如果心跳接口、注冊(cè)客戶信息接口。到這一步,我們所知道的信息如下:

? ? 死鎖報(bào)告的中的SQL腳本是由EFCore生成的,表面上看不出來(lái)進(jìn)程2到底是哪一個(gè)接口。這里我們借助SkyWalking 的端點(diǎn)埋點(diǎn)數(shù)據(jù),下圖1是所有心跳接口的錯(cuò)誤記錄,時(shí)間點(diǎn)與死鎖日志中的時(shí)間完全匹配,沒(méi)有例外;圖2是錯(cuò)誤詳情,其中的事務(wù)進(jìn)程Id和死鎖犧牲對(duì)象與死鎖中報(bào)告完全匹配。

3.2、主外鍵對(duì)執(zhí)行計(jì)劃的影響

? ? SQL Server 數(shù)據(jù)庫(kù)引擎提供了訪問(wèn)查詢執(zhí)行計(jì)劃的運(yùn)行時(shí)信息。出現(xiàn)性能問(wèn)題時(shí),最重要的操作之一是準(zhǔn)確了解正在執(zhí)行的工作負(fù)載以及如何驅(qū)動(dòng)使用資源。為此,訪問(wèn)實(shí)際執(zhí)行計(jì)劃將很重要。這里的更新服務(wù)心跳接口,只有對(duì)客戶服務(wù)器表(CustomerServer)訪問(wèn),并沒(méi)有直接對(duì)Customer表進(jìn)行訪問(wèn),通過(guò)SkyWalking的端點(diǎn)數(shù)據(jù),以及死鎖報(bào)告中的SQL腳本,可以拿到心跳接口的估算執(zhí)行計(jì)劃。盡管業(yè)務(wù)場(chǎng)景只需要更新一個(gè)Status字段,但由于未開(kāi)啟EFCore的模型跟蹤(ChangeTracker),EFCore生成的SQL腳本顯示的更新了除主鍵以外所有字段。其中[CustomerId]和[PluginId]正好是外鍵字段,分別來(lái)自Customer和Plugin表,為了保證主外鍵的約束,一條簡(jiǎn)單的單表update操作,將涉及到3張表的資源訪問(wèn)。下圖展示了心跳接口在SQL Server中的執(zhí)行計(jì)劃:

? ? 如果開(kāi)啟的模型跟蹤,或者手動(dòng)寫(xiě)編寫(xiě)SQL,按需更新字段,上面的死鎖將不會(huì)存在,下圖展示了單表單字段場(chǎng)景下的執(zhí)行計(jì)劃:

四、業(yè)務(wù)改進(jìn)

? ? 我們通過(guò)簡(jiǎn)單的SQL改造,在不影響業(yè)務(wù)的情況下,將進(jìn)程2的SQL資源訪問(wèn)由3張表降低至單表操作,這里不敢保證說(shuō)已經(jīng)消除了死鎖,但至少將死鎖降低到一個(gè)可以忽略不計(jì)的范圍。為了保險(xiǎn)起見(jiàn),這里繼續(xù)對(duì)進(jìn)程1(調(diào)度服務(wù)Job)優(yōu)化。

? ? 上述提到客戶服務(wù)器狀態(tài)同步作業(yè)每分鐘執(zhí)行一次,每次作業(yè)任務(wù)耗時(shí)50s,這里的耗時(shí)有點(diǎn)過(guò)長(zhǎng),Job在全天24小時(shí)內(nèi),有83%(50s/60s)的時(shí)間處于作業(yè)中,為了保證原子性,這里采用是的方法級(jí)事務(wù),事務(wù)鎖定的范圍是整個(gè)作業(yè)周期,即時(shí)50s,并且不論客戶的服務(wù)器狀態(tài)是否發(fā)生改變,這里都會(huì)修改數(shù)據(jù),下面是Job相關(guān)的代碼:

? ? 在不改變業(yè)務(wù)場(chǎng)景的基礎(chǔ)上,我們對(duì)作業(yè)Job的執(zhí)行策略做了微調(diào):

  • 修改正式環(huán)境時(shí)間間隔為10分鐘

  • 更新方式調(diào)整為更新指定字段

  • 每個(gè)客戶單獨(dú)開(kāi)啟事務(wù)處理

  • 狀態(tài)未發(fā)生變化時(shí)不修改數(shù)據(jù)

? ? 客戶環(huán)境的服務(wù)器比較復(fù)雜,通常來(lái)說(shuō)偶爾的抖動(dòng)屬于正常現(xiàn)象,心跳的有效期都是3-5分鐘,每分鐘去檢測(cè)一次狀態(tài)有點(diǎn)多余,這里將作業(yè)時(shí)間由每分鐘調(diào)整10分鐘,可以有效降低后臺(tái)作業(yè)與前端API接口之間的資源沖突;更新方式采用EFCore的模型跟蹤(ChangeTracker),按需更新,這里既然只檢測(cè)狀態(tài)變更,就只需要更改狀態(tài),減少修改的字段,可以避免由主外鍵引起的額外共享鎖申請(qǐng);第3條和第4條都是為了降低事務(wù)的范圍,這里的事務(wù)原子性控制到單個(gè)客戶明顯比全局性價(jià)比高,沒(méi)必要因?yàn)橐粋€(gè)客戶的失敗,導(dǎo)致整個(gè)作業(yè)失敗,當(dāng)客戶服務(wù)器狀態(tài)沒(méi)有發(fā)生變化時(shí),對(duì)當(dāng)前客戶的處理應(yīng)直接跳過(guò),減少修改次數(shù);通過(guò)上面4條優(yōu)化策略,任務(wù)的作業(yè)時(shí)間由之前的50s降低為15s,且不會(huì)對(duì)業(yè)務(wù)產(chǎn)生影響,死鎖也隨時(shí)消除。

五、寫(xiě)在最后

? ? 盡管死鎖不能完全避免,但遵守特定的編碼習(xí)慣可以將發(fā)生死鎖的機(jī)會(huì)降至最低。在這里分享幾點(diǎn)研發(fā)協(xié)同平臺(tái)團(tuán)隊(duì)的開(kāi)發(fā)規(guī)范,有助于大家在日常開(kāi)發(fā)中避免死鎖和提高數(shù)據(jù)庫(kù)性能:

  • 縮小事務(wù)的范圍,提前計(jì)算出需要更新的數(shù)據(jù),避免在事務(wù)中做額外的業(yè)務(wù)邏輯計(jì)算;

  • 按需更新行字段,EFCore類似的ORM框架,帶來(lái)了開(kāi)發(fā)上的便捷,同時(shí)也會(huì)帶來(lái)性能上的隱患;

  • 外鍵字段加索引,外鍵字段索引可以顯著降低查詢或更新時(shí),降低對(duì)數(shù)據(jù)資源鎖定的范圍;

  • 定期優(yōu)化慢SQL ,慢SQL意味著需研發(fā)協(xié)同平臺(tái)持續(xù)交付2.0架構(gòu)演進(jìn)要讀取更多索引頁(yè)或者數(shù)據(jù)頁(yè),加大資源鎖定的范圍;

作者簡(jiǎn)介

馮同學(xué):?研發(fā)工程師,目前負(fù)責(zé)研發(fā)協(xié)同平臺(tái)的設(shè)計(jì)與開(kāi)發(fā)工作。

也許您還想看

研發(fā)協(xié)同平臺(tái)持續(xù)集成Jenkins作業(yè)設(shè)計(jì)演進(jìn)

研發(fā)協(xié)同平臺(tái)持續(xù)交付之代理服務(wù)實(shí)踐

研發(fā)協(xié)同平臺(tái)持續(xù)集成2.0架構(gòu)演進(jìn)

研發(fā)協(xié)同平臺(tái)持續(xù)交付2.0架構(gòu)演進(jìn)

總結(jié)

以上是生活随笔為你收集整理的研发协同平台数据库死锁处理及改进的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。