Akka之在IoT系统中使用Actor(一)
(一)IoT系統介紹
通過了解Actor的層次結構和行為,剩下的問題是如何將IoT系統的頂層組件映射到actor。將代表設備和儀表板的Actor放在頂層可能很誘人。相反,我們建議創建一個代表整個應用程序的顯式組件。換句話說,我們將在物聯網系統中擁有一名頂級Actor。創建和管理設備和儀表板的組件將是此Actor的子組件。這允許我們將IoT系統用Actor樹來表示:
?(二)IoT系統的頂層
?我們可以使用幾行簡單的代碼來定義第一個actor,即IotSupervisor。
import akka.actor.AbstractActor; import akka.actor.Props; import akka.event.Logging; import akka.event.LoggingAdapter;public class IotSupervisor extends AbstractActor {private final LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);public static Props props() {return Props.create(IotSupervisor.class, IotSupervisor::new);}@Overridepublic void preStart() {log.info("IoT Application started");}@Overridepublic void postStop() {log.info("IoT Application stopped");}// No need to handle any messages@Overridepublic Receive createReceive() {return receiveBuilder().build();} } import java.io.IOException;import akka.actor.ActorSystem; import akka.actor.ActorRef;public class IotMain {public static void main(String[] args) throws IOException {ActorSystem system = ActorSystem.create("iot-system");try {// Create top level supervisorActorRef supervisor = system.actorOf(IotSupervisor.props(), "iot-supervisor");System.out.println("Press ENTER to exit the system");System.in.read();} finally {system.terminate();}} }(三)設備actor?
如果我們使用對象,我們通常會將API設計為接口,這是由實際實現填充的抽象方法的集合。在Actor的世界中,協議取代了接口。雖然不可能在編程語言中形式化通用協議,但我們可以編寫它們最基本的元素,即消息。因此,我們將首先確定要發送給設備Actor的消息。
通常,消息屬于類別或模式。通過識別這些模式,您會發現在它們之間進行選擇并實現它們變得更加容易。
設備actor的任務很簡單:
??? ?收集溫度測量值
??? ?當被問到時,報告最后測量的溫度
但是,設備可能在啟動時沒有立即進行溫度測量。因此,我們需要考慮溫度不存在的情況。這也允許我們在沒有寫入部分的情況下測試actor的查詢部分,因為設備actor可以報告空結果。
用于從設備actor獲得當前溫度的協議是簡單的。
1.?? ?等待當前溫度的請求。
2.?? ?響應請求并回復:包含當前溫度或者表示溫度尚不可用。
我們需要兩條消息,一條用于請求,另一條用于回復。
這兩條消息似乎涵蓋了所需的功能。但是,我們選擇的方法必須考慮應用程序的分布式特性。雖然與本地JVM上的actor進行通信的基本機制與遠程actor相同,但我們需要牢記以下幾點:
??? ?本地和遠程消息之間的傳遞延遲將存在可觀察到的差異,因為網絡鏈路帶寬和消息大小等因素也會發揮作用。
??? ?可靠性是一個問題,因為遠程消息發送涉及更多步驟,這意味著更多可能出錯。
??? ?本地發送將傳遞對同一JVM內的消息的引用,而不會對發送的基礎對象進行任何限制,而遠程傳輸將對消息大小設置限制。
此外,雖然在同一個JVM內部發送更可靠,但如果一個Actor在處理消息時由于程序員錯誤而失敗,其效果就像遠程主機請求因處理消息時遠程主機崩潰而失敗一樣。即使在這兩種情況下,服務都會在一段時間后恢復(Actor由其supervisor重新啟動,host由運營商或監控系統重新啟動)在崩潰期間各個請求都會丟失。因此,寫下你的Actor,使每條消息都可能丟失,這是安全、悲觀的賭注。
但是為了進一步理解協議的靈活性需求,將有助于考慮Akka消息排序和消息傳遞保證。Akka為消息發送提供以下行為:
??? ?最多一次傳遞,即無保證傳遞。
??? ?每個發送者、接收者對維護消息排序。?
一、消息傳遞
消息傳遞子系統提供的傳遞語義通常分為以下幾類:
??? ?最多一次發送 - 每條消息一次或零次發送 ; 在更多的因果關系中,這意味著消息可能會丟失,但永遠不會重復。
??? ?至少一次傳遞 - 可能會多次嘗試傳遞每條消息,直到至少一次成功; 這意味著消息可以重復,但永遠不會丟失。
??? ?完全一次發送 - 每條消息只發送一次給收件人; 消息既不會丟失也不會重復。
第一種方式是最便宜的,并且性能最高。它具有最少的實現開銷,因為它可以以一種即發即忘的方式完成,而不會將狀態保持在發送端或傳輸機制中。第二種方式,需要至少一次重試以抵消運輸損失。這增加了將狀態保持在發送端并在接收端具有確認機制的開銷。第三種方式完全一次交付是最昂貴的,并且導致最差的性能:除了至少一次交付所增加的開銷之外,它還要求將狀態保持在接收狀態以便過濾掉重復的交付。
在Actor系統中,我們需要保證一個確切的含義 - 系統在何時將發送視為已完成:
1.?? ?當消息在網絡上發送出去?
2.?? ?當目標actor的主持人收到消息時?
3.?? ?當消息被放入目標actor的郵箱時?
4.?? ?當消息目標actor開始處理消息時?
5.?? ?目標actor何時成功處理了消息?
大多數聲稱保證交付的框架和協議實際上提供了類似于第4點和第5點的內容。雖然這聽起來很合理,但它實際上有用嗎?要理解其含義,請考慮一個簡單實用的示例:用戶嘗試下訂單,一旦它成功寫在訂單數據庫中的磁盤上。我們就聲明它已經成功處理。
如果我們依賴于成功處理消息,則只要訂單已提交給負責驗證它的內部API,處理它并將其放入數據庫,actor就會報告成功。不幸的是,在調用API之后,可能會發生以下任何一種情況:
??? ?主機可能崩潰。
??? ?反序列化可能會失敗。
??? ?驗證可能會失敗。
??? ?數據庫可能不可用。
??? ?可能會發生編程錯誤。
這表明發送的保證不會轉化為domain級保證。我們只想在訂單實際完全處理和存儲后報告成功??梢詧蟾娉晒Φ奈ㄒ粚嶓w是應用程序本身,因為只有它對所需的domain保證有了解。沒有通用框架可以弄清楚特定domain的細節以及在該域中被認為是成功的。
在這個特定的例子中,我們只希望在成功的數據庫寫入后發出成功信號,數據庫確認訂單現在已安全存儲。由于這些原因,Akka將保證的責任提升到應用程序本身,即您必須使用Akka提供的工具自行實現它們。這使您可以完全控制要提供的保證?,F在,讓我們考慮Akka提供的消息排序,以便于推理應用程序邏輯。
二、消息排序
在Akka中,對于給定的一對Actor,直接從第一個發送到第二個的消息將不會被無序接收。這強調,這種保證僅適用于將tell的operator直接發送到最終目的地,而不是在使用mediators時。
如果:
??? ?Actor A1發送消息M1,M2,M3到A2。
??? ?Actor A3發送消息M4,M5,M6到A2。
這意味著,對于Akka消息:
??? ?如果發送M1,必須在M2和之前發送M3。
??? ?如果發送M2,必須在之前交付M3。
??? ?如果發送M4,必須在M5和之前發送M6。
??? ?如果發送M5,必須在之前發送M6。
??? ?A2可以看到來自A1交錯信息的消息A3。?
??? ?由于沒有保證傳遞,任何消息都可能被丟棄,即沒有到達A2。
這些保證達到了良好的平衡:讓一個Actor的消息按順序到達對于構建易于追溯的系統是方便的,而另一方面允許來自不同Actor的消息交錯到達提供了足夠的自由來有效地實現Actor系統。
?
總結
以上是生活随笔為你收集整理的Akka之在IoT系统中使用Actor(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 四层负载均衡与七层负载均衡
- 下一篇: 中国移动系统集成公司2020春招技术综合