徐 丹,艾文凱
(南京南瑞繼保電氣有限公司 研究院數(shù)據(jù)平臺(tái)部,南京 211101)
隨著電力系統(tǒng)高實(shí)時(shí)要求應(yīng)用的發(fā)展,時(shí)間序列數(shù)據(jù)庫在電力系統(tǒng)中的應(yīng)用越來越廣泛,廣域測(cè)量系統(tǒng)、變電站監(jiān)控、調(diào)度、直流、穩(wěn)控等多個(gè)電力自動(dòng)化系統(tǒng)中都能見到身影,用于滿足存儲(chǔ)海量、高頻數(shù)據(jù)的需求.時(shí)間序列數(shù)據(jù)庫主要用于處理秒級(jí)、毫秒級(jí)高頻數(shù)據(jù),每個(gè)存儲(chǔ)周期(毫秒或是秒)會(huì)產(chǎn)生一批數(shù)據(jù),因此數(shù)據(jù)量極大,對(duì)網(wǎng)絡(luò)流量和網(wǎng)絡(luò)中間件的讀寫性能要求極高,通用架構(gòu)的網(wǎng)絡(luò)中間件很難滿足時(shí)間序列數(shù)據(jù)庫的特別要求,需要定制開發(fā)適用于時(shí)間序列數(shù)據(jù)庫的網(wǎng)絡(luò)中間件,針對(duì)報(bào)文、網(wǎng)絡(luò)和存儲(chǔ)特點(diǎn)進(jìn)行全面優(yōu)化.
RPC的基本通信模型是基于Client/Server進(jìn)程間相互通信模型的一種同步通信形式;它對(duì)Client提供了遠(yuǎn)程服務(wù)的過程抽象,其底層消息傳遞操作對(duì)Client是透明的.在 RPC 中,Client即是請(qǐng)求服務(wù)的調(diào)用者(Caller),而Server則是執(zhí)行Client的請(qǐng)求而被調(diào)用的程序(Callee)[1,2].
這種形式的網(wǎng)絡(luò)中間件以DCOM與COBRA為代表,但無論哪種標(biāo)準(zhǔn)與實(shí)現(xiàn),均由以下部份組成.
(1)實(shí)際完成服務(wù)和功能的遠(yuǎn)程對(duì)象,負(fù)責(zé)實(shí)際完成系統(tǒng)服務(wù),接受遠(yuǎn)程請(qǐng)求.
(2)訪問客戶端代理,負(fù)責(zé)從客戶端接受請(qǐng)求,并將請(qǐng)求轉(zhuǎn)換為遠(yuǎn)程調(diào)用發(fā)送到服務(wù)端.
(3)對(duì)象請(qǐng)求代理 ORB,提供一個(gè)通信框架,透明的在異構(gòu)分布式計(jì)算環(huán)境中傳遞對(duì)象請(qǐng)求,負(fù)責(zé)定位對(duì)象實(shí)現(xiàn),并將請(qǐng)求傳輸給對(duì)象實(shí)現(xiàn)后返回結(jié)果,在分布式網(wǎng)絡(luò)中間件中處于核心地位[3,4].
基于消息的網(wǎng)絡(luò)中間件主要用于在不同應(yīng)用間投遞消息,專注于異構(gòu)環(huán)境的消息交換,目前最流行的面向消息的網(wǎng)絡(luò)中間件是Apache的ActiveMQ.
消息可不包括語意和狀態(tài),因此面向消息的網(wǎng)絡(luò)中間件對(duì)應(yīng)用而言是最透明的選擇.應(yīng)用無需關(guān)心消息的來源、連接方式,而中間件無需關(guān)心消息的語意,這樣可以很好的實(shí)現(xiàn)與應(yīng)用解耦[5–11].
此類中間件一般并不直接提供高級(jí)服務(wù),而僅僅是負(fù)責(zé)對(duì)網(wǎng)絡(luò)業(yè)務(wù)進(jìn)行封裝,降低編程復(fù)雜性,以ACE、boost.asio、libevent等為代表.
這些庫基本都實(shí)現(xiàn)了Reactor與Proactor設(shè)計(jì)模式,實(shí)現(xiàn)了高效的多路事件分離.下面以ACE庫為代表介紹其基本概念.
ACE自適配通信環(huán)境(ADAPTIVE Communication Environment)是可自由使用、開放源碼的面向?qū)ο髽?gòu)架(framework),它實(shí)現(xiàn)了許多用于并發(fā)通信軟件的核心模式.ACE提供了一組豐富的可重用C++包裝外觀(wrapper facade)和構(gòu)架組件,可跨多種平臺(tái)完成通用的通信軟件任務(wù),其中包括:事件多路分離和事件處理器分派、信號(hào)處理、服務(wù)初始化、進(jìn)程間通信、共享內(nèi)存管理、消息路由、分布式服務(wù)動(dòng)態(tài)(重)配置、并發(fā)執(zhí)行和同步等[12–16].
以上網(wǎng)絡(luò)中間件雖然都是較為成熟的框架,但并不適用于大數(shù)據(jù)量、高性能要求的時(shí)序數(shù)據(jù)處理.首先、這些框架都是通用框架,針對(duì)時(shí)序數(shù)據(jù)的鍵值對(duì)特性無法優(yōu)化,使得通訊協(xié)議過于龐大而造成資源浪費(fèi);其次、通用框架需要考慮過多的場景,因此中間件過于復(fù)雜,例如CORBA就是一個(gè)重量級(jí)框架,將會(huì)拖累整個(gè)時(shí)序數(shù)據(jù)庫部署;再次、傳統(tǒng)中間件很好的屏蔽了底層操作系統(tǒng)相關(guān)性,做到通用性和跨平臺(tái),但這是在損失一定的系統(tǒng)性能基礎(chǔ)上,因此無法滿足時(shí)序數(shù)據(jù)的大數(shù)據(jù)量和低響應(yīng)時(shí)延的要求.
本文在設(shè)計(jì)高性能中間件時(shí),提出了以下核心原則:
(1)盡量減少數(shù)據(jù)共享,以減少共享的互斥開銷.為此在中間件內(nèi)部,所有的數(shù)據(jù)都設(shè)計(jì)為線程私有,兩個(gè)線程之間不存在共享數(shù)據(jù),數(shù)據(jù)通過消息進(jìn)行傳遞,這樣減少了大量的互斥量、信號(hào)量、競爭條件等同步手段.
(2)每個(gè)線程異步且獨(dú)立運(yùn)行,一個(gè)線程對(duì)其他線程沒有時(shí)間依賴性,不存在等待其他線程的時(shí)序一致性要求.線程間的協(xié)作請(qǐng)求、中間件內(nèi)部命令也通過消息發(fā)送.每個(gè)線程維護(hù)自身的消息隊(duì)列,消息隊(duì)列除本線程外,僅有分發(fā)器可以訪問,不與其它線程共享.
(3)在本地盡量采用進(jìn)程間管道進(jìn)行通訊,在節(jié)點(diǎn)間通訊,可選點(diǎn)對(duì)點(diǎn)模式,減少中間件消息代理的負(fù)荷,提高效率并避免形成瓶頸.
根據(jù)上述原則,首先需要確定高性能中間件的并發(fā)模型,并發(fā)度的好壞決定了網(wǎng)絡(luò)中間件的性能優(yōu)劣.目前主流的并發(fā)模型有以下幾種:
表1 主流并發(fā)模型
時(shí)序數(shù)據(jù)客戶端進(jìn)程的多個(gè)連接存在相關(guān)聯(lián)的可能性很小,且多個(gè)IO線程可明顯提高系統(tǒng)資源利用率,因此必須要有良好的線程擴(kuò)展性;其次通知的異步調(diào)用有助于提高效率,線程池的設(shè)置則明顯減少了創(chuàng)建開銷.結(jié)合上述特點(diǎn)和七個(gè)方案的特性,我們最終選擇了方案7.
本文將整個(gè)系統(tǒng)內(nèi)的線程分為兩種類型:應(yīng)用線程(Application thread),在中間件以外由應(yīng)用程序創(chuàng)建的業(yè)務(wù)線程,會(huì)訪問中間件的接口函數(shù)完成功能;核心線程 (Core thread/IO Thread),在中間件內(nèi)部創(chuàng)建的線程,用于實(shí)際的功能實(shí)現(xiàn).
線程通過線程池進(jìn)行管理,根據(jù)配置預(yù)先創(chuàng)建讀線程池和寫線程池,默認(rèn)創(chuàng)建8個(gè)讀線程和8個(gè)寫線程,通過統(tǒng)一的線程管理器進(jìn)行管理.讀寫線程池依據(jù)選擇的負(fù)載均衡算法,選定具體的處理線程,并將消息放入對(duì)應(yīng)的線程消息隊(duì)列,網(wǎng)絡(luò)中間件默認(rèn)選擇的策略為均衡輪循策略.線程對(duì)象關(guān)系圖如圖1.
圖1 線程對(duì)象關(guān)系
負(fù)載均衡策略池中包含多種負(fù)載均衡策略,有均衡輪循策略、隨機(jī)均衡策略、權(quán)重隨機(jī)均衡策略、響應(yīng)速度均衡策略、最少連接數(shù)均衡策略等.讀寫線程池依據(jù)選擇的負(fù)載均衡算法,選定具體的處理線程.每一個(gè)讀寫線程池根據(jù)配置預(yù)先創(chuàng)建一定數(shù)量線程的讀線程池和寫線程池,通過統(tǒng)一的線程管理器進(jìn)行管理,使用多線程進(jìn)行IO讀寫可明顯提高系統(tǒng)資源利用率,而采用預(yù)先創(chuàng)建線程可以明顯減少后期頻繁創(chuàng)建銷毀線程的開銷.每個(gè)線程都有自己的消息隊(duì)列,從消息隊(duì)列中獲取處理報(bào)文.
2.2.1 消息格式設(shè)計(jì)
對(duì)于消息的要求一般來說比較復(fù)雜,因電力行業(yè)軟件在具有大量小尺寸應(yīng)用消息的同時(shí),也會(huì)有很多比較巨大的數(shù)據(jù)庫同步消息,同時(shí)由于消息的實(shí)際傳輸方式存在多種可能性,如兩個(gè)網(wǎng)絡(luò)節(jié)點(diǎn)間、同一節(jié)點(diǎn)的兩個(gè)應(yīng)用之間、同一進(jìn)程的兩個(gè)線程之間.對(duì)于小尺寸的消息而言,在棧上分配空間的開銷要遠(yuǎn)小于在堆中分配-析構(gòu)的開銷,因此對(duì)于小尺寸的消息應(yīng)盡量在棧上分配,同時(shí)由于大尺寸的消息容易造成棧溢出,不可在棧上分配,因此對(duì)于不同大小的消息應(yīng)提供不同的內(nèi)存分配方案.且同一幀消息,有可能被發(fā)送至不同的接收端,如果接收方處于同一進(jìn)程內(nèi),同一進(jìn)程共享地址空間,消息拷貝沒有意義;如果消息體很大,拷貝代價(jià)很高,因此對(duì)于消息應(yīng)提供引用計(jì)數(shù)的功能.
結(jié)合以上需求,對(duì)消息進(jìn)行以下設(shè)計(jì):
小尺寸消息在棧上分配,因大多數(shù)消息長度有限,如果使用內(nèi)存操作符進(jìn)行堆分配、析構(gòu),會(huì)造成性能瓶頸,也容易造成內(nèi)存空間碎片,雖然部分中間件使用預(yù)先分配、統(tǒng)一使用的方式,但在棧上分配性能更佳.
大尺寸消息在堆上分配,防止棧溢出,同時(shí)支持引用計(jì)數(shù),以避免內(nèi)存拷貝開銷,此外由于不同的應(yīng)用,不同的系統(tǒng)可能有不同的內(nèi)存管理機(jī)制,消息可支持外部特定的析構(gòu)函數(shù).
小尺寸消息在棧上分配時(shí),消息內(nèi)容直接存儲(chǔ)在msg_buffer中,msg_buffer的長度由常量在編譯時(shí)指定.設(shè)計(jì)第一個(gè)Byte為消息類型(msg_type),第二個(gè)Byte為消息大小(msg_size,最大支持256),最后為256 Byte 的消息內(nèi)容 (msg_buffer),由 msg_size 指定.消息結(jié)構(gòu)如圖2所示.
圖2 消息結(jié)構(gòu)
大尺寸消息,需要防止棧溢出,同時(shí)支持引用計(jì)數(shù)以避免大內(nèi)存拷貝開銷,采用堆上分配方式,設(shè)計(jì)第一個(gè) Byte為消息類型 (msg_type),第二個(gè) Byte為空,其后 8–256 Byte用于記錄實(shí)際數(shù)據(jù)的地址 (dest),指向的地址空間包含數(shù)據(jù)的大小(size)、函數(shù)指針(Extern Func)、引用計(jì)數(shù)(Ref counter)和數(shù)據(jù)內(nèi)容信息(User data).消息結(jié)構(gòu)如圖3所示.
圖3 消息體結(jié)構(gòu)
2.2.2 可擴(kuò)展協(xié)議設(shè)計(jì)
傳統(tǒng)的網(wǎng)絡(luò)消息格式會(huì)被設(shè)計(jì)為消息頭(Message Head)+消息體(Message)的模式.如圖4所示.
圖4 傳統(tǒng)網(wǎng)絡(luò)消息格式
為了能對(duì)消息協(xié)議進(jìn)行方便的擴(kuò)充,本文引入了多幀消息的概念,通俗的說,每個(gè)消息可以有多個(gè)消息體組成.每一幀報(bào)文長度固定,由常量在編譯時(shí)指定,消息頭也被視為一個(gè)獨(dú)立的消息幀,這樣可以通過擴(kuò)展消息幀數(shù)的方式擴(kuò)展通訊協(xié)議.如圖5所示.
圖5 多幀消息結(jié)構(gòu)
一個(gè)消息不再硬性的被區(qū)分為消息頭+消息體的機(jī)制,一個(gè)消息可以由多個(gè)消息幀組成.每個(gè)消息幀均為對(duì)等的獨(dú)立消息緩存,每一幀的大小固定.應(yīng)用與中間件可以采用擴(kuò)展消息幀的方式擴(kuò)展通訊協(xié)議,而無須破壞現(xiàn)有結(jié)構(gòu)與應(yīng)用消息結(jié)構(gòu).
基于上述可擴(kuò)展消息協(xié)議和負(fù)載均衡鏈接池并發(fā)模型,設(shè)計(jì)開發(fā)了時(shí)間序列數(shù)據(jù)庫高性能中間件組件,中間件主要包含兩個(gè)核心模塊:
OS_Wrapper為操作系統(tǒng)基礎(chǔ)接口封裝層,用于屏蔽不同操作系統(tǒng)底層調(diào)用的差異性,從而實(shí)現(xiàn)中間件的跨平臺(tái).
WP_Network為高性能中間件的核心模塊,包含了協(xié)議解析、鏈接池管理分配、負(fù)載均衡實(shí)現(xiàn)等功能,該模塊位于OS_Wrapper之上,調(diào)用了OS_Wrapper封裝的底層接口.
電力系統(tǒng)時(shí)間序列數(shù)據(jù)庫會(huì)運(yùn)行在Windows、Linux、Solaris、AIX等多種操作系統(tǒng)上,由于各個(gè)系統(tǒng)的數(shù)據(jù)類型、系統(tǒng)調(diào)用、線程管理、同步原語等均存在差異,為了保證跨平臺(tái)可移植性,采用OS_Wrapper來進(jìn)行包裝,屏蔽差異性,主要有以下類組成:
表2 OS_Wrapper主要構(gòu)成類
WP_Network是高性能中間件的核心功能模塊,其具有高性能、可擴(kuò)展協(xié)議和負(fù)載均衡等特點(diǎn),能有效節(jié)省網(wǎng)絡(luò)流量和提高響應(yīng)速率.主要由以下多個(gè)類組成:
WP_Network中包含的類較多,邏輯也比較復(fù)雜,其中各類的靜態(tài)繼承和依賴關(guān)系如圖6所示.
本文研究了時(shí)間序列數(shù)據(jù)庫所需的高性能網(wǎng)絡(luò)中間件特點(diǎn),并對(duì)其進(jìn)行了開發(fā)實(shí)現(xiàn),本文所涉及的網(wǎng)絡(luò)中間件已經(jīng)運(yùn)用于PCS-9000時(shí)間序列數(shù)據(jù)中.采用上述方案后,高性能中間件具有以下特點(diǎn):
(1)不需要為每個(gè)客戶端創(chuàng)建處理線程,降低了系統(tǒng)資源開銷,支持客戶端最大并發(fā)數(shù)顯著提高;
表3 WP_Network 主要構(gòu)成類
圖6 WP_Network 主要結(jié)構(gòu)
(2)顯著提高報(bào)文處理能力,每秒可處理500萬事件(記錄);
(3)降低了網(wǎng)絡(luò)流量,服務(wù)端占用的CPU和內(nèi)存明顯減少.
表4 與國內(nèi)外主流時(shí)間序列數(shù)據(jù)庫比較
時(shí)間序列數(shù)據(jù)庫在國內(nèi)外都有廣泛應(yīng)用,主流產(chǎn)品如海迅時(shí)間序列數(shù)據(jù)庫、PI時(shí)間序列數(shù)據(jù)庫、eDNA時(shí)間序列數(shù)據(jù)庫等.相比較,PCS-9000時(shí)間序列數(shù)據(jù)庫具有以下的優(yōu)勢(shì):
綜上所述,高性能中間件技術(shù)的引入大大提高了時(shí)間序列數(shù)據(jù)庫的處理能力,降低了系統(tǒng)和網(wǎng)絡(luò)資源的開銷,使得同樣硬件資源可以實(shí)現(xiàn)更高數(shù)據(jù)量的存儲(chǔ),具有推廣意義.