這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)碛嘘P(guān)SQL Server中怎么實(shí)現(xiàn)一個(gè)自旋鎖,文章內(nèi)容豐富且以專業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
“專業(yè)、務(wù)實(shí)、高效、創(chuàng)新、把客戶的事當(dāng)成自己的事”是我們每一個(gè)人一直以來堅(jiān)持追求的企業(yè)文化。 創(chuàng)新互聯(lián)建站是您可以信賴的網(wǎng)站建設(shè)服務(wù)商、專業(yè)的互聯(lián)網(wǎng)服務(wù)提供商! 專注于成都做網(wǎng)站、網(wǎng)站建設(shè)、軟件開發(fā)、設(shè)計(jì)服務(wù)業(yè)務(wù)。我們始終堅(jiān)持以客戶需求為導(dǎo)向,結(jié)合用戶體驗(yàn)與視覺傳達(dá),提供有針對性的項(xiàng)目解決方案,提供專業(yè)性的建議,創(chuàng)新互聯(lián)建站將不斷地超越自我,追逐市場,引領(lǐng)市場!
為什么我們需要自旋鎖?
用閂鎖同步多個(gè)線程間數(shù)據(jù)結(jié)構(gòu)訪問,在每個(gè)共享數(shù)據(jù)結(jié)構(gòu)前都放置一個(gè)閂鎖沒有意義的。閂鎖與此緊密關(guān)聯(lián):當(dāng)你不能獲得閂鎖(因?yàn)槠渌艘呀?jīng)有一個(gè)不兼容的閂鎖拿到),查詢就會(huì)強(qiáng)制等待,并進(jìn)入掛起(SUSPENDED)狀態(tài)。查詢在掛起狀態(tài)等待直到可以拿到閂鎖,然后就會(huì)進(jìn)入可執(zhí)行(RUNNABLE)狀態(tài)。對于查詢執(zhí)行只要沒有可用的CPU,查詢就一直在可執(zhí)行(RUNNABLE)狀態(tài)。一旦CPU有空閑,查詢會(huì)進(jìn)入運(yùn)行(RUNNING)狀態(tài),最后成功獲取到閂鎖,用它來保護(hù)訪問的共享數(shù)據(jù)結(jié)構(gòu)。下圖展示了SQLOS對協(xié)調(diào)線程調(diào)度實(shí)現(xiàn)的狀態(tài)機(jī)。
因?yàn)樘嚓P(guān)聯(lián)的閂鎖,對“忙碌”數(shù)據(jù)結(jié)構(gòu)使用閂鎖保護(hù)沒有意義。因此SQL Server實(shí)現(xiàn)所謂
自旋鎖(Spinlocks)。自旋鎖就像一個(gè)閂鎖,存儲(chǔ)引擎使用的一個(gè)輕量級(jí)同步對象,用來同步對共享數(shù)據(jù)結(jié)構(gòu)線程訪問。和閂鎖的主要區(qū)別是你積極等待自旋鎖——不離開CPU。在自旋鎖上的“等待”總會(huì)發(fā)生在運(yùn)行(RUNNING)狀態(tài)的CPU。在你閉合循環(huán)里旋轉(zhuǎn)直到獲得自旋鎖。這就是所謂的忙碌等待(busy wait)。自旋鎖的最大優(yōu)點(diǎn)是當(dāng)查詢在自旋鎖上等待時(shí),不會(huì)涉及到上下文切換。另一方面忙碌等待浪費(fèi)CPU周期,其他查詢也許能對它們更有效的使用。
為了避免太多的CPU周期浪費(fèi),SQL Server 2008 R2及后續(xù)版本實(shí)現(xiàn)所謂的指數(shù)補(bǔ)償機(jī)制(exponential backoff mechanism),那里在CPU上一些時(shí)間的休眠后,線程停止旋轉(zhuǎn)。在線程進(jìn)入休眠期間,增加了嘗試獲得自旋鎖的超時(shí)。這個(gè)行為可以降低對CPU性能的影響。
(補(bǔ)充說明:Spinlock中文可以稱為自旋鎖。它是一個(gè)輕量級(jí)的,用戶態(tài)的同步對象,和critical section類似,但是粒度比前者小多了。它主要用來保護(hù)某些特定的內(nèi)存對象的多線程并發(fā)訪問。Spinlock是排他性的。一次只能一個(gè)線程擁有。
Spinlock的設(shè)計(jì)目標(biāo)是非??旌透咝?。Spinlock內(nèi)部如何工作呢?它首先試圖獲得某個(gè)對象的鎖,如果目標(biāo)被其它線程占有,就在那里輪詢(spin)一定時(shí)間。如果還得不到鎖,就sleep一小會(huì),然后繼續(xù)spin。反復(fù)這個(gè)過程直到得到對象的占有權(quán)。)
自旋鎖與故障排除對自旋鎖故障排除的主要DMV是 sys.dm_os_spinlock_stats。這個(gè)DMV里返回的每一行都代表SQL Server里的一個(gè)自旋鎖。SQL Server 2014實(shí)現(xiàn)了262個(gè)不同自旋鎖。我們來詳細(xì)看下這個(gè)DMV里的各個(gè)列:
name:自旋鎖名稱collision:當(dāng)嘗試訪問保護(hù)的數(shù)據(jù)結(jié)構(gòu)時(shí),被自旋鎖阻塞的線程次數(shù)spins:在循環(huán)里嘗試獲得自旋鎖的自旋鎖線程次數(shù)spins_per_collision:旋轉(zhuǎn)和碰撞之間的比率sleep_time:因?yàn)橥吮芫€程休眠時(shí)間backoffs:為了其他線程在CPU上繼續(xù),線程退避次數(shù)在這個(gè)DMV里最重要的列是backoffs,對于特定的自旋鎖類型,這列告訴你退避發(fā)生頻率。高頻率的退避會(huì)屈服于CPU消耗引起SQL Server里的自旋鎖競爭(Spinlock Contention)。我就見過一個(gè)32核的SQL Server服務(wù)器,CPU運(yùn)行在100%而不進(jìn)行任何工作——典型的自旋鎖競爭癥狀。
對自旋鎖問題進(jìn)行故障排除你可以使用擴(kuò)展事件提供的sqlos.spinlock_backoff。當(dāng)退避(backoff)發(fā)生時(shí),就會(huì)觸發(fā)這個(gè)擴(kuò)展事件。如果你捕獲了這個(gè)事件,你還要保證你使用非常好的選擇性謂語,因?yàn)樵赟QL Server里退避會(huì)經(jīng)常發(fā)生。一個(gè)好的謂語可以是特定的自旋鎖類型,通過剛才提到的DMV你已經(jīng)看到。下列代碼給你展示了如何創(chuàng)建這樣的擴(kuò)展事件會(huì)話。
-- Retrieve the type value for the LOCK_HASH spinlock. -- That value is used by the next XEvent session SELECT * FROM sys.dm_xe_map_values WHERE name = 'spinlock_types' AND map_value = 'LOCK_HASH' GO -- Tracks the spinlock_backoff event CREATE EVENT SESSION SpinlockContention ON SERVER ADD EVENT sqlos.spinlock_backoff( ACTION ( package0.callstack ) WHERE ( [type] = 129 -- <<< Value from the previous query )) ADD TARGET package0.histogram ( SET source = 'package0.callstack', source_type = 1 ) GO
從代碼里可以看到,這里我在調(diào)用堆棧(callstack)上使用了直方圖(histogram)目標(biāo)來bucktize。因此對于特定的自旋鎖,你可以可能到SQL Serve里生成的最高退避(backoffs)代碼路徑。你甚至可以通過啟用3656跟蹤標(biāo)記(trace flag)來標(biāo)識(shí)調(diào)用堆棧。這里你可以看到來自這個(gè)擴(kuò)展會(huì)話的輸出:
sqldk.dll!XeSosPkg::spinlock_backoff::Publish+0x138sqldk.dll!SpinlockBase::Sleep+0xc5sqlmin.dll!Spinlock<129,7,1>::SpinToAcquireWithExponentialBackoff+0x169sqlmin.dll!lck_lockInternal+0x841sqlmin.dll!XactWorkspaceImp::GetSharedDBLockFromLockManager+0x18dsqlmin.dll!XactWorkspaceImp::GetDBLockLocal+0x15bsqlmin.dll!XactWorkspaceImp::GetDBLock+0x5asqlmin.dll!lockdb+0x4a sqlmin.dll!DBMgr::OpenDB+0x1ecsqlmin.dll!sqlusedb+0xebsqllang.dll!usedb+0xb3sqllang.dll!LoginUseDbHelper::UseByMDDatabaseId+0x93sqllang.dll!LoginUseDbHelper::FDetermineSessionDb+0x3e1sqllang.dll!FRedoLoginImpl+0xa1bsqllang.dll!FRedoLogin+0x1c1sqllang.dll!process_request+0x3ecsqllang.dll!process_commands+0x4a3sqldk.dll!SOS_Task::Param::Execute+0x21esqldk.dll!SOS_Scheduler::RunTask+0xa8sqldk.dll!SOS_Scheduler::ProcessTasks+0x279sqldk.dll!SchedulerManager::WorkerEntryPoint+0x24csqldk.dll!SystemThread::RunWorker+0x8fsqldk.dll!SystemThreadDispatcher::ProcessWorker+0x3absqldk.dll!SchedulerManager::ThreadEntryPoint+0x226
使用提供調(diào)用堆棧,不難找出自旋鎖競爭發(fā)生的地方。在那個(gè)指定的笤俑堆棧里競爭發(fā)生在LOCK_HASH自旋鎖類型里,它是保護(hù)鎖管理器的哈希表。每次在鎖管理器里加鎖或解鎖被執(zhí)行時(shí),自旋鎖必須在對應(yīng)的哈希桶里獲得。如你所見,在調(diào)用堆棧里,當(dāng)從XactWorkspacelmp類調(diào)用GetSharedDBLockFromLockManager函數(shù)時(shí),自旋鎖被獲得。這表示當(dāng)競爭到數(shù)據(jù)庫時(shí),共享數(shù)據(jù)庫鎖被嘗試獲取。最后在用很高的退避(backoffs)的LOCK_HASH自旋鎖里,這屈服于自旋鎖競爭。
上述就是小編為大家分享的SQL Server中怎么實(shí)現(xiàn)一個(gè)自旋鎖了,如果剛好有類似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。
網(wǎng)頁題目:SQLServer中怎么實(shí)現(xiàn)一個(gè)自旋鎖
標(biāo)題鏈接:http://m.rwnh.cn/article34/gspepe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供、軟件開發(fā)、ChatGPT、域名注冊、關(guān)鍵詞優(yōu)化、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)