溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析

發(fā)布時(shí)間:2022-01-04 17:21:15 來(lái)源:億速云 閱讀:194 作者:iii 欄目:數(shù)據(jù)庫(kù)

這篇文章主要講解了“PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析”吧!

賽題概覽

比賽總體分成了初賽和復(fù)賽兩個(gè)階段,整體要求實(shí)現(xiàn)一個(gè)簡(jiǎn)化、高效的 kv 存儲(chǔ)引擎

初賽要求支持 Write、Read 接口。

public abstract void write(byte[] key, byte[] value);public abstract byte[] read(byte[] key);

復(fù)賽在初賽題目基礎(chǔ)上,還需要額外實(shí)現(xiàn)一個(gè) Range 接口。

public abstract void range(byte[] lower, byte[] upper, AbstractVisitor visitor);

程序評(píng)測(cè)邏輯 分為2個(gè)階段: 1)Recover 正確性評(píng)測(cè): 此階段評(píng)測(cè)程序會(huì)并發(fā)寫(xiě)入特定數(shù)據(jù)(key 8B、value 4KB)同時(shí)進(jìn)行任意次 kill -9 來(lái)模擬進(jìn)程意外退出(參賽引擎需要保證進(jìn)程意外退出時(shí)數(shù)據(jù)持久化不丟失),接著重新打開(kāi) DB,調(diào)用 Read、Range 接口來(lái)進(jìn)行正確性校驗(yàn)

2)性能評(píng)測(cè)

  • 隨機(jī)寫(xiě)入:64 個(gè)線程并發(fā)隨機(jī)寫(xiě)入,每個(gè)線程使用 Write 各寫(xiě) 100 萬(wàn)次隨機(jī)數(shù)據(jù)(key 8B、value 4KB)

  • 隨機(jī)讀?。?4 個(gè)線程并發(fā)隨機(jī)讀取,每個(gè)線程各使用 Read 讀取 100 萬(wàn)次隨機(jī)數(shù)據(jù)

  • 順序讀?。?4 個(gè)線程并發(fā)順序讀取,每個(gè)線程各使用 Range 有序(增序)遍歷全量數(shù)據(jù) 2 次 注: 2.2 階段會(huì)對(duì)所有讀取的 kv 校驗(yàn)是否匹配,如不通過(guò)則終止,評(píng)測(cè)失敗; 2.3 階段除了對(duì)迭代出來(lái)每條的 kv校 驗(yàn)是否匹配外,還會(huì)額外校驗(yàn)是否嚴(yán)格字典序遞增,如不通過(guò)則終止,評(píng)測(cè)失敗。

語(yǔ)言限定:C++ & JAVA,一起排名

 賽題剖析

關(guān)于文件 IO 操作的一些基本常識(shí),我已經(jīng)在專(zhuān)題文章中進(jìn)行了介紹,如果你沒(méi)有瀏覽那篇文章,建議先行瀏覽一下:文件IO操作的一些最佳實(shí)踐。再回歸賽題,先對(duì)賽題中的幾個(gè)關(guān)鍵詞來(lái)進(jìn)行解讀。

3.1 key 8B, value 4kb

key 為固定的 8 字節(jié),因此可使用 long 來(lái)表示。

value 為 4kb,這節(jié)省了我們很大的工作量,因?yàn)?4kb 的整數(shù)倍落盤(pán)是非常磁盤(pán) IO 友好的。

value 為 4kb 的另一個(gè)好處是我們?cè)賰?nèi)存做索引時(shí),可以使用 int 而不是 long,來(lái)記錄數(shù)據(jù)的邏輯偏移量:LogicOffset = PhysicalOffset / 4096,可以將 offset 的內(nèi)存占用量減少一半。

3.2 kill -9 數(shù)據(jù)不丟失

首先賽題明確表示會(huì)進(jìn)行 kill -9 并驗(yàn)證數(shù)據(jù)的一致性,這加大了我們?cè)趦?nèi)存中做 write buffer 的難度。但它并沒(méi)有要求斷電不丟失,這間接地闡釋了一點(diǎn):我們可以使用 pageCache 來(lái)做寫(xiě)入緩存,在具體代碼中我使用了 PageCache 來(lái)充當(dāng)數(shù)據(jù)和索引的寫(xiě)入緩沖(兩者策略不同)。同時(shí)這點(diǎn)也限制了參賽選手,不能使用 AIO 這樣的異步落盤(pán)方式。

3.3 分階段測(cè)評(píng)

賽題分為了隨機(jī)寫(xiě),隨機(jī)讀,順序讀三個(gè)階段,每個(gè)階段都會(huì)重新 open,且不會(huì)發(fā)生隨機(jī)寫(xiě)到一半校驗(yàn)隨機(jī)讀這樣的行為,所以我們?cè)陔S機(jī)寫(xiě)階段不需要在內(nèi)存維護(hù)索引,而是直接落盤(pán)。隨機(jī)讀和順序讀階段,磁盤(pán)均存在數(shù)據(jù),open 階段需要恢復(fù)索引,可以使用多線程并發(fā)恢復(fù)。

同時(shí),賽題還有存在一些隱性的測(cè)評(píng)細(xì)節(jié)沒(méi)有披露給大家,但通過(guò)測(cè)試,我們可以得知這些信息。

3.4 清空 PageCache 的耗時(shí)

雖然我們可以使用 PageCache,但評(píng)測(cè)程序在每個(gè)階段之后都使用腳本清空了 PageCache,并且將這部分時(shí)間也算進(jìn)了最終的成績(jī)之中,所以有人感到奇怪:三個(gè)階段的耗時(shí)相加比輸出出來(lái)的成績(jī)要差,其實(shí)那幾秒便是清空 PageCache 的耗時(shí)。

#清理 pagecache (頁(yè)緩存)
sysctl -w vm.drop_caches=1
#清理 dentries(目錄緩存)和 inodes
sysctl -w vm.drop_caches=2
#清理pagecache、dentries和inodes
sysctl -w vm.drop_caches=3

這一點(diǎn)啟發(fā)我們,不能毫無(wú)節(jié)制的使用 PageCache,也正是因?yàn)檫@一點(diǎn),一定程度上使得 Direct IO 這一操作成了本次競(jìng)賽的銀彈。

3.5 key 的分布

這一個(gè)隱性條件可謂是本次比賽的關(guān)鍵,因?yàn)樗婕暗?Range 部分的架構(gòu)設(shè)計(jì)。本次比賽的 key 共計(jì) 6400w,但是他們的分布都是均勻的,在《文件IO操作的一些最佳實(shí)踐》 一文中我們已經(jīng)提到了數(shù)據(jù)分區(qū)的好處,可以大大減少順序讀寫(xiě)的鎖沖突,而 key 的分布均勻這一特性,啟發(fā)我們?cè)谧鰯?shù)據(jù)分區(qū)時(shí),可以按照 key 的搞 n 位來(lái)做 hash,從而確保 key 兩個(gè)分區(qū)之間整體有序(分區(qū)內(nèi)部無(wú)序)。實(shí)際我嘗試了將數(shù)據(jù)分成 1024、2048 個(gè)分區(qū),效果最佳。

3.6 Range 的緩存設(shè)計(jì)

賽題要求 64 個(gè)線程 Range 兩次全量的數(shù)據(jù),限時(shí) 1h,這也啟發(fā)了我們,如果不對(duì)數(shù)據(jù)進(jìn)行緩存,想要在 1h 內(nèi)完成比賽是不可能的,所以,我們的架構(gòu)設(shè)計(jì)應(yīng)該盡量以 Range 為核心,兼顧隨機(jī)寫(xiě)和隨機(jī)讀。Range 部分也是最容易拉開(kāi)差距的一個(gè)環(huán)節(jié)。

4 架構(gòu)詳解

首先需要明確的是,隨機(jī)寫(xiě)指的是 key 的寫(xiě)入是隨機(jī)的,但我們可以根據(jù) key hash,將隨機(jī)寫(xiě)轉(zhuǎn)換為對(duì)應(yīng)分區(qū)文件的順序?qū)憽?/p>

/**
 * using high ten bit of the given key to determine which file it hits.
 */
public class HighTenPartitioner implements Partitionable {
    @Override
    public int getPartition(byte[] key) {
        return ((key[0] & 0xff) << 2) | ((key[1] & 0xff) >> 6);
    }
}

明確了高位分區(qū)的前提再來(lái)看整體的架構(gòu)就變得明朗了

全局視角

PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析

分區(qū)視角

PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析

內(nèi)存視角

內(nèi)存中僅僅維護(hù)有序的 key[1024][625000] 數(shù)組和 offset[1024][625000] 數(shù)組。

上述兩張圖對(duì)整體的架構(gòu)進(jìn)行了一個(gè)很好的詮釋?zhuān)脭?shù)據(jù)分布均勻的特性,可以將全局?jǐn)?shù)據(jù) hash 成 1024 個(gè)分區(qū),在每個(gè)分區(qū)中存放兩類(lèi)文件:索引文件和數(shù)據(jù)文件。在隨機(jī)寫(xiě)入階段,根據(jù) key 獲得該數(shù)據(jù)對(duì)應(yīng)分區(qū)位置,并按照時(shí)序,順序追加到文件末尾,將全局隨機(jī)寫(xiě)轉(zhuǎn)換為局部順序?qū)?。利用索引和?shù)據(jù)一一對(duì)應(yīng)的特性,我們也不需要將 data 的邏輯偏移量落盤(pán),在 recover 階段可以按照恢復(fù) key 的次序,反推出 value 的邏輯偏移量。

在 range 階段,由于我們事先按照 key 的高 10 為做了分區(qū),所以我們可以認(rèn)定一個(gè)事實(shí),patition(N) 中的任何一個(gè)數(shù)據(jù)一定大于 partition(N-1) 中的任何一個(gè)數(shù)據(jù),于是我們可以采用大塊讀,將一個(gè) partition 整體讀進(jìn)內(nèi)存,供 64 個(gè) visit 線程消費(fèi)。到這兒便奠定了整體的基調(diào):讀盤(pán)線程負(fù)責(zé)按分區(qū)讀盤(pán)進(jìn)入內(nèi)存,64 個(gè) visit 線程負(fù)責(zé)消費(fèi)內(nèi)存,按照 key 的次序隨機(jī)訪問(wèn)內(nèi)存,進(jìn)行 Visitor 的回調(diào)。

 隨機(jī)寫(xiě)流程

介紹完了整體架構(gòu),我們分階段來(lái)看一下各個(gè)階段的一些細(xì)節(jié)優(yōu)化點(diǎn),有一些優(yōu)化在各個(gè)環(huán)節(jié)都會(huì)出現(xiàn),未避免重復(fù),第二次出現(xiàn)的同一優(yōu)化點(diǎn)我就不贅述了,僅一句帶過(guò)。

使用 pageCache 實(shí)現(xiàn)寫(xiě)入緩沖區(qū)

主要看數(shù)據(jù)落盤(pán),后討論索引落盤(pán)。磁盤(pán) IO 類(lèi)型的比賽,第一步便是測(cè)量磁盤(pán)的 IOPS 以及多少個(gè)線程一次讀寫(xiě)多大的緩存能夠打滿(mǎn) IO,在固定 64 線程寫(xiě)入的前提下,16kb,64kb 均可以達(dá)到最理想 IOPS,所以理所當(dāng)然的想到,可以為每一個(gè)分區(qū)分配一個(gè)寫(xiě)入緩存,湊齊 4 個(gè) value 落盤(pán)。但是此次比賽,要做到 kill -9 不丟失數(shù)據(jù),不能簡(jiǎn)單地在內(nèi)存中分配一個(gè) ByteBuffer.allocate(4096*4);, 而是可以考慮使用 mmap 內(nèi)存映射出一片寫(xiě)入緩沖,湊齊 4 個(gè)刷盤(pán),這樣在 kill -9 之后,PageCache 不會(huì)丟失。實(shí)測(cè) 16kb 落盤(pán)比 4kb 落盤(pán)要快 6s 左右。

索引文件的落盤(pán)則沒(méi)有太大的爭(zhēng)議,由于 key 的數(shù)據(jù)量為固定的 8B,所以 mmap 可以發(fā)揮出它寫(xiě)小數(shù)據(jù)的優(yōu)勢(shì),將 pageCache 利用起來(lái),實(shí)測(cè) mmap 相比 filechannel 寫(xiě)索引要快 3s 左右,相信如果把 polardb 這塊盤(pán)換做其他普通的 ssd,這個(gè)數(shù)值還要增加。

寫(xiě)入時(shí)不維護(hù)內(nèi)存索引,不寫(xiě)入數(shù)據(jù)偏移

一開(kāi)始審題不清,在隨機(jī)寫(xiě)之后誤以為會(huì)立刻隨機(jī)讀,實(shí)際上每個(gè)階段都是獨(dú)立的,所以不需要在寫(xiě)入時(shí)維護(hù)內(nèi)存索引;其次,之前的架構(gòu)圖中也已經(jīng)提及,不需要寫(xiě)入連帶 key+offset 一起寫(xiě)入文件,recover 階段可以按照恢復(fù)索引的順序,反推出 data 的邏輯偏移,因?yàn)槲覀兊?key 和 data 在同一個(gè)分區(qū)內(nèi)的位置是一一對(duì)應(yīng)的。

 恢復(fù)流程

recover 階段的邏輯實(shí)際上包含在程序的 open 接口之中,我們需要再數(shù)據(jù)庫(kù)引擎啟動(dòng)時(shí),將索引從數(shù)據(jù)文件恢復(fù)到內(nèi)存之中,在這之中也存在一些細(xì)節(jié)優(yōu)化點(diǎn)。

由于 1024 個(gè)分區(qū)的存在,我們可以使用 64 個(gè)線程 (經(jīng)驗(yàn)值) 并發(fā)地恢復(fù)索引,使用快速排序?qū)?key[1024][62500]  數(shù)組和 offset[1024][62500]  進(jìn)行 sort,之后再 compact,對(duì) key 進(jìn)行去重。需要注意的一點(diǎn)是,不要使用結(jié)構(gòu)體,將 key 和 offset 封裝在一起,這會(huì)使得排序和之后的二分效率非常低,這之中涉及到 CPU 緩存行的知識(shí)點(diǎn),不了解的讀者可以翻閱我之前的博客: 《CPU Cache 與緩存行》

// wrongpublic class KeyOffset {    long key;    int offset;}

整個(gè) recover 階段耗時(shí)為 1s,跟 cpp 選手交流后發(fā)現(xiàn)恢復(fù)流程比之慢了 600ms,這中間讓我覺(jué)得比較詭異,加載索引和排序不應(yīng)該這么慢才對(duì),最終也沒(méi)有優(yōu)化成功。

 隨機(jī)讀流程

隨機(jī)讀流程沒(méi)有太大的優(yōu)化點(diǎn),優(yōu)化空間實(shí)在有限,實(shí)現(xiàn)思路便是先根據(jù) key 定位到分區(qū),之后在有序的 key 數(shù)據(jù)中二分查找到 key/offset,拿到 data 的邏輯偏移和分區(qū)編號(hào),便可以愉快的隨機(jī)讀了,隨機(jī)讀階段沒(méi)有太大的優(yōu)化點(diǎn),但仍然比 cpp 選手慢了 2-3s,可能是語(yǔ)言無(wú)法越過(guò)的差距。

 順序讀流程

Range 環(huán)節(jié)是整個(gè)比賽的大頭,也是拉開(kāi)差距的分水嶺。前面我們已經(jīng)大概提到了 Range 的整體思路是一個(gè)生產(chǎn)者消費(fèi)者模型,n 個(gè)生成者負(fù)責(zé)從磁盤(pán)讀數(shù)據(jù)進(jìn)入內(nèi)存(n 作為變量,通過(guò) benchmark 來(lái)確定多少合適,最終實(shí)測(cè) n 為 4 時(shí)效果最佳),64 個(gè)消費(fèi)者負(fù)責(zé)調(diào)用 visit 回調(diào),來(lái)驗(yàn)證數(shù)據(jù),visit 過(guò)程就是隨機(jī)讀內(nèi)存的過(guò)程。在 Range 階段,剩余的內(nèi)存還有大概 1G 左右,所以我分配了 4 個(gè)堆外緩沖,一個(gè) 256M,從而可以緩存 4 個(gè)分區(qū)的數(shù)據(jù),并且,我為每一個(gè)分區(qū)分配了一個(gè)讀盤(pán)線程,負(fù)責(zé) load 數(shù)據(jù)進(jìn)入緩存,供 64 個(gè)消費(fèi)者消費(fèi)。

具體的順序讀架構(gòu)可以參見(jiàn)下圖:

PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析

大體來(lái)看,便是 4 個(gè) fetch 線程負(fù)責(zé)讀盤(pán),fetch thread n 負(fù)責(zé) partitionNo%4==n 編號(hào)的分區(qū),完成后通知 visit 消費(fèi)。這中間充斥著比較多的互斥等待邏輯,并未在圖中體現(xiàn)出來(lái),大體如下:

  1. fetch thread 1~4 加載磁盤(pán)數(shù)據(jù)進(jìn)入緩存是并發(fā)的

  2. visit group 1~64 訪問(wèn)同一個(gè) buffer 是并發(fā)的

  3. visit group 1~64 訪問(wèn)不同 partition 對(duì)應(yīng)的 buffer 是按照次序來(lái)進(jìn)行的(打到全局有序)

  4. 加載 partitonN 會(huì)阻塞 visit bufferN,visit bufferN 會(huì)阻塞加載 partitionN+4(相當(dāng)于復(fù)用4塊緩存)

大塊的加載讀進(jìn)緩存,最大程度復(fù)用,是 ReadSeq 部分的關(guān)鍵。順序讀兩輪的成績(jī)?cè)?196~198s 左右,相比 C++ 又慢了 4s 左右。

魔鬼在細(xì)節(jié)中

這兒是個(gè)分水嶺,介紹完了整體架構(gòu)和四個(gè)階段的細(xì)節(jié)實(shí)現(xiàn),下面就是介紹下具體的優(yōu)化點(diǎn)了。

Java 實(shí)現(xiàn) Direct IO

由于這次比賽將 drop cache 的時(shí)間算進(jìn)了測(cè)評(píng)程序之中,所以在不必要的地方應(yīng)當(dāng)盡量避免 pageCache,也就是說(shuō)除了寫(xiě)索引之外,其他階段不應(yīng)該出現(xiàn) pageCache。這對(duì)于 Java 選手來(lái)說(shuō)可能是不小的障礙,因?yàn)?Java 原生沒(méi)有提供 Direct IO,需要自己封裝一套 JNA 接口,封裝這套接口借鑒了開(kāi)源框架 jaydio 的思路,感謝@塵央的協(xié)助,大家可以在文末的代碼中看到實(shí)現(xiàn)細(xì)節(jié)。這一點(diǎn)可以說(shuō)是攔住了一大票 Java 選手。

Direct IO 需要注意的兩個(gè)細(xì)節(jié):

  1. 分配的內(nèi)存需要對(duì)齊,對(duì)應(yīng) jna 方法:posix_memalign

  2. 寫(xiě)入的數(shù)據(jù)需要對(duì)齊通常是 pageSize 的整數(shù)倍,實(shí)際使用了 pread 的 O_DIRECT

 直接內(nèi)存優(yōu)于堆內(nèi)內(nèi)存

這一點(diǎn)在《文件IO操作的一些最佳實(shí)踐》中有所提及,堆外內(nèi)存的兩大好處是減少了一份內(nèi)存拷貝,并且對(duì) gc 友好,在 Direct IO 的實(shí)現(xiàn)中,應(yīng)該配備一套堆外內(nèi)存的接口,才能發(fā)揮出最大的功效。尤其在 Range 階段,一個(gè)緩存區(qū)的大小便對(duì)應(yīng)一個(gè) partition 數(shù)據(jù)分區(qū)的大?。?56M,大塊的內(nèi)存,更加適合用 DirectByteBuffer 裝載。

 JVM 調(diào)優(yōu)

-server -Xms2560m -Xmx2560m -XX:MaxDirectMemorySize=1024m -XX:NewRatio=4 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:-UseBiasedLocking

眾所周知 newRatio 控制的是 young 區(qū)和 old 區(qū)大小的比例,官方推薦參數(shù)為 -XX:NewRatio=1,很多不注意的 Java 選手可能沒(méi)有意識(shí)去修改它,會(huì)在無(wú)形中被 gc 拖累。經(jīng)過(guò)和@阿杜的討論,最終得出的結(jié)論:

  1. young 區(qū)過(guò)大,對(duì)象在年輕代待得太久,多次拷貝

  2. old 區(qū)過(guò)小,會(huì)頻繁觸發(fā) old 區(qū)的 cms gc

在比賽中這顯得尤為重要, -XX:NewRatio=4 放大老年代可以有效的減少 cms gc 的次數(shù),將 126 次 cms gc,下降到最終的 5 次。

 池化對(duì)象

無(wú)論是 apache 的 ObjectPool 還是 Netty 中的 Recycler,還是 RingBuffer 中預(yù)先分配的對(duì)象,都在傳達(dá)一種思想,對(duì)于那些反復(fù)需要 new 出來(lái)的東西,都可以池化,分配內(nèi)存再回收,這也是一筆不小的開(kāi)銷(xiāo)。在此次比賽的場(chǎng)景下,沒(méi)必要大費(fèi)周章地動(dòng)用對(duì)象池,直接一個(gè) ThreadLocal 即可搞定,事實(shí)上我對(duì) key/value 的寫(xiě)入和讀取都進(jìn)行了 ThreadLocal 的緩存,做到了永遠(yuǎn)不再循環(huán)中分配對(duì)象。

 減少線程切換

無(wú)論是網(wǎng)絡(luò) IO 還是磁盤(pán) IO,io worker 線程的時(shí)間片都顯得尤為的可貴,在我的架構(gòu)中,range 階段主要分為了兩類(lèi)線程:64 個(gè) visit 線程并發(fā)隨機(jī)讀內(nèi)存,4 個(gè) io 線程并發(fā)讀磁盤(pán)。木桶效應(yīng),我們很容易定位到瓶頸在于 4 個(gè) io 線程,在 wait/notify 的模型中,為了盡可能的減少 io 線程的時(shí)間片流失,可以考慮使用 while(true) 進(jìn)行輪詢(xún),而 visit 線程則可以 sleep(1us) 避免 cpu 空轉(zhuǎn)帶來(lái)的整體性能下降,由于評(píng)測(cè)機(jī)擁有 64 core,所以這樣的分配算是較為合理的,為此我實(shí)現(xiàn)了一個(gè)簡(jiǎn)單粗暴的信號(hào)量。

  1. public class LoopQuerySemaphore {


  2.    private volatile boolean permit;


  3.    public LoopQuerySemaphore(boolean permit) {

  4.        this.permit = permit;

  5.    }


  6.    // for 64 visit thread

  7.    public void acquire() throws InterruptedException {

  8.        while (!permit) {

  9.            Thread.sleep(0,1);

  10.        }

  11.        permit = false;

  12.    }


  13.    // for 4 fetch thread

  14.    public void acquireNoSleep() throws InterruptedException {

  15.        while (!permit) {

  16.        }

  17.        permit = false;

  18.    }


  19.    public void release() {

  20.        permit = true;

  21.    }


  22. }

正確的在 IO 中 acquireNoSleep,在 Visit 中 acquire,可以讓成績(jī)相比使用普通的阻塞 Semaphore 提升 6s 左右。

 綁核

線上機(jī)器的抖動(dòng)在所難免,避免 IO 線程的切換也并不僅僅能夠用依靠 while(true) 的輪詢(xún),一個(gè) CPU 級(jí)別的優(yōu)化便是騰出 4 個(gè)核心專(zhuān)門(mén)給 IO 線程使用,完全地避免 IO 線程的時(shí)間片爭(zhēng)用。在 Java 中這也不難實(shí)現(xiàn),依賴(lài)萬(wàn)能的 github,我們可以輕松地實(shí)現(xiàn) Affinity。

使用方式:

try (final AffinityLock al2 = AffinityLock.acquireLock()) {    // do fetch ...}

這個(gè)方式可以讓你的代碼快 1~2 s,并且保持測(cè)評(píng)的穩(wěn)定性。

感謝各位的閱讀,以上就是“PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)PolarDB數(shù)據(jù)庫(kù)性能實(shí)例分析這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI