基于JavaScript語言的快速物聯(lián)網(wǎng)開發(fā)架構(gòu)
隨 JavaScript 語言的流行,及物聯(lián)網(wǎng)領(lǐng)域的崛起,我們能看到它們結(jié)合的可能性,同時(shí)也發(fā)現(xiàn)它特別適合于物聯(lián)網(wǎng)開發(fā)。因此,在這篇文章里,筆者將主要從以下三個(gè)方面進(jìn)行介紹:
- 典型的物聯(lián)網(wǎng)架構(gòu),及多種語言帶來的問題;
- 只使用 JavaScript 語言的物聯(lián)網(wǎng)架構(gòu);
- 詳解基于 JavaScript 語言的物聯(lián)網(wǎng)不同層級(jí)結(jié)構(gòu)。
那么,先讓我們看看典型的物聯(lián)網(wǎng)架構(gòu)是怎樣的吧。
典型的物聯(lián)網(wǎng)架構(gòu)
我們甚至還可以認(rèn)為,物聯(lián)網(wǎng)只是對互聯(lián)網(wǎng)的擴(kuò)展。與傳統(tǒng)的 C/S 架構(gòu)相比,它多了一個(gè)“數(shù)據(jù)采集層”,我們稱之為傳感器層、硬件層等。數(shù)據(jù)的產(chǎn)出不再只是用戶,還來自于各式各樣的聯(lián)網(wǎng)設(shè)備。物聯(lián)網(wǎng)不再局限于使用 HTTP 協(xié)議來傳輸數(shù)據(jù),它還會(huì)使用 CoAP(受限制的應(yīng)用協(xié)議)、MQTT(消息隊(duì)列遙測傳輸)協(xié)議。
物聯(lián)網(wǎng)的四個(gè)層級(jí)
當(dāng)前的物聯(lián)網(wǎng)應(yīng)用,所要做的就是控制和數(shù)據(jù)處理。指令,由用戶到終端一層一層往下下達(dá),直到硬件端由設(shè)備去執(zhí)行。而數(shù)據(jù),便是一層一層往上上報(bào),直至被可視化。
因此,與互聯(lián)網(wǎng)的架構(gòu)相比(如圖 1、圖 2 所示),起點(diǎn)與終點(diǎn)不一樣了:指令的終點(diǎn)與數(shù)據(jù)的起點(diǎn),變成了硬件層,而非***的用戶層。
數(shù)據(jù)由客戶端 A 發(fā)送到服務(wù)端,客戶端 B 再從服務(wù)端獲取 A 的數(shù)據(jù),如此便算是完成了一個(gè)回路。而物聯(lián)網(wǎng)架構(gòu)則稍微麻煩了一些,多了一個(gè)層級(jí),便多了一個(gè)步驟。
硬件層上的微控制器通過直連的方式,采集各式各樣的數(shù)據(jù),比如溫度、濕度等。而受限于微控制器的成本、環(huán)境條件等因素,它可能無法直接連接到互聯(lián)網(wǎng)。因此,需要連接到一些額外的聯(lián)網(wǎng)設(shè)備才能實(shí)現(xiàn)。
而這些聯(lián)網(wǎng)設(shè)備,會(huì)負(fù)責(zé)處理來自各個(gè)硬件設(shè)備的數(shù)據(jù),并將其上傳至服務(wù)器。同時(shí),它會(huì)提供一個(gè)無線(如藍(lán)牙、紅外、ZigBee)接口作為數(shù)據(jù)的入口。因此,這一層級(jí)需要有更好的數(shù)據(jù)處理能力,并且它應(yīng)該要可以快速開發(fā)。因?yàn)檫@些設(shè)備主要做的是協(xié)調(diào)工作,我們習(xí)慣于將其稱為“協(xié)調(diào)層”。
使用多種語言的物聯(lián)網(wǎng)
多年以前,筆者曾做過一個(gè)并不復(fù)雜的物聯(lián)網(wǎng)系統(tǒng):
- 使用 Python 里的 Django 作為 Web 服務(wù)框架,Django REST Framework 創(chuàng)建 RESTful API;
- 為了使用手機(jī)作為控制器,還用 Java 寫一個(gè) Android 應(yīng)用;
- 使用 Raspberry Pi 作為硬件端的協(xié)調(diào)層,用于連接網(wǎng)絡(luò),并傳輸控制信號(hào)給硬件;
- 在硬件端使用 Arduino 作為控制器,寫起代碼特別簡單;
- 還使用了 ZigBee 模塊 XBee 及 I2C 作為連接不同 Arduino 模塊的介質(zhì);
- ***,還需在網(wǎng)頁上做一個(gè)圖表來顯示實(shí)時(shí)數(shù)據(jù)。
為此,我們需要使用 Python、Java、javascript、C、Arduino 五種語言。而如果我們要寫相應(yīng)的 iOS 應(yīng)用,還要用到 Objective-C。對于其他物聯(lián)網(wǎng)項(xiàng)目來說,也多是如此,這簡直是一場災(zāi)難。
在做這樣的物聯(lián)網(wǎng)項(xiàng)目之前,我們需要找到六個(gè)不同類型的工程師:一個(gè)硬件工程師設(shè)計(jì)電路圖,一個(gè)懂硬件的嵌入式工程師,一個(gè)寫服務(wù)端應(yīng)用的工程師,一個(gè)寫 Web 前端的工程師,以及對應(yīng)的 Android 和 ios 工程師。
且不考慮系統(tǒng)本身的協(xié)作,要找到這么多的工程師就不是一件容易的事。而如果我們可以只使用一種語言,將大大地改善開發(fā)效率、開發(fā)人員的難題。JavaScript 語言下的物聯(lián)網(wǎng)架構(gòu)
JavaScript 語言在最近幾年里特別流行,它流行起來有很多個(gè)原因,如:
- 使用 WebView 開發(fā) UI 效率更高,也因此使得 WebView 隨處可見;
- 基于事件驅(qū)動(dòng)的編程模型;
- JavaScript 容易上手(這是優(yōu)點(diǎn),也是缺點(diǎn));
- 也因此,React、Unity 等框架提供了更多的可能性,可以讓開發(fā)者用 JavaScript 開發(fā)游戲、VR 應(yīng)用等等。
那么,只使用 JavaScript,我們可以設(shè)計(jì)出怎樣的物聯(lián)網(wǎng)系統(tǒng)呢?
基于純 JavaScript 的物聯(lián)網(wǎng)架構(gòu)
如上所述,幾年前要想尋找一門能完成一個(gè)包含客戶端、服務(wù)端的系統(tǒng)的語言可謂相當(dāng)?shù)乩щy。而隨著客戶端(瀏覽器、移動(dòng)設(shè)備)性能的提升、Node.js 的出現(xiàn),這樣的語言就浮現(xiàn)了出來,即 JavaScript。它不僅可以讓我們只用一門語言來降低開發(fā)成本,還能實(shí)現(xiàn)快速地開發(fā)出這樣的一個(gè)系統(tǒng)。那么,剩下的問題就是,在不同的層級(jí),如何選用合適的框架來實(shí)現(xiàn)快速開發(fā)。
如圖 3 所示,我們可以看到不同層級(jí)的可選用 JavaScript 方案。在此之中,有些純粹只是為了證明 JavaScript 是可行的;有一些則可以在開發(fā)效率與運(yùn)行速率上達(dá)到***的平衡。選用這些方案,可以讓我們實(shí)現(xiàn)更快速的 JavaScript 物聯(lián)網(wǎng)應(yīng)用開發(fā)。
服務(wù)層
對于服務(wù)層來說,自主開發(fā)的物聯(lián)網(wǎng)服務(wù)端,主要采用的是基于 node.js 的方案。然而,我們發(fā)現(xiàn)有越來越多的應(yīng)用,在使用 Serverless 的架構(gòu),不僅可以快速推出一個(gè)可用的原型,未來也能夠輕松地基于這個(gè)原型來添加業(yè)務(wù)功能。
圖 4 便是我們看到的物聯(lián)網(wǎng)服務(wù)層的三種方案:
- 自主開發(fā):即遵循傳統(tǒng)的服務(wù)端開發(fā)模式,定義自己所需要的功能;
- 使用云服務(wù):直接使用成熟的物聯(lián)網(wǎng)云服務(wù),它們在云端集成了各種所需要的功能;
- Serverless:Server 可以看作是在云服務(wù)之上的自主開發(fā),集兩者之便利。
每一種方案都有各自的特點(diǎn),也適合于不同開發(fā)能力的項(xiàng)目。但如果要實(shí)現(xiàn)快速的開發(fā),那么理想的方式便是采用 Serverless 架構(gòu)模式。
自主開發(fā)
出于不同的原因,諸如保密、安全、可擴(kuò)展、核心技術(shù)等原因,一定規(guī)模的公司會(huì)采用自主開發(fā)的方式。這種開發(fā)方式與 Web 應(yīng)用開發(fā)方式并沒有太大區(qū)別,都是在數(shù)據(jù)進(jìn)行 CRUD 操作。并且和前后端分離架構(gòu)一樣,使用 API 作為接口,同時(shí)再加上支持不同的傳輸協(xié)議,如 MQTT、CoAP 等。
如筆者之前在 GitHub 上開源的 Lan(https://github.com/phodal/lan),便是一個(gè)精簡的物聯(lián)網(wǎng)服務(wù)端示例。基于 Node.js 與 MongoDB,其架構(gòu)如圖 5 所示。
- 采用傳統(tǒng)的關(guān)系型數(shù)據(jù)庫來存儲(chǔ)用戶信息;
- 采用 NoSQL 可以應(yīng)對不同的傳感器數(shù)據(jù);
- 提供 UI 界面供管理人員管理用戶;
- 在協(xié)議上提供 HTTP、CoAP、MQTT、WebSocket 等的支持,方便不同的類型適配。
除此,物聯(lián)網(wǎng)系統(tǒng)在存儲(chǔ)上,采用 NoSQL 作為存儲(chǔ)介質(zhì)會(huì)有更大的優(yōu)勢。一般來說,物聯(lián)網(wǎng)系統(tǒng)的數(shù)據(jù)都是寫入遠(yuǎn)遠(yuǎn)多于讀取的場景。與此同時(shí),由于設(shè)備的種類繁多,不可能為每一類設(shè)備創(chuàng)建表;或者考慮到大量設(shè)備的特性,來建立一個(gè)通用的表,但在未來這樣的表可能仍不適用。
因此,對于物聯(lián)網(wǎng)數(shù)據(jù)來說,選用諸如 mongodb 這一類的 NoSQL 數(shù)據(jù)庫,有這么一些優(yōu)點(diǎn):
- 靈活性。采用非結(jié)構(gòu)化的數(shù)據(jù)模型,可以存儲(chǔ)和處理任何結(jié)構(gòu)的數(shù)據(jù);
- 支持水平擴(kuò)展。NoSQL 數(shù)據(jù)庫的分布式存儲(chǔ)架構(gòu),帶來了優(yōu)秀的水平擴(kuò)展性;
- 實(shí)時(shí)數(shù)據(jù)分析。如 MongoDB 可以通過豐富的索引和查詢支持,包括二次、地理空間和文本搜索索引,聚合框架和本地 MapReduce,可以針對傳感器數(shù)據(jù)就地運(yùn)行報(bào)告分析。
然而,這樣的系統(tǒng)不免存在研發(fā)周期長的問題。如果需要快速驗(yàn)證,那么應(yīng)該考慮使用云服務(wù)來完成部分功能。
物聯(lián)網(wǎng)云服務(wù)
對于硬件團(tuán)隊(duì)來說,直接使用云服務(wù)是一種更簡單、快速的搭建物聯(lián)網(wǎng)系統(tǒng)的方法。而使用物聯(lián)網(wǎng)云服務(wù),就意味著:我們可以直接上硬件層的傳感器數(shù)據(jù),并在應(yīng)用層獲取、分析這些數(shù)據(jù)。這一類的服務(wù),比較成熟的有 AWS IoT Things(如圖 6 所示)、Azure IoT 等。
基于 AWS IoT Things,我們只需要在云端,定義好對應(yīng)的數(shù)據(jù)處理規(guī)則,便可以在硬件端直接對接服務(wù)。不過值得注意的是,單一的云服務(wù)無法提供復(fù)雜的功能,這個(gè)時(shí)候就需要一些搭配額外的服務(wù)。
Serverless
Serverless 架構(gòu)(如圖 7 所示)是云服務(wù)的一種,但是它在可編程與云服務(wù)之間做了一個(gè)折中。它是一種基于互聯(lián)網(wǎng)的技術(shù)架構(gòu)理念,應(yīng)用邏輯并非全部在服務(wù)端實(shí)現(xiàn),而是采用 FaaS(Function as a Service)架構(gòu),通過功能組合來實(shí)現(xiàn)應(yīng)用程序邏輯。
從理論上來講,這些服務(wù)提供的是一層 API 封裝,它不會(huì)限制我們所使用的語言。使用 Serverless 服務(wù),我們可以具備更好的快速開發(fā)能力,并且能使用同一種語言(JavaScript)來完成編程。
在這個(gè)過程中,開發(fā)者要所做的便是:在不同的服務(wù)之間傳輸數(shù)據(jù),每一次都只處理下一個(gè)服務(wù)所需要的數(shù)據(jù),類似于 Pipe and Filters 架構(gòu)模式。如一個(gè)典型的物聯(lián)網(wǎng)應(yīng)用的數(shù)據(jù)傳輸過程中是這樣的:
- 對設(shè)備進(jìn)行鑒權(quán);
- 轉(zhuǎn)換、存儲(chǔ)設(shè)備的數(shù)據(jù);
- 廣播通知其他監(jiān)聽此設(shè)備數(shù)據(jù)的服務(wù);
- 后臺(tái)查詢數(shù)據(jù);
- 分析數(shù)據(jù)(AI);
- 可視化數(shù)據(jù)。
只需要少量的編程,我們就可以完成服務(wù)端的開發(fā)。隨后,專注于硬件層的開發(fā),以及應(yīng)用層的業(yè)務(wù)功能。
應(yīng)用層
在應(yīng)用層方面,已經(jīng)有大量的地方使用到了 JavaScript。除了傳統(tǒng)的桌面瀏覽器,還有更多的領(lǐng)域也可以用 JavaScript 來開發(fā)。比如移動(dòng)應(yīng)用,已經(jīng)有基于 Cordova + WebView 的成熟方案,還有近兩三年流行起來的 React Native,都可以讓開發(fā)者使用 JavaScript 完成物聯(lián)網(wǎng)移動(dòng)應(yīng)用的開發(fā)。又如微信小程序,可以直接用藍(lán)牙來連接硬件設(shè)備,也是使用 JavaScript 來編程。
因此,就目前的 Web 趨勢來看,在應(yīng)用層,JavaScript 將是快速開始的主流選擇。
在日常中的應(yīng)用中,我們可以發(fā)現(xiàn)物聯(lián)網(wǎng)的應(yīng)用層,經(jīng)常作為協(xié)調(diào)裝置來連接硬件,并上傳應(yīng)用的數(shù)據(jù)。諸如共享單車、智能手環(huán)應(yīng)用等,它們既通過藍(lán)牙來獲取數(shù)據(jù),又上傳數(shù)據(jù)到服務(wù)端。與此同時(shí),有相當(dāng)多的應(yīng)用是運(yùn)行在桌面客戶端上的。故而在這一層級(jí)的應(yīng)用,可謂是種類繁多。
今天,開發(fā)人員在做移動(dòng)端的技術(shù)選型時(shí),都會(huì)優(yōu)先考慮到跨平臺(tái)能力(android、iOS)。而在這些跨平臺(tái)框架里,混合應(yīng)用框架 Cordova(WebView)和 react Native 是使用最為廣泛的兩個(gè)框架,且它們都是使用 JavaScript 作為核心開發(fā)語言。
Cordova 是使用 WebView 來渲染頁面的。因此與 Reavt Native 相比,使用 Cordova 的***優(yōu)勢是,可以復(fù)用已有的 Web 前端應(yīng)用的邏輯,并且有大量的圖表工具可以直接使用——這一點(diǎn)在物聯(lián)網(wǎng)應(yīng)用中特別重要。而在混合應(yīng)用框架中,Ionic 是這個(gè)領(lǐng)域使用最多的 UI 框架。
React Native 使用原生組件來渲染 UI 組件,不僅可以解決 Cordova 飽受詬病的性能問題;同時(shí),它還能嵌入 WebView,解決一些復(fù)雜的圖表顯示問題。
但是如果只能藍(lán)牙的交互,可以考慮 PWA 或微信小程序。運(yùn)行在 Chrome 瀏覽器上的 PWA 應(yīng)用,可以直接使用 Web Devices API,如 Bluetooth、NFC、USB,即在瀏覽器上直接調(diào)用原生接口,并實(shí)現(xiàn)對設(shè)備的控制。而諸如最近一年內(nèi)流行的微信小程序,則也可以訪問藍(lán)牙、GPS、羅盤、加速度計(jì)等硬件接口,同時(shí)用戶不存在安裝成本,打開即用。
另外,諸如 Electron、NW.js 這樣的框架,可以讓開發(fā)者直接使用 WebView + Node.js 模塊開發(fā)物聯(lián)網(wǎng)桌面應(yīng)用。它可以加速 UI 界面的開發(fā),并輕松地美化 UI 界面。
硬件層
在硬件層上,就當(dāng)前而言,Arduino 是最合適的原型開發(fā)硬件,除此還有自帶 Wi-Fi 的 ESP8266 開發(fā)板。盡管使用 JavaScript 的開發(fā)板數(shù)量較少,也沒有 Arduino 這樣的成熟生態(tài),但是未來可期。在嵌入式領(lǐng)域,使用 JavaScript 編寫的代碼,具有移植性強(qiáng)、事件驅(qū)動(dòng)、天生支持異步等特點(diǎn)。
令人遺憾的是,為了保持上面提到的那些 JavaScript 特性,當(dāng)前的 JavaScript 開發(fā)板都需要處理性能比較高的處理器,這也導(dǎo)致了此類開發(fā)板在生產(chǎn)上存在較高的成本。不過,好在多數(shù)使用 JavaScript 作為開發(fā)語言的設(shè)備,都具有網(wǎng)絡(luò)功能連接到互聯(lián)網(wǎng),直接作為物聯(lián)網(wǎng)設(shè)備使用。
就目前而言,這一類的設(shè)備有 Tessel、Espruino、Ruff 等等,它們的處理器性能都相當(dāng)不錯(cuò),價(jià)格也相對較高一些。但是,它們可以直接使用 JavaScript,能為軟件開發(fā)工程師屏蔽底層相關(guān)細(xì)節(jié),及事件驅(qū)動(dòng)、異步特性,帶來更好的開發(fā)體驗(yàn)。
幸運(yùn)的是,Samsung 公司推出的開源物網(wǎng)框架 IoT.js,只需要 64KB RAM、200 KB ROM。在未來,或許它能解決一些制造成本上的問題。
協(xié)調(diào)層
當(dāng)我們的硬件層不能直接聯(lián)網(wǎng)時(shí),協(xié)調(diào)層就可以完成這樣的功能。作為一個(gè)協(xié)調(diào)層的設(shè)備,它應(yīng)該能與一定數(shù)量的微控制器連接,接收它們的數(shù)據(jù),并上傳到服務(wù)端;又能與服務(wù)端通訊,獲取一些控制指令,并將這些指令準(zhǔn)時(shí)地發(fā)送給不同的控制器。所以,它需要有更好的處理能力、更多的 RAM、ROM 等等。因此,在這一層級(jí)使用 JavaScript 便不存在成本問題。我們只需要使用和服務(wù)端、應(yīng)用層相似的知識(shí),就可以快速地連接設(shè)備到網(wǎng)絡(luò)中心。還能直接在本地的 Linux 機(jī)器上編寫代碼,并無縫地運(yùn)行在設(shè)備上。
這一類應(yīng)用,依賴于 Node.js 引擎來實(shí)現(xiàn)快速開發(fā)。它可以運(yùn)行在帶有嵌入式系統(tǒng)的開發(fā)板上,如流行的 Raspberry Pi、OpenWRT 路由器等。
我們只需要一個(gè)運(yùn)行嵌入式 linux 系統(tǒng)的開發(fā)板,就可以完成這樣的工作。與此同時(shí),主流的 ARM 開發(fā)板都提供相應(yīng)的 Linux 移植,因此在這個(gè)層級(jí),我們也只需要關(guān)注于業(yè)務(wù)的實(shí)現(xiàn)。
小結(jié)
如上所述,物聯(lián)網(wǎng)應(yīng)用的架構(gòu)與 Web 應(yīng)用的架構(gòu)區(qū)別并不是太大,只是在這上面做一系列的演進(jìn)。除了上面提到的一系列快速實(shí)踐框架,當(dāng)前在 Web 開發(fā)中流行的一些開發(fā)思想,勢必也會(huì)引導(dǎo)到物聯(lián)網(wǎng)系統(tǒng)中:
- 微服務(wù)化;
- DevOps;
- 容器化。
物聯(lián)網(wǎng)會(huì)吸引互聯(lián)網(wǎng)的優(yōu)秀開發(fā)思想,并演進(jìn)出更優(yōu)秀的架構(gòu)。