呂海東
(大連理工大學(xué), 城市學(xué)院, 遼寧, 大連 116600)
當(dāng)今世界,隨著監(jiān)測設(shè)備和控制設(shè)備日益大規(guī)模增加,尤其是物聯(lián)網(wǎng)(IoT)的迅猛發(fā)展[1],工業(yè)過程控制系統(tǒng)變得越來越復(fù)雜,已經(jīng)由傳統(tǒng)的集中控制模式,全面轉(zhuǎn)變?yōu)榉植际娇刂颇J健?/p>
傳統(tǒng)的控制系統(tǒng)通常可以控制幾百或幾千的傳感器和執(zhí)行設(shè)備,再多就感到力不從心,系統(tǒng)性能嚴(yán)重下降,實時性難以滿足實際需求。如一個大城市的交通信號控制系統(tǒng),智慧城市控制系統(tǒng),需要控制的各種設(shè)備可能超過幾十萬,甚至上百萬。
為了克服多線程編程復(fù)雜,難以實現(xiàn)真正的高并發(fā)性,高可靠性和實時性的問題,Lightbend推出了著名的Akka框架[2]。Akka為構(gòu)建分布式、異步、高性能的實時系統(tǒng)提供了一種創(chuàng)新的編程模式模型。Akka使開發(fā)人員能夠輕松地使用高級抽象來構(gòu)建異步響應(yīng)式系統(tǒng),不必處理諸如線程、互斥和死鎖之類難題。Akka將應(yīng)用程序的行為和狀態(tài)封裝和建模為Actor(角色),如過程控制系統(tǒng)中的每個設(shè)備對應(yīng)一個Actor,這些Actor通過傳遞消息進(jìn)行相互協(xié)作,完成數(shù)據(jù)的采集、傳輸和處理[3]。
Actor的核心工作模式是,應(yīng)用程序只通過相互發(fā)送消息與之交互,而不像傳統(tǒng)的面向?qū)ο缶幊棠J街苯诱{(diào)用對象的方法。
Akka的Actor對象占用資源非常少,按照Akka的官方文檔說明,Akka的Actor運行在Java的JVM中,1GB Heap的內(nèi)存可以運行250萬個Actor對象,即可以模擬250萬個控制設(shè)置(如傳感器、執(zhí)行器、轉(zhuǎn)換器等),通過增加計算機(jī)的內(nèi)存,Akka可以控制的Actor數(shù)量急劇上升。
Akka中Actor的工作在消息驅(qū)動模式[4],不像傳統(tǒng)的編程模式通過調(diào)用對象的方法,或函數(shù)調(diào)用Actor功能,而是發(fā)送消息給Actor,Actor只有接收到消息后,才可以執(zhí)行指定的功能。消息驅(qū)動完全工作在異步模式[5],與傳統(tǒng)的同步模式相比,沒有線程的阻塞、鎖等問題,極大提高了系統(tǒng)的處理性能。
提出的過程控制系統(tǒng)基于Akka設(shè)計,當(dāng)單個計算機(jī)無法滿足控制的設(shè)備數(shù)量需求時,可以通過Akka-Cluster模塊[6],實現(xiàn)多個計算機(jī)的集群,將Akka的Actor System向外擴(kuò)展并跨越許多計算機(jī),從而實現(xiàn)完全分布式處理。
當(dāng)監(jiān)控設(shè)備增多,單個節(jié)點服務(wù)器無法創(chuàng)建足夠多的參與者來映射每個設(shè)備,可采用Akka集群模塊構(gòu)建節(jié)點群。每個節(jié)點上構(gòu)建參與者系統(tǒng),在網(wǎng)絡(luò)上監(jiān)聽各個Actor System跨節(jié)點的消息傳輸。集群上的參與者可以互相發(fā)送消息,處理來自分布式系統(tǒng)中設(shè)備的監(jiān)測數(shù)據(jù)。
每個節(jié)點Akka參與者系統(tǒng),負(fù)責(zé)控制和監(jiān)視該節(jié)點的所有參與者。每個參與者映射到物聯(lián)網(wǎng)設(shè)備,如溫度傳感器、壓力傳感器等設(shè)備,負(fù)責(zé)處理設(shè)備數(shù)據(jù)和執(zhí)行設(shè)備(如流量控制閥等)的狀態(tài)。
通過Akka MQTT連接器[7],控制設(shè)備通過MQTT協(xié)議,通過發(fā)送消息將收集到的傳感器數(shù)據(jù)發(fā)送到其對應(yīng)的Actor參與者。參與者通過定義由郵箱接收消息事件觸發(fā)的消息接收方法,并以異步響應(yīng)式方式接收消息。Actor完全采用異步模型工作,不阻塞線程處理,可以處理大量的設(shè)備數(shù)據(jù)轉(zhuǎn)換。
Akka中的Actor非常輕量級,每個只消耗幾百個字節(jié)。根據(jù)Akka文檔,擁有1GB內(nèi)存的節(jié)點可以創(chuàng)建大約250萬個Actor,而傳統(tǒng)的控制系統(tǒng)采用多線程模式只能有1 024個線程,只能支持連接1 020個設(shè)備。
在Akka-Cluster集群模塊的支持下,分布式控制系統(tǒng)的每個節(jié)點可以隨著需要控制的設(shè)備的數(shù)量多少進(jìn)行動態(tài)的添加或移除Actor System節(jié)點,從而使平臺具有動態(tài)集群架構(gòu)特性。基于Akka的控制系統(tǒng)總體架構(gòu)如圖1所示。

圖1 基于Akka的控制系統(tǒng)總體架構(gòu)圖
Actor模型使用發(fā)送和接收消息來實現(xiàn)設(shè)備間的通信和相互協(xié)作,有利于并發(fā)性和并行性,Actor是非常簡單的抽象,有利于簡化控制系統(tǒng)的編程。
Actor工作在異步、非阻塞和高性能的事件驅(qū)動編程模型中,所有Actor的工作必須通過給Actor發(fā)送消息實現(xiàn)。
為了在平臺中呈現(xiàn)實際的設(shè)備,使用Scala開發(fā)了用于定義設(shè)備和設(shè)備類型的Actor類,下面的代碼片段中展示了Actor對象的定義。
class DeviceType(name:String,mesureUnit:String){}
class Device(id:String,location:String,type:DeviceType){}
采集數(shù)據(jù)消息的設(shè)備是用Scala語言的case類實現(xiàn)的,當(dāng)傳感器設(shè)備通過MQTT協(xié)議向Actor系統(tǒng)發(fā)送數(shù)據(jù)時,內(nèi)置的Akka MQTT連接器將流轉(zhuǎn)換為Actor系統(tǒng)消息,該消息定義為以下代碼片段。
case class SensorData(device:DeviceModel,data:Double);
傳感器數(shù)據(jù)模型中包括采集數(shù)據(jù)的裝置device及其測量數(shù)據(jù)值data,最后用device屬性定義傳感器Actor,并重寫用接收到的消息觸發(fā)的超類Actor方法receive。
在創(chuàng)建Actor類之后,在Actor系統(tǒng)中創(chuàng)建它的對象,Actor系統(tǒng)運行并監(jiān)視所有Actor。下面的代碼片段展示了如何使用Scala語言在Akka Actor系統(tǒng)中創(chuàng)建Actor對象,代碼中201為設(shè)備的編號。
implicit val system = ActorSystem();
val sensor201=system.actorOf(Props[SensorActor],"NO201");
在Actor對象創(chuàng)建之后,它可以監(jiān)視自己的郵箱,當(dāng)郵箱中接收到消息時,事件觸發(fā)器receive方法以響應(yīng)式模式工作,不再阻塞線程。
在集群分布式系統(tǒng)中,參與者可以創(chuàng)建在遠(yuǎn)程節(jié)點的Actor系統(tǒng)中,Akka Remote模塊實現(xiàn)參與者透明地向遠(yuǎn)程參與者發(fā)送消息。
為了滿足超大規(guī)模控制系統(tǒng)中設(shè)備和數(shù)據(jù)采集處理的需要,必須建立服務(wù)器集群。雖然Akka Actor非常輕量級,1GB HEAP的單臺服務(wù)器可以容納250萬個Actor,可以支持相同數(shù)量的控制設(shè)備,但單個節(jié)點不支持容錯,還需要集群架構(gòu)。
Akka集群提供了一種基于點對點的容錯分布式集群成員服務(wù),沒有單點故障或單點瓶頸。Akka集群允許構(gòu)建分布式應(yīng)用程序,其中一個應(yīng)用程序或服務(wù)跨越多個節(jié)點(實際上是多個Actor系統(tǒng))。
控制系統(tǒng)應(yīng)用程序駐留在一個主節(jié)點中,主節(jié)點管理其他3個成員節(jié)點,這些節(jié)點可以動態(tài)加入集群。在每個節(jié)點上,應(yīng)用程序類路徑群集配置文件應(yīng)用程序.conf創(chuàng)建為以下代碼段。
akka {
cluster {
seed-nodes = [
"akka.tcp://IoTPlatform@210.30.108.224:2551",
"akka.tcp://IoTPlatform@210.30.108.225:2551",
"akka.tcp://IoTPlatform@210.30.108.226:2551"
]
}
}
akka.extensions=["akka.cluster.metrics.ClusterMetricsExtension"]
akka.cluster.metrics.native-library-extract-folder=${user.dir}/target/native
在Akka的集群系統(tǒng)中,先創(chuàng)建種子節(jié)點,再創(chuàng)建普通節(jié)點。當(dāng)新普通節(jié)點啟動時,它向所有種子節(jié)點發(fā)送一條消息,實現(xiàn)與種子節(jié)點交互。
在控制系統(tǒng)設(shè)備采集層,采用JavaScript框架Johnny Five框架連接傳感器等設(shè)備[8],傳感器數(shù)據(jù)通過Johnny Five獲取后,發(fā)送到Kafka服務(wù)器[9],并轉(zhuǎn)換到Actor郵箱。
關(guān)鍵是以Apache-Kafka[10]為中心來接收傳感器的監(jiān)測數(shù)據(jù),并向執(zhí)行器發(fā)送動作指令。Apache-Kafka是一個發(fā)布/訂閱消息傳遞系統(tǒng),設(shè)計用于分布式集群環(huán)境中,Kafka中的數(shù)據(jù)被持久地、有序地存儲,并且可以被確定地讀取。Kafka常用于實時流數(shù)據(jù)體系結(jié)構(gòu),實現(xiàn)數(shù)據(jù)的實時處理。
對于設(shè)備層,當(dāng)數(shù)據(jù)被獲取時,發(fā)送到Kafka消息主題,Kafka節(jié)點是一個節(jié)點.js客戶端,與Apache Kafka 集成。
采集的數(shù)據(jù)發(fā)送到Kafka后,本控制系統(tǒng)使用Alpakka-Kafka連接器連接Apache-Kafka,并將Kafka隊列中的數(shù)據(jù)轉(zhuǎn)換為Akka-Stream。Alpakka是一個開源項目,用于實現(xiàn)流數(shù)據(jù)的自動感知和響應(yīng)式集成數(shù)據(jù)流管道,它建立在Akka Streams之上,為反應(yīng)式和面向流的編程提供DSL,同時內(nèi)置了對背壓的支持,實現(xiàn)高可靠性的數(shù)據(jù)傳輸。
最后Alpakka消費者訂閱Kafka主題并將消息傳遞到Akka流中。為了連接Kafka,ActorSystem內(nèi)的ConsumerSettings配置為Akka-Kafka,同時消息的消費者在應(yīng)用程序.conf文件配置。將Actor被編程為Kafka client,在接收事件時對消息做出反應(yīng),然后將Akka消息發(fā)送給Webs Socket Actor,將數(shù)據(jù)發(fā)送給Web客戶端顯示。
本文設(shè)計并實現(xiàn)了一個基于Akka框架的全新的高可靠分布式和基于響應(yīng)式編程模型的的過程控制系統(tǒng)。與傳統(tǒng)的基于多線程的控制系統(tǒng)相比,該系統(tǒng)具有消息驅(qū)動、彈性、彈性、響應(yīng)性強(qiáng)等優(yōu)點,編程模型簡單,編程效率高,開發(fā)時間短等優(yōu)點。
充分利用Akka的Actor模型,每個Actor只使用非常少的內(nèi)存資源,可以使用實現(xiàn)一個普通PC控制上百萬設(shè)備的能力,這是傳統(tǒng)的基于線程的C語言編程模式難以企及的。
在Akka集群和遠(yuǎn)程模塊的支持下,系統(tǒng)可以擴(kuò)展和伸縮,可以支持多個核心CPU和多個服務(wù)器。使用Akka Actor模型,開發(fā)人員不必使用諸如線程和鎖之類的低級結(jié)構(gòu),這也是使用傳統(tǒng)編程模式難以實現(xiàn)超大規(guī)模的控制系統(tǒng)的原因所在。
在未來的控制系統(tǒng)的開發(fā)與應(yīng)用中,基于角色模型為基礎(chǔ)的Akka技術(shù),必將成為主流的技術(shù)和平臺。