六月婷婷AV,国产偷窥猎奇福利二区,日韩三级片。,好吊色网站,日韩成人中文在线视频,国产亚洲午夜啪啪,亚洲欧美另类国产精品,国产成人av1,任你艹在线观看

TDengine 資深研發(fā)分享解決思路,長(zhǎng)查詢不再成為系統(tǒng)性能瓶頸!

長(zhǎng)查詢問題指的是在數(shù)據(jù)庫寫入和查詢并存的日常應(yīng)用場(chǎng)景中,存在處理數(shù)據(jù)量大且耗時(shí)很長(zhǎng)的查詢長(zhǎng)時(shí)間占用系統(tǒng)資源,導(dǎo)致寫入可能被阻塞的問題。有時(shí),查詢代碼對(duì)于資源釋放函數(shù)調(diào)用的遺忘也可能以長(zhǎng)查詢問題的形式表現(xiàn)出來。如何在數(shù)據(jù)寫入不被阻塞同時(shí),保證長(zhǎng)查詢的正確進(jìn)行是一個(gè)具有挑戰(zhàn)性的問題。

盡管在絕大多數(shù)時(shí)序數(shù)據(jù)使用場(chǎng)景下,用戶不太可能遇到這個(gè)問題,但一旦出現(xiàn),也會(huì)讓人頭疼不已。為了解決這一問題,TDengine 研發(fā)團(tuán)隊(duì)一直致力于不斷優(yōu)化系統(tǒng),提高查詢性能和響應(yīng)速度。本文將深入剖析這一挑戰(zhàn),并探討如何應(yīng)對(duì)和解決長(zhǎng)查詢問題,以提升 TDengine 在復(fù)雜查詢場(chǎng)景下的表現(xiàn)。

在分析長(zhǎng)查詢問題之前,我們首先需要為大家普及一下 TDengine 的寫入/查詢并發(fā)機(jī)制。

數(shù)據(jù)寫入/讀取機(jī)制

Vnode 是 TDengine 中存儲(chǔ)和查詢數(shù)據(jù)的基本單元,這里主要介紹 Vnode 的寫入/讀取及并發(fā)機(jī)制。

數(shù)據(jù)寫入機(jī)制

TDengine 資深研發(fā)分享解決思路,長(zhǎng)查詢不再成為系統(tǒng)性能瓶頸! - TDengine Database 時(shí)序數(shù)據(jù)庫

  • 每個(gè) Vnode 在創(chuàng)建時(shí)都會(huì)根據(jù) DB 參數(shù)分配一定數(shù)量的內(nèi)存
  • 這些內(nèi)存在 Vnode 中被分為三個(gè)內(nèi)存塊
  • 每個(gè) Vnode 只有一個(gè)線程寫入
  • Vnode 在寫入時(shí),會(huì)從內(nèi)存塊的空閑列表 (free list) 中分配一個(gè)內(nèi)存塊(mem),供數(shù)據(jù)寫入使用
  • 當(dāng)內(nèi)存塊中數(shù)據(jù)寫入超過一定量后,開始落盤(imem),同時(shí)分配一個(gè)新的內(nèi)存塊供數(shù)據(jù)寫入使用
  • 當(dāng)內(nèi)存塊全部用完,沒有空閑內(nèi)存塊時(shí),寫入會(huì)被阻塞,一直等待有內(nèi)存塊釋放出來

數(shù)據(jù)查詢機(jī)制

  • 查詢分多批次進(jìn)行,每次返回部分?jǐn)?shù)據(jù),然后該查詢等待下一次拉取數(shù)據(jù)的請(qǐng)求
  • 查詢結(jié)果是內(nèi)存(mem/imem)數(shù)據(jù)和硬盤數(shù)據(jù)合并的結(jié)果
  • 查詢開始時(shí),會(huì)先 take snapshot,引用(ref) mem/imem 以及硬盤文件
  • 查詢結(jié)束時(shí),unref mem/imem,如果內(nèi)存塊的引用計(jì)數(shù)變?yōu)?0,則內(nèi)存塊被回收到空閑鏈表中
TDengine 資深研發(fā)分享解決思路,長(zhǎng)查詢不再成為系統(tǒng)性能瓶頸! - TDengine Database 時(shí)序數(shù)據(jù)庫

長(zhǎng)查詢問題

時(shí)序數(shù)據(jù)絕大部分查詢持續(xù)時(shí)間都比較短,如查詢表/超級(jí)表的最后一條記錄、做 count 或 sum 類的聚合查詢等。這類查詢持續(xù)時(shí)間較短,對(duì)于 mem/imem 的占用時(shí)間也較短,查詢很快會(huì)釋放 MemTable 供 Vnode 回收再次利用,從而不影響寫入的進(jìn)行。但是,如果存在一個(gè)持續(xù)時(shí)間很長(zhǎng)的查詢,如超過 1 小時(shí)或 1 天的查詢,這時(shí)候就會(huì)出現(xiàn)此類問題。當(dāng)然,只有一個(gè)長(zhǎng)查詢的情況下,問題也不大,因?yàn)?Vnode 的內(nèi)存池默認(rèn)被分成了 3 個(gè)內(nèi)存塊,一個(gè)長(zhǎng)查詢最多占用兩個(gè)內(nèi)存塊,還剩余一個(gè)內(nèi)存塊可以用來進(jìn)行持續(xù)寫入。但是如果存在多個(gè)長(zhǎng)查詢,Vnode 中的所有內(nèi)存塊都可能被長(zhǎng)時(shí)間占用,無法進(jìn)行回收,從而導(dǎo)致寫入停止的情況。

另外,如果查詢部分的代碼存在 BUG,忘記關(guān)閉查詢句柄,也會(huì)導(dǎo)致 mem/imem 被長(zhǎng)期占用,阻塞寫入。這個(gè)問題在 TDengine 訂閱和流計(jì)算功能中曾經(jīng)就出現(xiàn)過。

TDengine 資深研發(fā)分享解決思路,長(zhǎng)查詢不再成為系統(tǒng)性能瓶頸! - TDengine Database 時(shí)序數(shù)據(jù)庫

長(zhǎng)查詢問題解決方案

我們需要一個(gè)方案,可以在長(zhǎng)查詢大量存在、或用戶應(yīng)用代碼有問題沒有及時(shí)關(guān)閉查詢句柄、甚至產(chǎn)品代碼有問題的情況下,也能達(dá)到既不阻塞寫入且不讓長(zhǎng)查詢失敗。該方案如下:

  1. 查詢?cè)讷@取數(shù)據(jù)快照時(shí),將查詢句柄注冊(cè)到它所占用的內(nèi)存塊上,同時(shí)注冊(cè)一個(gè) reseek 函數(shù)
  2. 當(dāng)查詢結(jié)束關(guān)閉句柄時(shí),該查詢將句柄從它所占用的所有內(nèi)存塊上注銷
  3. 當(dāng)寫入發(fā)現(xiàn)沒有可用內(nèi)存塊時(shí),嘗試回收已經(jīng) COMMIT 但是仍舊被查詢占用的最老的內(nèi)存塊
  4. 寫入線程回收內(nèi)存塊時(shí),遍歷所有注冊(cè)在該內(nèi)存塊上的注冊(cè)句柄,調(diào)用 reseek 函數(shù)
  5. reseek 函數(shù)會(huì)嘗試鎖查詢句柄,如果鎖句柄成功,則將查詢句柄設(shè)置為 RESEEK 狀態(tài),同時(shí)將查詢的狀態(tài)保存下來并 untake snapshot,歸還占用的所有內(nèi)存塊
  6. 查詢線程在查詢活躍周期開始時(shí)鎖查詢句柄,然后檢查是否為 RESEEK 狀態(tài),如果為 RESEEK 狀態(tài),重新 take snapshot,并根據(jù)保存的查詢狀態(tài),恢復(fù)各種查詢變量,接著進(jìn)行查詢

從上述方案中我們可以看到:

  1. 寫入在發(fā)現(xiàn)內(nèi)存不足的條件下,可以主動(dòng)回收非激活狀態(tài)的查詢占用的內(nèi)存塊,從而不會(huì)長(zhǎng)時(shí)間阻塞寫入
  2. 長(zhǎng)查詢?cè)趯懭牖厥掌渌加玫膬?nèi)存塊后,可以根據(jù)自己保存的查詢狀態(tài),重新 take snapshot,繼續(xù)查詢,從而不會(huì)讓長(zhǎng)查詢失敗
TDengine 資深研發(fā)分享解決思路,長(zhǎng)查詢不再成為系統(tǒng)性能瓶頸! - TDengine Database 時(shí)序數(shù)據(jù)庫

TDengine 資深研發(fā)分享解決思路,長(zhǎng)查詢不再成為系統(tǒng)性能瓶頸! - TDengine Database 時(shí)序數(shù)據(jù)庫

答疑解惑

Q:如何解決死鎖問題?

A:在寫入回收內(nèi)存塊時(shí),需要遍歷查詢句柄注冊(cè)鏈表,因此需要對(duì)鏈表進(jìn)行加鎖操作,即需要鎖定鏈表的鎖。在調(diào)用 reseek 回調(diào)時(shí),也需要鎖定查詢句柄的鎖。這樣就存在寫入線程出現(xiàn) lock(mutex_list)–>lock(mutex_qhandle) 的情況。而在查詢結(jié)束時(shí),需要將句柄從注冊(cè)鏈表中移除,導(dǎo)致出現(xiàn) lock(mutex_qhandle)–>lock(mutex_list) 的情況。如果兩個(gè)線程不按照相同的順序?qū)蓚€(gè)鎖進(jìn)行加鎖,就會(huì)產(chǎn)生死鎖的問題。

為了解決這個(gè)問題,可以采用以下優(yōu)化方案:

  1. 使用 trylock 替代 lock:對(duì)于寫入回收調(diào)用 reseek 函數(shù)的場(chǎng)景,可以嘗試使用 trylock 而不是直接使用 lock 來獲取查詢句柄的控制權(quán)。通過 trylock 嘗試獲取鎖,可以避免線程因等待鎖而被阻塞,從而減少死鎖的風(fēng)險(xiǎn)。
  2. 多次嘗試機(jī)制:在使用 trylock 的基礎(chǔ)上,可以結(jié)合多次嘗試的機(jī)制。如果一次 trylock 未成功獲取鎖,可以進(jìn)行多次嘗試,直至成功獲取鎖或達(dá)到嘗試次數(shù)上限為止。這樣能夠增加獲取鎖的機(jī)會(huì),降低死鎖風(fēng)險(xiǎn)。
Q:長(zhǎng)查詢會(huì)不會(huì)一直被寫入 reseek,從而導(dǎo)致查詢一直恢復(fù)?

A:不會(huì)存在這種情況。查詢?cè)诿看未蜷_句柄時(shí),會(huì)給一個(gè)版本號(hào),這個(gè)版本號(hào)是已經(jīng)寫入 Vnode 中的最新數(shù)據(jù)的版本號(hào),查詢只能看到版本號(hào)小于等于該版本號(hào)的數(shù)據(jù)。當(dāng) take snapshot 時(shí),會(huì)根據(jù) mem/imem 中的數(shù)據(jù)是否被查詢版本號(hào)覆蓋而決定 mem/imem 是否被該查詢引用。隨著數(shù)據(jù)的寫入,新的 mem/imem 中的數(shù)據(jù)肯定都大于該查詢創(chuàng)建時(shí)給的版本號(hào),因此,新的 mem/imem 不會(huì)被長(zhǎng)查詢引用。這樣一來,一個(gè)長(zhǎng)查詢最多會(huì)被寫入 RESEEK 兩次。

TDengine 資深研發(fā)分享解決思路,長(zhǎng)查詢不再成為系統(tǒng)性能瓶頸! - TDengine Database 時(shí)序數(shù)據(jù)庫

以上就是 TDengine 資深研發(fā)人員對(duì)解決長(zhǎng)查詢問題進(jìn)行的深入探討。如果你還有關(guān)于查詢的更多問題想要討論或交流,歡迎添加小T vx:tdengine 尋求幫助,也可以在下方留言區(qū)進(jìn)行相關(guān)評(píng)論,靜待回復(fù)即可~