構(gòu)建物聯(lián)網(wǎng)系統(tǒng)的挑戰(zhàn)
并發(fā)處理能力
聯(lián)網(wǎng)系統(tǒng)需要處理大量的設(shè)備連接和海量數(shù)據(jù),尤其工業(yè)物聯(lián)網(wǎng)系統(tǒng)可能是面對(duì)毫秒級(jí)的數(shù)據(jù)傳輸,傳統(tǒng)的線程模型在處理高并發(fā)請(qǐng)求時(shí)可能遇到性能瓶頸,并且多線程的管理難以處理。
系統(tǒng)穩(wěn)定性
物聯(lián)網(wǎng)系統(tǒng)往往不像互聯(lián)網(wǎng)系統(tǒng)一樣,隨著用戶操作帶來并發(fā),物聯(lián)網(wǎng)系統(tǒng)的并發(fā)通常是持續(xù)存在的,可能會(huì)存在大量的設(shè)備長連接,而工業(yè)物聯(lián)網(wǎng)系統(tǒng)又關(guān)乎著整個(gè)廠站生產(chǎn)穩(wěn)定,所以物聯(lián)網(wǎng)系統(tǒng)的穩(wěn)定性至關(guān)重要。傳統(tǒng)架構(gòu)可能因?yàn)槟硞€(gè)組件的故障而影響整個(gè)系統(tǒng)的運(yùn)行。
拓展性要求高
物聯(lián)網(wǎng)系統(tǒng)通常面向多種協(xié)議、多種設(shè)備,我們不能每次通過停機(jī)修改代碼的方式增加支持的協(xié)議,所以各個(gè)組件需要解耦,需要具備很強(qiáng)的拓展性,更需要組件間有效的消息傳遞機(jī)制以保證數(shù)據(jù)同步和命令傳遞。
并發(fā)處理方案選型
在這樣的背景下,Actor模型作為一種先進(jìn)的并發(fā)計(jì)算模型,逐漸在物聯(lián)網(wǎng)系統(tǒng)應(yīng)用中嶄露頭角。Actor 模型以其獨(dú)特的消息傳遞、獨(dú)立計(jì)算實(shí)體和容錯(cuò)機(jī)制等特性,為物聯(lián)網(wǎng)平臺(tái)提供了一種高效、可靠的應(yīng)用解決方案。
為什么選擇Actor模型
Actor模型在1973年由Carl Hewitt定義,被Erlang OTP推廣,其消息傳遞更加符合面向?qū)ο蟮脑荚O(shè)計(jì),Actor模型屬于并發(fā)組件模型,通過組件方式定義并發(fā)編程范式的高級(jí)階段,避免使用者直接接觸多線程并發(fā)或線程池等基礎(chǔ)概念。
不同于傳統(tǒng)的直接功能間調(diào)用,該模型將功能實(shí)例拆分成一個(gè)個(gè)Actor,每個(gè)Actor由狀態(tài)、行為和郵箱三部分組成。每個(gè)Actor之間的通訊通過互相發(fā)送消息完成。
簡單來說郵箱就是Actor之間的通信橋梁,郵箱內(nèi)部通過FIFO(先入先出)消息隊(duì)列來存儲(chǔ)發(fā)送方Actor的消息,接收方Actor再從郵箱隊(duì)列中獲取消息。按消息的流向可以看出,可以將Actor模型分為發(fā)送方和接收方,一個(gè)Actor模型既可以是發(fā)送方也可以是接收方。
在使用Java語言進(jìn)行并發(fā)編程時(shí)需要特別關(guān)注鎖和內(nèi)存原子性等一系列線程問題,而Actor模型內(nèi)部的狀態(tài)由它自己維護(hù),它內(nèi)部數(shù)據(jù)只能由它自己修改,所以使用Actor模型進(jìn)行并發(fā)編程可以很好地避免線程問題。
如何在物聯(lián)網(wǎng)中應(yīng)用
Actor模型是一個(gè)通用的并發(fā)編程模型,而非某個(gè)語言或框架所有,幾乎可以用在任何一門編程語言中,如 Erlang在語言層面支持Actor模型,如著名的消息中間件RabbitMQ正是使用了該模型。
而在java語言中,Akka是一個(gè)很成熟的Actor模型實(shí)現(xiàn),工業(yè)物聯(lián)網(wǎng)統(tǒng)一接入系統(tǒng)正是引入了Akka,從而從架構(gòu)層面實(shí)現(xiàn)了Actor模型。
我們將工業(yè)物聯(lián)網(wǎng)統(tǒng)一接入系統(tǒng)的所有的功能進(jìn)行劃分,每個(gè)功能采用一個(gè)Actor實(shí)現(xiàn),每個(gè)Actor都有一個(gè)專用的郵箱來接收消息,這也是Actor模型實(shí)現(xiàn)異步的基礎(chǔ)。功能之間由直接調(diào)用,變成了消息的傳遞,就好像郵遞員,并不是把郵件直接送到收信人手里,而是放進(jìn)每家的郵箱,這樣郵遞員就可以快速地進(jìn)行下一項(xiàng)工作。所以在系統(tǒng)里,功能間完成一次調(diào)用是非??斓模⑶蚁到y(tǒng)中的每一個(gè)功能,每一個(gè)組件都實(shí)現(xiàn)了解耦,每個(gè)Actor僅需專注實(shí)現(xiàn)自己的功能即可。
一個(gè)Akka系統(tǒng)支持?jǐn)?shù)萬個(gè)Actor并發(fā)的運(yùn)行,每個(gè)Actor的實(shí)例非常小,單機(jī)幾十萬的Actor實(shí)例很輕松,我們將并發(fā)比較高的功能,如設(shè)備協(xié)議解析組件,每種協(xié)議的接入組件都創(chuàng)建多個(gè)相同的Actor,形成內(nèi)部的負(fù)載,他們并發(fā)的處理同一種協(xié)議數(shù)據(jù),且每個(gè)Actor都以自己的步調(diào)運(yùn)行,發(fā)送消息、接收消息都不會(huì)被阻塞,大大提高了物聯(lián)網(wǎng)統(tǒng)一接入系統(tǒng)的并發(fā)接入能力。
同時(shí),我們可以便捷的在代碼運(yùn)行時(shí)創(chuàng)建并啟用一個(gè)新的Actor,賦予Actor不同的能力,也大大提高了物聯(lián)網(wǎng)統(tǒng)一接入系統(tǒng)的動(dòng)態(tài)拓展性。
Actor模型的其他優(yōu)勢(shì)
天生分布式支持
除了高并發(fā)外,Akka的集群模式,讓Actor分布在不同的服務(wù)器上,每個(gè)服務(wù)成為一個(gè)ActorSystem,但對(duì)于開發(fā)者來說,無需關(guān)心Actor在本地還是在遠(yuǎn)程的機(jī)器上,想要調(diào)用一個(gè)Actor,只需要知道Actor的地址即可,Akka可以隨意橫向擴(kuò)展來應(yīng)對(duì)并發(fā),所以說他天生就支持分布式,大大提高系統(tǒng)的可伸縮性。
便捷的生命周期
每個(gè)Actor模型實(shí)例都有自己的生命周期,就像java中的垃圾回收機(jī)制一樣,對(duì)于需要淘汰的Actor實(shí)例,系統(tǒng)會(huì)銷毀并釋放內(nèi)存等資源來保證系統(tǒng)的持續(xù)性。
靈活的異常管理
傳統(tǒng)的編程方式是在將來可能出現(xiàn)異常的地方去捕獲異常來保證系統(tǒng)的穩(wěn)定性,比如在java代碼中很多地方充斥著判斷變量是否為空,防止出現(xiàn)空指針異常。但是Actor模型的程序并不進(jìn)行防御式編程,而是讓Actor模型的管理者們來處理這些異常問題。每個(gè)Actor的異常信息都可以反饋到管理者那里,這就保證了系統(tǒng)在管理每個(gè)Actor實(shí)例時(shí)的靈活性。