最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會(huì)員登陸 & 注冊(cè)

openGauss內(nèi)核分析(一):多線程架構(gòu)啟動(dòng)過程詳解

2022-05-10 19:53 作者:Gauss松鼠會(huì)  | 我要投稿

openGauss數(shù)據(jù)庫(kù)是一個(gè)單進(jìn)程多線程的數(shù)據(jù)庫(kù),客戶端可以使用JDBC/ODBC/Libpq/Psycopg等驅(qū)動(dòng)程序,向openGauss的主線程(Postmaster)發(fā)起連接請(qǐng)求。

openGauss為什么要使用多線程架構(gòu)

隨著計(jì)算機(jī)領(lǐng)域多核技術(shù)的發(fā)展,如何充分有效的利用多核的并行處理能力,是每個(gè)服務(wù)器端應(yīng)用程序都必須考慮的問題。由于數(shù)據(jù)庫(kù)服務(wù)器的服務(wù)進(jìn)程或線程間存在著大量數(shù)據(jù)共享和同步,而多線程可以充分利用多CPU來(lái)并行執(zhí)行多個(gè)強(qiáng)相關(guān)任務(wù),例如執(zhí)行引擎可以充分的利用線程的并發(fā)執(zhí)行以提供性能。在多線程的架構(gòu)下,數(shù)據(jù)共享的效率更高,能提高服務(wù)器訪問的效率和性能,同時(shí)維護(hù)開銷和復(fù)雜度更低,這對(duì)于提高數(shù)據(jù)庫(kù)系統(tǒng)的并行處理能力非常重要。

多線程的三大主要優(yōu)勢(shì):

優(yōu)勢(shì)一:線程啟動(dòng)開銷遠(yuǎn)小于進(jìn)程啟動(dòng)開銷。與進(jìn)程相比,它是一種非?!肮?jié)儉”的多任務(wù)操作方式。在Linux系統(tǒng)下,啟動(dòng)一個(gè)新的進(jìn)程必須分配給它獨(dú)立的地址空間,建立眾多的數(shù)據(jù)表來(lái)維護(hù)它的代碼段、堆棧段和數(shù)據(jù)段,這是一種“昂貴”的多任務(wù)工作方式。而運(yùn)行于一個(gè)進(jìn)程中的多個(gè)線程,它們彼此之間使用相同的地址空間,共享大部分?jǐn)?shù)據(jù),啟動(dòng)一個(gè)線程所花費(fèi)的空間遠(yuǎn)遠(yuǎn)小于啟動(dòng)一個(gè)進(jìn)程所花費(fèi)的空間。

優(yōu)勢(shì)二:線程間方便的通信機(jī)制:對(duì)不同進(jìn)程來(lái)說(shuō),它們具有獨(dú)立的數(shù)據(jù)空間,要進(jìn)行數(shù)據(jù)的傳遞只能通過通信的方式進(jìn)行,這種方式不僅費(fèi)時(shí),而且很不方便。線程則不然,由于同一進(jìn)程下的線程之間共享數(shù)據(jù)空間,所以一個(gè)線程的數(shù)據(jù)可以直接為其他線程所用,這不僅快捷,而且方便。

優(yōu)勢(shì)三:線程切換開銷小于進(jìn)程切換開銷,對(duì)于Linux系統(tǒng)來(lái)講,進(jìn)程切換分兩步:1.切換頁(yè)目錄以使用新的地址空間;2.切換內(nèi)核棧和硬件上下文。對(duì)線程切換,第1步是不需要做的,第2步是進(jìn)程和線程都要做的,所以明顯線程切換開銷小。

openGauss主要線程有哪些

數(shù)據(jù)庫(kù)啟動(dòng)后,可以通過操作系統(tǒng)命令ps查看線程信息(進(jìn)程號(hào)為17012)

openGauss啟動(dòng)過程

下面主要介紹openGauss數(shù)據(jù)庫(kù)的啟動(dòng)過程,包括主線程,輔助線程及業(yè)務(wù)處理線程的啟動(dòng)過程

gs_ctl啟動(dòng)數(shù)據(jù)庫(kù)

gs_ctl是openGauss提供的數(shù)據(jù)庫(kù)服務(wù)控制工具,可以用來(lái)啟停數(shù)據(jù)庫(kù)服務(wù)和查詢數(shù)據(jù)

庫(kù)狀態(tài)。主要供數(shù)據(jù)庫(kù)管理模塊調(diào)用,啟動(dòng)數(shù)據(jù)庫(kù)使用如下命令

gs_ctl的入口函數(shù)在“src/bin/pg_ctl/pg_ctl.cpp”,gs_ctl進(jìn)程fork一個(gè)進(jìn)程來(lái)運(yùn)行 gaussdb進(jìn)程,通過shell命令啟動(dòng)。

上圖中的cmd為“/opt/software/openGauss/bin/gaussdb -D /opt/software/openGauss/data”,進(jìn)入到數(shù)據(jù)庫(kù)運(yùn)行調(diào)用的第一個(gè)函數(shù)是main函數(shù),在“src/gausskernel/process/main/main.cpp”文件中,在main.cpp文件中,主要完成實(shí)例Context(上下文)的初始化、本地化設(shè)置,根據(jù)main.cpp文件的入口參數(shù)調(diào)用BootStrapProcessMain函數(shù)、GucInfoMain函數(shù)、PostgresMain函數(shù)和PostmasterMain函數(shù)。BootStrapProcessMain函數(shù)和PostgresMain函數(shù)是在initdb場(chǎng)景下初始化數(shù)據(jù)庫(kù)使用的。GucInfoMain函數(shù)作用是顯示GUC(grand unified configuration,大統(tǒng)一配置,在數(shù)據(jù)庫(kù)中指的是運(yùn)行參數(shù))參數(shù)信息。正常的數(shù)據(jù)庫(kù)啟動(dòng)會(huì)進(jìn)入PostmasterMain函數(shù)。下面對(duì)這個(gè)函數(shù)進(jìn)行更詳細(xì)的介紹。

1.MemoryContextInit:內(nèi)存上下文系統(tǒng)初始化,主要完成對(duì)ThreadTopMemoryContext,ErrorContext,AlignContext和ProfileLogging等全局變量的初始化

2.pg_perm_setlocale:設(shè)置程序語(yǔ)言環(huán)境相關(guān)的全局變量

3.check_root: 確認(rèn)程序運(yùn)行者無(wú)操作系統(tǒng)的root權(quán)限,防止的意外文件覆蓋等問題

4.如果gaussdb后的第一個(gè)參數(shù)是—boot,則進(jìn)行數(shù)據(jù)庫(kù)初始化,如果gaussdb后的第一個(gè)參數(shù)是--single,則調(diào)用PostgresMain(),進(jìn)入(本地)單用戶版服務(wù)端程序。之后,與普通服務(wù)器端線程類似,循環(huán)等待用戶輸入SQL語(yǔ)句,直至用戶輸入EOF(Ctrl+D),退出程序。如果沒有指定額外啟動(dòng)選項(xiàng),程序進(jìn)入PostmasterMain函數(shù),開始一系列服務(wù)器端的正常初始化工作。

PostmasterMain函數(shù)

下面具體介紹PostmasterMain。

1.設(shè)置線程號(hào)相關(guān)的全局變量MyProcPid、PostmasterPid、MyProgName和程序運(yùn)行環(huán)境相關(guān)的全局變量IsPostmasterEnvironment

2.調(diào)用postmaster_mem_cxt = AllocSetContextCreate(t_thrd.top_mem_cxt,...),在目前線程的top_mem_cxt下創(chuàng)建postmaster_mem_cxt全局變量和相應(yīng)的內(nèi)存上下文

3. MemoryContextSwitchTo(postmaster_mem_cxt)切換到postmaster_mem_cxt內(nèi)存上下文

4.調(diào)用getInstallationPaths(),設(shè)置my_exec_path(一般即為gaussdb可執(zhí)行文件所在路徑)

5.調(diào)用InitializeGUCOptions(),根據(jù)代碼中各個(gè)GUC參數(shù)的默認(rèn)值生成ConfigureNamesBool、ConfigureNamesInt、ConfigureNamesReal、ConfigureNamesString、ConfigureNamesEnum等 GUC參數(shù)的全局變量數(shù)組,以及統(tǒng)一管理GUC參數(shù)的guc_variables、num_guc_variables、size_guc_variables全局變量,并設(shè)置與具體操作系統(tǒng)環(huán)境相關(guān)的GUC參數(shù)

6. while (opt = ...) SetConfigOption, 若在啟動(dòng)gaussdb時(shí)用指定了非默認(rèn)的GUC參數(shù),則在此時(shí)加載至上一步中創(chuàng)建的全局變量中

7.調(diào)用checkDataDir(),確認(rèn)數(shù)據(jù)庫(kù)安裝成功以及PGDATA目錄的有效性

8.調(diào)用CreateDataDirLockFile(),創(chuàng)建數(shù)據(jù)目錄的鎖文件

9.調(diào)用process_shared_preload_libraries(),處理預(yù)加載庫(kù)

10.為每個(gè)ListenSocket創(chuàng)建監(jiān)聽

11. reset_shared,設(shè)置共享內(nèi)存和信號(hào),主要包括頁(yè)面緩存池、各種鎖緩存池、WAL日志緩存池、事務(wù)日志緩存池、事務(wù)(號(hào))概況緩存池、各后臺(tái)線程(鎖使用)概況緩存池、各后臺(tái)線程等待和運(yùn)行狀態(tài)緩存池、兩階段狀態(tài)緩存池、檢查點(diǎn)緩存池、WAL日志復(fù)制和接收緩存池、數(shù)據(jù)頁(yè)復(fù)制和接收緩存池等。在后續(xù)階段創(chuàng)建出的客戶端后臺(tái)線程以及各個(gè)輔助線程均使用該共享內(nèi)存空間,不再單獨(dú)開辟

12.將啟動(dòng)時(shí)手動(dòng)設(shè)置的GUC參數(shù)以文件形式保存下來(lái),以供后續(xù)后臺(tái)服務(wù)端線程啟動(dòng)時(shí)使用

13.為不同信號(hào)設(shè)置handler

14.調(diào)用pgstat_init(),初始化狀態(tài)收集子系統(tǒng);

15.調(diào)用load_hba(),加載pg_hba.conf文件,該文件記錄了允許連接(指定或全部)數(shù)據(jù)庫(kù)的客戶端物理機(jī)的地址和端口;調(diào)用load_ident(),加載pg_ident.conf文件,該文件記錄了操作系統(tǒng)用戶名與數(shù)據(jù)庫(kù)系統(tǒng)用戶名的對(duì)應(yīng)關(guān)系,以便后續(xù)處理客戶端連接時(shí)的身份認(rèn)證

16.調(diào)用 StartupPID = initialize_util_thread(STARTUP),進(jìn)行數(shù)據(jù)一致性校驗(yàn)。對(duì)于服務(wù)端主機(jī)來(lái)說(shuō),查看pg_control文件,若上次關(guān)閉狀態(tài)為DB_SHUTDOWNED且recovery.conf文件沒有指定進(jìn)行恢復(fù),則認(rèn)為數(shù)據(jù)一致性成立;否則,根據(jù)pg_control中檢查點(diǎn)的redo位置或者recovery.conf文件中指定的位置,讀取WAL日志或歸檔日志進(jìn)行replay(回放),直至數(shù)據(jù)達(dá)到預(yù)期的一致性狀,主要函數(shù)StartupXLOG

17. 最后進(jìn)入ServerLoop()函數(shù),循環(huán)響應(yīng)客戶端連接請(qǐng)求

ServerLoop函數(shù)

下面來(lái)講ServerLoop函數(shù)主流程

1.調(diào)用gs_signal_setmask(&UnBlockSig, NULL)和gs_signal_unblock_sigusr2(),使得線程可以響應(yīng)用戶或其它線程的、指定的信號(hào)集

2.每隔PM_POLL_TIMEOUT_MINUTE時(shí)間修改一次socket文件和socket鎖文件的訪問和修改時(shí)間,以免被操作系統(tǒng)淘汰

3.判斷線程狀態(tài)(pmState),若為PM_WAIT_DEAD_END,則休眠100毫秒,并且不接收任何連接;否則,通過系統(tǒng)調(diào)用poll()或select()來(lái)阻塞地讀取監(jiān)聽端口上傳入的數(shù)據(jù),最長(zhǎng)阻塞時(shí)間PM_POLL_TIMEOUT_SECOND

4.調(diào)用gs_signal_setmask(&BlockSig, NULL)和gs_signal_block_sigusr2()不再接收外源信號(hào)

5.判斷poll()或select()函數(shù)的返回值,若小于零,監(jiān)聽出錯(cuò),服務(wù)端進(jìn)程退出;若大于零,則創(chuàng)建連接ConnCreate(),并進(jìn)入后臺(tái)服務(wù)線程啟動(dòng)流程BackendStartup()。對(duì)于父線程,即postmaster線程,在結(jié)束BackendStartup()的調(diào)用以后,會(huì)調(diào)用ConnFree(),清除連接信息;若poll()或select()的返回值為零,即沒有信息傳入,則不進(jìn)行任何操作

6.調(diào)用ADIO_RUN()、ADIO_END() ,若AioCompleters沒有啟動(dòng),則啟動(dòng)之

7.檢查各個(gè)輔助線程的線程號(hào)是否為零,若為零,則調(diào)用initialize_util_thread啟動(dòng)

以非線程池模式為例,介紹線程的啟動(dòng)邏輯。BackendStartup函數(shù)是通過調(diào)用initialize_worker_thread(WORKE,port)創(chuàng)建一個(gè)后臺(tái)線程處理客戶請(qǐng)求。后臺(tái)線程的啟動(dòng)函數(shù)initialize_util_thread和工作線程的啟動(dòng)函數(shù)initialize_worker_thread,最后都是調(diào)用initialize_thread函數(shù)完成線程的啟動(dòng)。

1.initialize_thread函數(shù)調(diào)用gs_thread_create函數(shù)創(chuàng)建線程,調(diào)用InternalThreadFunc函數(shù)處理線程

2.InternalThreadFunc函數(shù)根據(jù)角色調(diào)用GetThreadEntry函數(shù),GetThreadEntry函數(shù)直接以角色為下標(biāo),返回對(duì)應(yīng)GaussdbThreadEntryGate數(shù)組對(duì)應(yīng)的元素。數(shù)組的元素是處理具體任務(wù)的回調(diào)函數(shù)指針,指針指向的函數(shù)為GaussDbThreadMain

3.在GaussDbThreadMain函數(shù)中,首先初始化線程基本信息,Context和信號(hào)處理函數(shù),接著就是根據(jù)thread_role角色的不同調(diào)用不同角色的處理函數(shù),進(jìn)入各個(gè)線程的main函數(shù),角色為WORKER會(huì)進(jìn)入PostgresMain函數(shù),下面具體介紹PostgresMain函數(shù)

PostgresMain函數(shù)

1 process_postgres_switches(),加載傳入的啟動(dòng)選項(xiàng)和GUC參數(shù)

2.為不同信號(hào)設(shè)置handler

3.調(diào)用sigdelset(&BlockSig, SIGQUIT),允許響應(yīng)SIGQUIT信號(hào)

4.調(diào)用BaseInit(),初始化存儲(chǔ)管理系統(tǒng)和頁(yè)面緩存池計(jì)數(shù)

5.調(diào)用on_shmem_exit(),設(shè)置線程退出前需要進(jìn)行的內(nèi)存清理動(dòng)作。這些清理動(dòng)作構(gòu)成一個(gè)鏈表(on_shmem_exit_list全局變量),每次調(diào)用該函數(shù)都向鏈表尾端添加一個(gè)節(jié)點(diǎn),鏈表長(zhǎng)度由on_shmem_exit_index記錄,且不可超過MAX_ON_EXITS宏。在線程退出時(shí),從后往前調(diào)用各個(gè)節(jié)點(diǎn)中的動(dòng)作(函數(shù)指針),完成清理工作

6.調(diào)用gs_signal_setmask (&UnBlockSig),設(shè)置屏蔽的信號(hào)類型

7.調(diào)用InitBackendWorker進(jìn)行統(tǒng)計(jì)系統(tǒng)初始化、syscache初始化工作

8. BeginReportingGUCOptions如有需要?jiǎng)t打印GUC參數(shù)

9.調(diào)用on_proc_exit(),設(shè)置線程退出前需要進(jìn)行的線程清理動(dòng)作。設(shè)置和調(diào)用機(jī)制與on_shmem_exit()類似

10.調(diào)用process_local_preload_libraries(),處理GUC參數(shù)設(shè)定后的預(yù)加載庫(kù)

11. AllocSetContextCreate創(chuàng)建MessageContext、RowDescriptionContext、MaskPasswordCtx上下文

12.調(diào)用sigsetjmp(),設(shè)置longjump點(diǎn),若后續(xù)查詢執(zhí)行中出錯(cuò),在某些情況下可以返回此處重新開始

13.調(diào)用gs_signal_unblock_sigusr2(),允許線程響應(yīng)指定的信號(hào)集

14.然后進(jìn)入for循環(huán),進(jìn)行查詢執(zhí)行

1.調(diào)用pgstat_report_activity()、pgstat_report_waitstatus(),告訴統(tǒng)計(jì)系統(tǒng)后臺(tái)線程正

處于idle狀態(tài)

2.設(shè)置全局變量DoingCommandRead = true

3.調(diào)用ReadCommand(),讀取客戶端SQL語(yǔ)句

4.設(shè)置全局變量DoingCommandRead=false

5.若在上述過程中收到SIGHUP信號(hào),表示線程需要重新加載修改過的postgresql.conf配置文件

6.進(jìn)入switch (firstchar),根據(jù)接收到的信息進(jìn)行分支判斷

思考如何新增一個(gè)輔助線程

參考其他線程完成

作者:酷哥

openGauss內(nèi)核分析(一):多線程架構(gòu)啟動(dòng)過程詳解的評(píng)論 (共 條)

分享到微博請(qǐng)遵守國(guó)家法律
翁源县| 隆回县| 大关县| 祥云县| 马鞍山市| 武威市| 蓬溪县| 西青区| 会宁县| 崇左市| 班戈县| 韩城市| 贞丰县| 淄博市| 祁连县| 宜都市| 宜昌市| 琼海市| 赤城县| 伊宁县| 广汉市| 新竹市| 文成县| 镇远县| 沅江市| 武隆县| 玛曲县| 定州市| 冷水江市| 夏津县| 紫金县| 花莲县| 渝北区| 虞城县| 新郑市| 施秉县| 浠水县| 岳普湖县| 寻甸| 仪陇县| 东平县|