李 軍,王 娜,劉志勇,宋祎寧,楊 壘,王吉利
(1. 中國(guó)科學(xué)院新疆天文臺(tái),新疆 烏魯木齊 830011;2. 中國(guó)科學(xué)院大學(xué),北京 100049;3. 中國(guó)科學(xué)院射電天文重點(diǎn)實(shí)驗(yàn)室,江蘇 南京 210033)
射電望遠(yuǎn)鏡是射電天文研究的基礎(chǔ),它由天線、接收機(jī)、終端、監(jiān)測(cè)和控制等系統(tǒng)組成,其中,具有連接、集成和管理功能的控制系統(tǒng)是射電望遠(yuǎn)鏡的重要組成部分[1]。數(shù)據(jù)交換是控制系統(tǒng)的基本功能之一,在望遠(yuǎn)鏡控制與多終端數(shù)據(jù)交換過(guò)程中,需要保證穩(wěn)定可靠的同時(shí)兼?zhèn)涓咝Ш屯ㄓ?。?duì)于將要建設(shè)的新疆奇臺(tái)110 m射電望遠(yuǎn)鏡(QiTai Radio Telescope, QTT),各設(shè)備之間通信數(shù)據(jù)大小由觀測(cè)波段和觀測(cè)模式?jīng)Q定,它們之間的單次數(shù)據(jù)通信量一般小于1 kB。天線伺服控制的數(shù)據(jù)通信最頻繁,數(shù)據(jù)交換頻率約為20 Hz,單次數(shù)據(jù)交換大小約200 B,其他設(shè)備的數(shù)據(jù)交換頻率約1 Hz。主動(dòng)面運(yùn)行時(shí),數(shù)據(jù)通信量約10 kB,電磁監(jiān)測(cè)的數(shù)據(jù)通信量一般為10~100 kB。110 m射電望遠(yuǎn)鏡控制系統(tǒng)擬采用分布式架構(gòu),各子系統(tǒng)之間的數(shù)據(jù)交換包含多種方式,如Linux,Windows,VxWorks,Unix和嵌入式等系統(tǒng)之間的信息傳輸;網(wǎng)絡(luò)的大端模式與機(jī)器的小端模式之間的信息傳輸;C++與Python之間的信息交換等。其中,大端模式的機(jī)器與小端模式的機(jī)器傳輸信息時(shí),long類型數(shù)據(jù)的前后字節(jié)互換。為了解決系統(tǒng)之間傳輸信息的數(shù)據(jù)格式問(wèn)題,序列化工具將射電望遠(yuǎn)鏡系統(tǒng)之間的傳輸信息編碼為統(tǒng)一格式。因此,序列化工具作為控制系統(tǒng)傳輸信息格式的基礎(chǔ),可以實(shí)現(xiàn)射電望遠(yuǎn)鏡軟硬件系統(tǒng)之間的信息傳輸。
現(xiàn)有的射電望遠(yuǎn)鏡控制系統(tǒng)大多使用序列化技術(shù)[2]。如阿塔卡馬大型毫米陣列(Atacama Large Millimeter Array, ALMA)的控制系統(tǒng)架構(gòu)結(jié)合文本序列化工具XML(Extensible Markup Language)作為控制系統(tǒng)傳輸信息編碼和解碼的基礎(chǔ)[3];澳大利亞平方公里矩陣探路者(Australian Square Kilometre Array Pathfinder, ASKAP)的監(jiān)控系統(tǒng)使用網(wǎng)絡(luò)通信引擎(Internet Communications Engine, ICE)提供的序列化技術(shù),完成不同射電望遠(yuǎn)鏡軟硬件系統(tǒng)之間的信息傳輸[4];巨型米波射電望遠(yuǎn)鏡(Giant Metrewave Radio Telescope, GMRT)監(jiān)控系統(tǒng)以Tango控制系統(tǒng)為基礎(chǔ),結(jié)合XML實(shí)現(xiàn)系統(tǒng)傳輸信息的編碼和解碼[5]。為了解決望遠(yuǎn)鏡控制系統(tǒng)之間信息傳輸?shù)母袷絾?wèn)題,文[6]提出了以通信中間件ZeroMQ和文本序列化工具JSON(JavaScript Object Notation)為望遠(yuǎn)鏡自動(dòng)控制系統(tǒng)的通信框架。
序列化工具中,XML和JSON是文本型序列化工具,廣泛應(yīng)用于互聯(lián)網(wǎng)軟件系統(tǒng),以及早期射電望遠(yuǎn)鏡控制系統(tǒng)的應(yīng)用層與服務(wù)層之間的數(shù)據(jù)交換。在射電望遠(yuǎn)鏡控制系統(tǒng)的使用過(guò)程中,我們發(fā)現(xiàn)XML和JSON存在一些不足,如內(nèi)存使用率高,數(shù)據(jù)類型精度易缺失,難以實(shí)現(xiàn)底層設(shè)備驅(qū)動(dòng)程序與服務(wù)之間的數(shù)據(jù)交換[7]。于是實(shí)驗(yàn)物理裝置、射電望遠(yuǎn)鏡等底層與服務(wù)層之間的通信逐漸被二進(jìn)制序列化工具M(jìn)sgpack,Protobuf和Flatbuffers[8-9]替代,它們可以更好地解決數(shù)據(jù)精度缺失、底層與服務(wù)層之間的數(shù)據(jù)交換效率等問(wèn)題。本文著重分析Msgpack,Protobuf和Flatbuffers 3款二進(jìn)制序列化工具的編碼原理、特性,通過(guò)測(cè)試、比較和分析它們的序列化數(shù)據(jù)大小、序列化時(shí)間和中央處理器利用率,兼顧底層、服務(wù)層和應(yīng)用層,選擇適合射電望遠(yuǎn)鏡控制系統(tǒng)的序列化工具,以提高控制系統(tǒng)的信息傳輸效率,保證射電望遠(yuǎn)鏡系統(tǒng)信息傳輸格式的統(tǒng)一性和兼容性。
序列化工具由編碼(又稱序列化)和解碼(又稱反序列化)構(gòu)成。序列化是將結(jié)構(gòu)化數(shù)據(jù)(或?qū)ο?編碼為字節(jié)流;反序列化則是將字節(jié)流還原成原始的結(jié)構(gòu)化數(shù)據(jù)(或?qū)ο?。
使用序列化工具構(gòu)建射電望遠(yuǎn)鏡控制系統(tǒng)時(shí),我們需要分析它的編碼原理和特性。不同的編碼方式影響序列化數(shù)據(jù)大小、序列化時(shí)間、中央處理器利用率等。本節(jié)后續(xù)部分以圖1的JSON數(shù)據(jù)為例分析Msgpack,Protobuf和Flatbuffers的編碼原理。
圖1 JSON格式示例Fig.1 An example of JSON schema
Msgpack是一款支持多語(yǔ)言、跨平臺(tái)、具有動(dòng)態(tài)編譯的二進(jìn)制序列化工具,編碼對(duì)象(或結(jié)構(gòu)化數(shù)據(jù))之后的字節(jié)流具有緊湊、簡(jiǎn)潔的特點(diǎn)。字節(jié)流由頭字節(jié)、前綴字節(jié)和數(shù)據(jù)字節(jié)構(gòu)成。頭字節(jié)表示之后緊跟的數(shù)據(jù)類型和類型個(gè)數(shù);前綴字節(jié)表示其后的數(shù)據(jù)類型;數(shù)據(jù)字節(jié)表示對(duì)象的內(nèi)容,如基本類型bin,float和uint,結(jié)構(gòu)化類型str,array和map,擴(kuò)展類型ext和fixext等。其中,字符串str不使用任何標(biāo)記(或任何轉(zhuǎn)義字符)表示內(nèi)容結(jié)束。
Msgpack的編碼方式包括兩種:第1種方式使用Msgpack編碼key-value值(這種方式簡(jiǎn)寫為MSGP-M),需要先編碼key值,再編碼value值。圖2和圖3分別表示MSGP-M編碼圖1的JSON數(shù)據(jù)之后得到的邏輯圖和字節(jié)流圖。邏輯圖為編碼之后的數(shù)據(jù)表示形式;字節(jié)流圖則是編碼之后各字節(jié)的先后順序,如83為第1個(gè)字節(jié)。字節(jié)流由7部分組成:(1)第1個(gè)字節(jié)(83)的前4位(1000)表示編碼的數(shù)據(jù)類型為map,后4位(0011)表示后續(xù)包含3個(gè)map對(duì)象。(2)第2個(gè)字節(jié)為第1個(gè)map對(duì)象中key值的前綴字節(jié)(A5),表示后續(xù)包含5個(gè)str對(duì)象;第3~第7個(gè)字節(jié)以ASCII碼表示map對(duì)象中的key值 “names”。(3)第8個(gè)字節(jié)(A5)表示后續(xù)包含5個(gè)字符串;第9~第13個(gè)字節(jié)使用ASCII碼表示字符串 “zhang”。(4)第14個(gè)字節(jié)表示第2個(gè)map對(duì)象中key值的前綴字節(jié)(A3),表明后續(xù)包含3個(gè)字符串;第15~第17個(gè)字節(jié)以ASCII碼表示字符串 “num”。(5)第18個(gè)字節(jié)為第2個(gè)map對(duì)象value值的前綴字節(jié)(CD),表明其后緊跟2個(gè)字節(jié)的無(wú)符號(hào)整數(shù);第19~第20個(gè)字節(jié)則以大端模式表示數(shù)字 “1331”。(6)第21個(gè)字節(jié)表示第3個(gè)map對(duì)象的key值前綴字節(jié)(A8),表示后續(xù)包含8個(gè)字符串;第22~第29字節(jié)使用ASCII表示字符串 “descript”。(7)第30個(gè)字節(jié)(AF)為第3個(gè)map對(duì)象的value值的前綴字節(jié)(A5),表示后續(xù)包含15個(gè)字符串;第31~第45字節(jié)表示字符串 “inthefirstnicks”。
圖2 MSGP-M對(duì)JSON格式中key-value值編碼之后的邏輯圖Fig.2 Logic diagram after MSGP-M encodes the key-value in JSON format
圖3 MSGP-M對(duì)JSON格式中key-value值編碼之后的字節(jié)流圖Fig.3 MSGP-M encodes byte stream after the key-value in the JSON format
第2種使用Msgpack編碼JSON格式中的value值(序列化結(jié)果以數(shù)組表示)。這種方式的Msgpack縮寫為MSGP-D。MSGP-D編碼圖1的JSON數(shù)據(jù)之后得到的邏輯圖和字節(jié)流圖如圖4和圖5,包括4部分:(1)第1個(gè)字節(jié)(0X93)表示后續(xù)包含3個(gè)array對(duì)象。(2)第2個(gè)字節(jié)(0XA5)表示后續(xù)包含5個(gè)字符串;第3~第7字節(jié)使用ASCII表示字符串 “zhang”。(3)第8個(gè)字節(jié)(0XCD)表明后續(xù)包含一個(gè)16位無(wú)符號(hào)整數(shù);第9~第16字節(jié)以大端模式的二進(jìn)制形式表示數(shù)字 “1331”。(4)第11字節(jié)(0XAF)后續(xù)包含15個(gè)字符串;第12~第26字節(jié)用ASCII表示字符串 “inthefirstnicks”。
圖4 MSGP-D對(duì)JSON格式中value值編碼后的邏輯圖Fig.4 Logic diagram after MSGP-D encodes value in JSON format
Protobuf(PB)是一款開(kāi)源、支持多語(yǔ)言、跨平臺(tái)、提供接口描述語(yǔ)言(Interactive Data Language, IDL)的二進(jìn)制序列化工具。PB編碼傳輸信息時(shí),需定義IDL的鍵和字段,以生成指定編程語(yǔ)言代碼,如C++,Python等。使用PB編碼數(shù)據(jù)后,得到的字節(jié)流由鍵、前綴字節(jié)和數(shù)據(jù)字節(jié)組成。鍵分為標(biāo)記數(shù)字和標(biāo)記類型,標(biāo)記數(shù)字將常用元素標(biāo)記為1~15,不常用元素標(biāo)記為16~2047;標(biāo)記類型包括string,float等。鍵可以對(duì)IDL文件中的數(shù)據(jù)類型進(jìn)行唯一標(biāo)記,標(biāo)記后的數(shù)據(jù)類型不能更改。
圖6和圖7分別為PB編碼圖1的JSON數(shù)據(jù)之后得到的邏輯圖和字節(jié)流圖。其中,字節(jié)流占用空間為27字節(jié),由3部分組成:(1)第1個(gè)字節(jié)(0A)中的第2位到第5位(0001)為數(shù)字標(biāo)記,后3位(010)表示數(shù)據(jù)類型為string;第2個(gè)字節(jié)(05)表示后續(xù)包含5個(gè)string對(duì)象;第3~第7字節(jié)以ASCII的形式表示字符串 “zhang”。(2)第8個(gè)字節(jié)(10)表示后續(xù)包含一個(gè)整型的數(shù)據(jù);第9~第10個(gè)字節(jié)是以小端模式表示16位的無(wú)符號(hào)整數(shù) “1331”。(3)第11個(gè)字節(jié)(10)表示后續(xù)包含字符串;第12個(gè)字節(jié)(0F)則表示后續(xù)包含15個(gè)字符串;第13~第27字節(jié)表示字符串 “inthefirstnicks”。
圖7 Protobuf對(duì)JSON格式中value值編碼后的字節(jié)流圖Fig.7 Protobuf encodes the result of value in JSON format
Flatbuffers(FB)是一款支持多語(yǔ)言、跨平臺(tái)、提供IDL的二進(jìn)制序列化工具。FB具備良好的兼容性,如系統(tǒng)添加新功能時(shí),新字段只能在IDL文件末尾添加,且舊字段仍會(huì)正常讀??;數(shù)據(jù)在內(nèi)存中的格式與編碼格式一致;反序列化過(guò)程支持零拷貝,便于快速讀取數(shù)據(jù)。FB序列化字節(jié)流包括int,string等標(biāo)量和struct,table等矢量。標(biāo)量由固定長(zhǎng)度的以小端模式表示的整型(8~64位)和浮點(diǎn)型構(gòu)成;矢量由字符串和數(shù)組構(gòu)成,開(kāi)頭必須是一個(gè)32位長(zhǎng)度的VECTOR SIZE來(lái)指明矢量長(zhǎng)度(不包括 ‘