陸俊杰1,周志剛,李曉峰
(1.江南大學 物聯(lián)網工程學院,江蘇 無錫 214000; 2.中國船舶科學研究中心,江蘇 無錫 21400)
以試驗平臺為載體搭載各種試驗系統(tǒng)與設備,對試驗平臺的關鍵共性技術與專有技術進行集中的試驗驗證,對其經濟性、可行性、適用性、安全性、可靠性等方面進行檢驗及評估,為特定產品的設計、建造和運行維護提供堅實的技術基礎及指導依據(jù),形成技術研究與工程示范相結合的重大成果。
浮式保障平臺的驗證項目涉及到眾多內容和技術門類,根據(jù)研究內容,可將平臺試驗驗證子系統(tǒng)劃分為如下內容:腐蝕監(jiān)檢測系統(tǒng)、浮式防波堤測量系統(tǒng)、波浪能發(fā)電性能測試系統(tǒng)、結構安全監(jiān)測系統(tǒng)、環(huán)境監(jiān)測系統(tǒng)和系統(tǒng)總體概覽。根據(jù)各個子系統(tǒng)的驗證要求需要采集的數(shù)據(jù)參數(shù)種類及數(shù)目繁多,并且數(shù)據(jù)無法實現(xiàn)互聯(lián)互通,由此數(shù)據(jù)采集系統(tǒng)的設計目標就是要實現(xiàn)數(shù)據(jù)參數(shù)的集中顯示和管理功能。
現(xiàn)如今有許多種不同的數(shù)據(jù)采集系統(tǒng)的設計但在各方各面都存在著缺點。在基于多線程的航空發(fā)動機數(shù)據(jù)采集系統(tǒng)中,采用多線程的方式結合MFC進行系統(tǒng)設計,其缺點是:1)與Actor模型自身高并發(fā)的特性相比較,會產生大量的代碼花銷占用內存[1];2)相較于采用WPF,MFC這款編程框架無論在運行速度、開發(fā)成本等性能上都不能比擬。在基于虛擬儀器的風洞數(shù)據(jù)采集系統(tǒng)中,其缺點是系統(tǒng)耦合度高導致容錯率低不易維護[2]。另外,在相同條件下使用基于C#的委托和事件的觀察者模式,與Actor模型相比較同樣存在系統(tǒng)耦合度高、不易升級維護的缺陷。從上述各種采集系統(tǒng)的設計發(fā)現(xiàn)大多數(shù)系統(tǒng)不能有效地解決內存花銷大以及降低解耦度的問題,而利用Actor模型可以解耦系統(tǒng),增加復用性,避免堵塞,尤其是像這種分布式系統(tǒng)可以提高并發(fā)性能[3],易于升級和維護。
本文將介紹基于Actor模型的浮式保障平臺數(shù)據(jù)采集系統(tǒng)的設計與實現(xiàn),對系統(tǒng)中各個功能點的測試驗證設計方案的可行性并且達到預期的設計目標。浮式保障平臺數(shù)據(jù)采集系統(tǒng)將采用Akka.Net框架來設計派生自基類Actor的各類子系統(tǒng)模塊。在各子系統(tǒng)模塊內自定義Actor類的消息類型用以傳遞各類子系統(tǒng)的參數(shù)數(shù)據(jù),通過Actor類與控件類的關聯(lián)實現(xiàn)數(shù)據(jù)的實時顯示以及不同控件類的交互。
Actor模型最早是由Carl Hewitt于1973提出[4]來的一個關于并發(fā)和分配問題的開創(chuàng)性概念。通過引用單個原語稱之為Actor,并用于并發(fā)和分布式實體,這種方法提供的高級抽象結合其靈活性和效率使其對當今的彈性多核系統(tǒng)以及在Internet規(guī)模上分發(fā)的任務具有極大的吸引力[5]。
Actor模型采用萬物皆可建模為Actor的理念[6],所有邏輯或者模塊均可被看作Actor,它們彼此之間可以直接發(fā)送消息,不需要通過什么中介,并且是異步發(fā)送和處理的。因而通過不同Actor之間的消息傳遞實現(xiàn)模塊之間的通信和交互。Actor模型具有許多特性,例如它的狀態(tài)是本地的,無法通過外部訪問;所有的Actor必須有響應消息傳遞來通信;異步非阻塞的事件驅動編程模型等等。最值得稱贊的是Actor模型在實現(xiàn)過程中將十分輕量,可以快速的批量創(chuàng)建和銷毀,“幾十萬甚至上百萬進程同時并行運行十分常見, 而且經常僅僅占用很少的內存”[6]。正是由于Actor具有如此多的特性和優(yōu)點,因而能夠克服傳統(tǒng)面向對象編程程序的局限性,高度滿足并發(fā)和分布式系統(tǒng)的挑戰(zhàn)。
浮式保障平臺數(shù)據(jù)采集系統(tǒng)的軟件部分在數(shù)據(jù)流的本質上是符合Actor模型的[7],這類系統(tǒng)都是通過相關配置信息的計算與處理來實現(xiàn)所需物理量的監(jiān)測和采集,從而根據(jù)各類控件實現(xiàn)數(shù)據(jù)的顯示以及后續(xù)利用配置信息與采集數(shù)據(jù)的運算和分析存儲。因此整個系統(tǒng)可以視作是一個流處理的系統(tǒng)[8],在每一步的環(huán)節(jié)都可以建立Actor模型來處理和傳遞數(shù)據(jù),提高各類專業(yè)化的數(shù)據(jù)采集子系統(tǒng)的解耦性,并且易于升級改造和維護。整個流處理系統(tǒng)被Actor強制組織成一個樹狀的層次結構,根據(jù)模型的監(jiān)督特性和傳遞消息的特殊性而減少出錯以及避免線程的鎖定和堵塞,從而保障整個系統(tǒng)的安全可靠并且降低升級維護的難度。
這里要詳細描述一下浮式保障平臺數(shù)據(jù)采集系統(tǒng)的業(yè)務架構,從而可以利用Actor模型去搭建完整的Actor系統(tǒng)。系統(tǒng)完整的業(yè)務架構如圖1所示。
圖1 系統(tǒng)業(yè)務架構
正如上文引言介紹,浮式保障平臺有6個子系統(tǒng)功能,接下來將一一介紹業(yè)務架構中各子系統(tǒng)的功能。
1)系統(tǒng)總體作為子系統(tǒng)其主要功能是顯示各功能子系統(tǒng)下主要的數(shù)據(jù),達到概覽系統(tǒng)總體的功能。
2)環(huán)境監(jiān)測系統(tǒng)最主要的功能是采取波浪騎士以及常用環(huán)境傳感器來收集平臺周圍的溫濕度以及有關波浪的參數(shù)。
3)結構安全監(jiān)測系統(tǒng)的功能是驗證監(jiān)測系統(tǒng)性能,收集近島礁的實測參數(shù)為后續(xù)的驗證研究提供支撐。
4)腐蝕建監(jiān)測系統(tǒng)用于配合海上試驗平臺進行腐蝕防護的試驗驗證,檢驗腐蝕防護設計的合理性,為保障平臺的安全運行提供可靠的腐蝕監(jiān)測數(shù)據(jù)。
5)防波提測量系統(tǒng)用于配合試驗平臺進行防波堤的海上試驗驗證,進一步檢驗所設計的防波堤構型和消浪機理的合理性,掌握浮式防波堤運動響應與消浪特點,為保障演示驗證平臺的安全運行提供可靠的環(huán)境測量數(shù)據(jù)。
6)波浪能發(fā)電性能測試系統(tǒng)主要用于實時監(jiān)測浮式防波堤波浪能發(fā)電裝置內外部運行環(huán)境參數(shù),采集發(fā)電裝置電功率參數(shù),為保障波浪能裝置及其配套設備的安全運行提供可靠的環(huán)境測量數(shù)據(jù)。
通過以上6個子系統(tǒng)的詳細介紹可以發(fā)現(xiàn)每一個子系統(tǒng)都需要將大量的參數(shù)數(shù)據(jù)進行監(jiān)控顯示,為了方便集中化地監(jiān)控查看從而需要設計一套數(shù)據(jù)采集系統(tǒng)可以全面詳細的顯示、存儲參數(shù)數(shù)據(jù),在結合以往的工程應用的基礎上,采用基于Actor模型的數(shù)據(jù)采集系統(tǒng)以達到所需設計要求。
本文采用Akka.Net開源庫來編寫實現(xiàn)浮式保障平臺數(shù)據(jù)采集系統(tǒng)中的Actor模型。Actor是封裝狀態(tài)和行為的對象,它的基本元素是演員(Actor)和消息(message)[9],它們只是通過交換放入收件人郵箱的消息進行通信[10],并且具有嚴格的等級制度,從而達到其監(jiān)督特性。因此在創(chuàng)建之前需要初始化一個Actor系統(tǒng),用來層層創(chuàng)建和管理各子Actor。
創(chuàng)建Actor模型最核心的是使用開源庫中的Actor類,它維護著單個Actor的狀態(tài),其中主要功能為自定義創(chuàng)建子Actor的數(shù)量、根據(jù)消息類型做出不同的響應、選擇相同Actor系統(tǒng)下其他Actor的傳遞對象。因而我們采用Prop(配置類,封裝自定義類型Actor實例所需的所有信息)配方創(chuàng)建Actor。
對于每一個Actor都有其獨有的命名,但是它們的類型只有兩種即UntypedActor和ReceiveActor。這兩種類型的差異就是對消息處理方式的不同。換種說法,Actor在Akka.Net開源庫中主要依賴于類似模式匹配的概念(能夠根據(jù)其.Net類型和/或值有選擇性的處理消息),在設計上UntypedActor和ReceiveActor類型能夠分別處理簡單和更為復雜的消息匹配。UntypedActor類通過onReceive方法實現(xiàn)消息的接收,其中消息作為參數(shù),這是一種較為簡單的方法;而ReceiveActor類內部可以為每一種要處理的消息類型提供調用,優(yōu)點在于處理較為復雜的消息處理并且具有與其他類交互的性能。這兩種類的不同決定著在實際應用中采取哪一種類來進行Actor的創(chuàng)建。
在創(chuàng)建的每一個Actor類中我們可以繼而創(chuàng)建新的Actor,兩者之間形成父子關系,這么做的目的就回歸到為什么一個Actor系統(tǒng)是層級結構的?原因有兩個,其一是將任務層層分解分配直至最低級以便一體化處理,也就是通過最小的代碼占用最容易的處理。另一個原因是監(jiān)督特性,層級結構可以將整個Actor系統(tǒng)的風險降到最低,當某一層級的某一個Actor出現(xiàn)問題,其父Actor會接收到消息并關閉這一分支,從而不影響其他的運行,提高整個系統(tǒng)的安全性。
在Actor模型中使用Tell()方法來發(fā)送消息,括號內自定義消息類型和內容從而達到萬物皆可傳遞的特性。與此同時,如何能夠實現(xiàn)一對一或者一對多傳遞等情況十分重要。因而需要Akka.Net中的ActorSelection類的幫助,通過查找路徑的方式可以最直接地與同一系統(tǒng)下任何層級的任何Actor進行通信,并且ActorSelection類只是獲取句柄的方式來完成查找降級代碼的占用。
圖2描述了一個名叫ActorSystem的簡易Actor系統(tǒng),
里面有最頂級即最上層的Actor,它的名字叫A,Actor的類名為ParentActor,并且創(chuàng)建了子Actor取名為B,Actor的類名為ChildActor。在這里要介紹一下Actor的重要組成-郵箱。Actor之間的通信并不是直接發(fā)送給Actor,而是發(fā)送給該Actor內的郵箱,也可以描述為消息隊列,按照先后順序在Actor有時間的情況下一一傳遞給它來處理。如果要實現(xiàn)向B傳遞消息則需要查找傳遞路徑,根據(jù)圖中的關系可以得到“akka://ActorSystem/user/A/B”這一路徑就是我們需要的,可以通過路徑直接與B通信,以這種方式去通信是最快捷有效的方式,只要在同一個Actor系統(tǒng)下無論是在哪個分支都可以通信。
圖2 簡易Actor系統(tǒng)的創(chuàng)建和消息傳遞
本章將根據(jù)上述的系統(tǒng)架構來搭建應用于浮式保障平臺的數(shù)據(jù)采集系統(tǒng)。具體的系統(tǒng)架構如圖3所示。
圖3 Actor系統(tǒng)的結構
和上文所述的系統(tǒng)架構有所不同的是,在實際創(chuàng)建過程中數(shù)據(jù)采集Actor與總體界面Actor為兄弟關系,都是根Actor,但這不影響整個系統(tǒng),反而可以使層次架構更為清晰,一個專門負責處理最原始的數(shù)據(jù),另一個專門用來作為中轉和分發(fā)站,向所有子系統(tǒng)Actor傳遞數(shù)據(jù)。
在數(shù)據(jù)采集Actor中有processDataActor類和displayDataActor類兩個父子Actor類,先后分別用來處理不同來源的原始數(shù)據(jù)和將相同子系統(tǒng)的參數(shù)數(shù)據(jù)歸類放入一個存放數(shù)據(jù)容器內,最終將完整的數(shù)據(jù)參數(shù)集通過Actor路徑傳遞給總體頁面Actor。
_subscriptions = new HashSet
IActorRef actor1= Context.ActorOf(Props.Create(() => new WindWavePageActor()), "windWavePageActor");
IActorRef actor2 =Context.ActorOf(Props.Create(() => new HomePageActor()), "homePageActor");
IActorRef actor3 = Context.ActorOf(Props.Create(() => new StructurePageActor()), "structurePageActor");
IActorRef actor4 = Context.ActorOf(Props.Create(() => new GroynePageActor()), "groynePageActor");
IActorRef actor5 = Context.ActorOf(Props.Create(() => new ErosionPageActor()), "erosionPageActor");
IActorRef actor6 = Context.ActorOf(Props.Create(() => new WavePowerPageActor()), "wavePowerPageActor");
_subscriptions.Add(actor1);
_subscriptions.Add(actor2);
_subscriptions.Add(actor3);
_subscriptions.Add(actor4);
_subscriptions.Add(actor5);
_subscriptions.Add(actor6);
pageActor類作為總體頁面Actor,最主要的任務就是作為消息中轉站,不斷地將接受到的消息遍歷傳遞給所有的子Actor。以下為創(chuàng)建子系統(tǒng)Actor的過程并且逐一放入HashSet
在每一個子系統(tǒng)Actor內,都將會根據(jù)收到的消息來創(chuàng)建控件Actor、傳遞參數(shù)數(shù)據(jù),因而舉例詳細介紹一下子系統(tǒng)homePageActor類及子Actor的消息傳遞過程,并且在命名系統(tǒng)主頁子系統(tǒng)Actor時名字和類名一樣,所以下文所有出現(xiàn)的homePageActor即是Actor的名字,否則會有特殊說明。homePageActor與系統(tǒng)主頁homePage類相互關聯(lián),在頁面初始化過程中創(chuàng)建的每一個控件都將會給homePageActor發(fā)送一個自定義的創(chuàng)建消息。其中內容包含譬如控件名稱描述的字符串、控件自身的類以及次序數(shù)字等,針對這種包含種類多較為復雜的消息類型,在homePageActor類中只能自定義message消息類,將例如字符串、值以及其他類在消息類中進行實例化。因而只需要將所需要傳遞的內容一一放入自定義的消息類中,隨即將整個消息類的實例作為message傳遞給homePageActor,就能實現(xiàn)復雜的通信過程并且進行控件Actor的創(chuàng)建。圖4就是創(chuàng)建控件Actor的過程。
圖4 創(chuàng)建控件Actor的過程
在創(chuàng)建完所有的控件Actor之后就將進行另一功能的運行。homePageActor會將接收到的來自父Actor也就是pageActor發(fā)送的消息進行過濾,選取符合自身子系統(tǒng)的參數(shù)數(shù)據(jù)繼而進行下一層級Actor的傳遞,從而起到一個中轉過濾的作用。在這里需要重點介紹的不是消息的傳遞,而是一種構成方法,即將Actor類與控件類進行交互也就是創(chuàng)建一種將控件類對象作為參數(shù)的Actor類,而這種構成方法只能在 ReceiveActor類生效,采用ReceiveActor類而不是UntypedActor類的優(yōu)勢在于可以對有關數(shù)據(jù)調用控件類的方法處理并且直接在控件類的參數(shù)中賦值修改,減少了許多額外的代碼占用。一旦控件Actor接收到消息,根據(jù)消息類型判斷為顯示數(shù)據(jù)時,就能將數(shù)據(jù)傳入控件類的事件進行處理繼而存放入控件的動態(tài)集合中進行刷新顯示最終呈現(xiàn)出來。
圖5展示了表格控件通過Actor顯示數(shù)據(jù)的效果。其中第一列為參數(shù)名稱,第三列為單位,這兩列是固定不變的顯示,不會被刷新變化;而第二列是參數(shù)數(shù)值以及第四列為數(shù)值狀態(tài)描述,從控件Actor傳遞到控件內的數(shù)據(jù)主要就是刷新這兩列的數(shù)值顯示。在這表格顯示的基礎上,增加了表格控件和曲線控件的交互,其功能為通過鼠標點擊表格的單元格實現(xiàn)曲線控件顯示選中單元格內參數(shù)數(shù)值隨時間變化的曲線圖。這和表格顯示數(shù)據(jù)的相似之處在于利用Actor傳遞消息的方法來取代C#語法中傳統(tǒng)的異步委托事件的方法。這兩者之間的比較不難看出,使用委托一旦綁定的事件越多,內存占用就越多,對性能的影響越大,在這方面Actor模型的并行和分布式特點使得占用內存會少很多,因而在面對高吞吐和低延遲的系統(tǒng)要求下,Actor模型要更加的出色。
圖5 表格控件效果圖
表格和曲線控件的交互流程如圖6所示。在創(chuàng)建控件Actor時,曲線Actor將自己的名字通過字符串的消息類型發(fā)送給表格Actor,然后在表格控件內保存有曲線Actor的路徑參數(shù)。當在表格的鼠標點擊響應事件激活時,將參數(shù)集合作為消息發(fā)送給曲線Actor,同樣的原理下,曲線控件接收到數(shù)據(jù)利用一系列的處理實現(xiàn)顯示。
圖6 表格與曲線的交互
本文所設計的系統(tǒng)最終部署在浮動平臺上,根據(jù)對各系統(tǒng)所上傳數(shù)據(jù)的頻率,實現(xiàn)大部分數(shù)據(jù)的刷新速率為1秒,少部分達到50毫秒。經過測試,軟件能夠正常接收并顯示各子系統(tǒng)的實時數(shù)據(jù),不存在數(shù)據(jù)丟失的情況,曲線的繪制效果良好,表格與曲線的交互并無延遲,即點即繪制,與此同時軟件的內存占用從原有的1 G多降低至600~700 MB。軟件運行效果如圖7所示。
圖7 數(shù)據(jù)采集系統(tǒng)的顯示效果
本文介紹了浮式保障平臺項目的內容以及對比各種數(shù)據(jù)采集系統(tǒng)的優(yōu)劣特性,結合Actor模型以及相關技術,設計并實現(xiàn)了基于Actor模型的浮式保障平臺數(shù)據(jù)采集系統(tǒng),具體的工作內容如下:
1)詳細介紹Actor模型以及Akka.NET開發(fā)庫中的Actor類。
2)詳細介紹浮式保障平臺數(shù)據(jù)采集系統(tǒng)的業(yè)務架構。
3)詳細介紹整體系統(tǒng)的實現(xiàn)過程并展示實現(xiàn)效果。
在系統(tǒng)的實際運行中可以發(fā)現(xiàn)采用Actor模型能夠模塊化地建立一條數(shù)據(jù)采集和傳輸?shù)耐?,最明顯的優(yōu)勢在于提高容錯率,易于維護,層級化的Actor模塊之間不會因為一條通信線路的問題導致全部失效。在開發(fā)過程中使用Actor模型較以往減少了代碼占用,并且可以更加便捷地修改和升級,提高開發(fā)效率。在利用Actor模型作為載體傳遞不間斷的數(shù)據(jù)時可以發(fā)現(xiàn)在高并發(fā)和分布式的系統(tǒng)中,Actor模型之間的傳遞速度十分優(yōu)異并且多線程、異步發(fā)送消息的特性使得系統(tǒng)真正意義上的成為分布式的系統(tǒng)。通過Actor模型的傳遞,數(shù)據(jù)參數(shù)最終將在表格控件中顯示,可以清晰的看到控件內數(shù)據(jù)值以初始設定的采樣速率不斷地刷新,達到預計的采集和顯示效果。在整個過程中,浮式保障平臺數(shù)據(jù)采集系統(tǒng)穩(wěn)定高效地完成數(shù)據(jù)的采集和顯示功能,并且相較于傳統(tǒng)的委托傳值的方法降低了計算機內存的消耗,證明了基于Actor模型的數(shù)據(jù)采集系統(tǒng)的可行性。
Actor模型現(xiàn)在已經廣泛成為高并發(fā)事物的首要解決方案,與此同時并發(fā)分布式的數(shù)據(jù)采集系統(tǒng)以往的設計思路并不能很好地解決性能上的缺陷,因而Actor模型與數(shù)據(jù)采集系統(tǒng)的結合是必然。在此次設計與實現(xiàn)中發(fā)現(xiàn)系統(tǒng)仍有改進優(yōu)化的方面,因而未來基于Actor模型的數(shù)據(jù)采集系統(tǒng)的工作可以包括以下幾個方面:
1)由于Actor模型的消息通信的機制,在萬物皆是Actor的理念下,有更多類與類之間的交互可以通過Actor模型來實現(xiàn);Actor具有延時發(fā)送的功能,在數(shù)據(jù)傳輸?shù)拈_發(fā)中可以根據(jù)特定的情況利用這一功能實現(xiàn)連續(xù)間隔的發(fā)送接收。
2)目前基于Actor模型的數(shù)據(jù)采集系統(tǒng)使用的只是本地的數(shù)據(jù)傳輸,由于Actor模型具有遠程傳輸?shù)墓δ苣K,可以將這方面的功能結合現(xiàn)有技術開發(fā)來優(yōu)化數(shù)據(jù)的采集傳輸,在數(shù)據(jù)采集系統(tǒng)上會有廣闊的前景。
3)Actor模型隨著發(fā)展已經具有多種語言的支持,因而在追求高速、低耗和強穩(wěn)定的性能指標下,將測試基于c++、Erlang等不同種語言下的Actor的性能,尋求最適用的一種。