標籤:intro 單元 軟硬體 定製 網路互動 class 互動模式 沒有 消費者
作者簡介:李知周,中國科學院微系統與資訊技術研究所博士,物聯網早期創業者,發起了開源物聯網項目 Openfpgaduino,目前在國際知名投資銀行從事基於大資料與機器學習的網路安全開發。
本文為《程式員》雜誌原創文章,未經授權,請勿轉載
關注公眾號“CSDN 物聯網開發”公眾號,瞭解更多物聯網資訊與乾貨
Jeff Atwood 曾提出“任何能夠用 JavaScript 實現的應用,最終都必將用 JavaScript 實現”他對 JavaScript 的推崇不言而喻。而當下這個物聯網大熱的時代,JavaScript 支援 HTTP 和 JSON、支援函數式編程、可提供互動式環境等特點堪稱適用於物聯網全棧開發。本文詳解了 JavaScript 可參與的每一個物聯網過程,並針對開源項目進行了匯總。
物聯網節點 JavaScript 開發
網路中,HTTP 協議與 JSON 資料格式特別是 RESTful API 無疑具有支配地位,各種雲端服務,資料轉送都基於這些協議來進行。而 JavaScript 為 HTTP 和 JSON 提供了最好的支援,當物聯網系統採用 JavaScript 開發時,天然對接了互連網上海量的雲端服務與雲資源,包括雲端儲存、雲端運算等一系列資源都可被方便調用,就像你在手機端訪問各種雲端服務一樣。微服務構架在伺服器端的興起,讓 JavaScript 編寫的每一個物聯網節點都可以作為一個大系統中的微服務,通過 RESTful API 介面提供自己的服務。
在設計模式上,JavaScript 的回調與事件迴圈等基於事件驅動的編程模型非常適合物聯網。在物聯網環境下,環境在不斷變化,物聯網節點要不斷對環境的變動做出響應,換句話說物聯網系統通常是 I/O 密集型的系統,回調與事件迴圈高效地完成了密集 I/O 操作這項工作,而事件響應式編程相比於多進程和多線程編程在記憶體的使用上又非常高效,而這又是物聯網系統所需要的,通常物聯網系統都是資源受限系統,記憶體與 CPU 的頻率都非常有限。物聯網節點底層開發中通常採用中斷響應模式,在 CPU 中由稱為中斷控制器的硬體來檢查中斷訊號的出現,並在中斷出現後控制 CPU 執行特定程式片段,這一執行模式和 JavaScript 的回調一致,很容易使用 JavaScript 回調機制來實現硬體的中斷響應。
物聯網節點的部署特點決定了其回收維護成本非常高昂甚至是不可接受的。而物聯網節點要不斷應對新的環境與應用需求,所以在開發中物聯網節點的遠程部署與更新是非常重要的一個功能。JavaScript 本來就是實現從伺服器端向用戶端部署的一門語言,其天然就具有在網路上實現遠程部署的屬性,實現起來就像你用瀏覽器下載 JavaScript 指令碼並運行一樣簡單。JavaScript 的熱部署也是一個比較熱門的研究領域,通過熱部署,物聯網節點可以實現在運行過程中遠程添加新功能,遠程修正 bug。
前面講了使用 JavaScript 來做物聯網開發的好處,那麼也有必要講一下 JavaScript 在物聯網應用中相對於 Web 應用程式的不同以及誤區。第一個問題就是即時性。作為嵌入式系統的物聯網網關,首要面對的就是即時性問題,比如各種電機的控制,一些電壓訊號的採集都是有即時性要求的,需要在規定的時間內完成所需工作。由於 JavaScript 的記憶體管理使用垃圾收集機制,所以必然存在由於垃圾收集而導致應用中斷執行的情況,甚至有可能在一些情況下造成即時性要求遭到破壞。所以在設計 JavaScript 物聯網即時程式時需要考慮記憶體垃圾資料時間對即時性的影響。當然,也可以採用另一個設計模式,就是把即時任務使用 C 語言編寫的單獨線程來實現,利用 JavaScript 的單線程特點,這種設計模式不會在嵌入式系統中佔用過多的資源,畢竟 JavaScript 本來就是一種嵌入在瀏覽器裡的語言。另一方面,由於物聯網網關是需要長期啟動並執行裝置,相對於 Web 端需要有更高的可靠性與穩定性,所以單元測試與整合測試是必須的,而且需要使用程式碼分析工具保證代碼沒有任何記憶體及檔案控制代碼的泄漏。即使在垃圾收集環境下,記憶體流失也是存在的,而在嵌入式系統中由於記憶體有限,特別容易泄漏。好在伺服器端 JavaScript 的開發應用已經有很長一段時間了,可以從伺服器開發裡借鑒不少工具。
JavaScript 物聯網節點開發開源項目匯總
OpenFPGAduino(https://github.com/OpenFPGAduino/)是筆者設計的基於 Node.js 與 FPGA 的開源物聯網軟硬體開發平台,與 Arduino 等快速原型開發平台類似。基於 Node.js 提供了網路互動能力,特別包括用於開發的網路識別碼E 以及類似於樹莓派的 Linux 軟體開發系統,方便安裝各種 Linux 通用軟體,並且通過 FPGA 提供了可程式化的相容 Arduino 外圍介面用於與豐富的物聯網感應器進行串連。
iotjs(https://github.com/Samsung/iotjs)是三星開發的嵌入式 JavaScript 執行環境,能夠在幾百 KB 記憶體的嵌入式系統上,不依靠作業系統實現完整的網路與 JavaScript 支援。JavaScript 解釋引擎採用
JerryScript(https://github.com/jerryscript-project/jerryscript),事件迴圈採用 libtuv。可以說是 Node.js 的嵌入式版本,其 API 與 Node.js 相相容。
Esprunio(https://github.com/espruino/Espruino)是為微控制開發的嵌入式 JavaScript 解釋引擎,提供了最小化的配置,可以在記憶體低至 8KB 的微控制器上執行 JavaScript 語言。
Cyclon(https://github.com/hybridgroup/cylon)是使用 JavaScript 來做機器人控制的項目,支援市面上主要的開發板,通過提供各種外設的驅動,實現了不需要寫一句 C 語言就能開發和組裝一個機器人。
物聯網 JavaScript 大資料處理
現在大資料技術方興未艾,在這些技術中,最基本的思想是 MapReduce,這一思想將不同運算拆解為 Map 與 Reduce,然後將這些 Map 與 Reduce 任務在叢集當中最大限度地並存執行。實現 MapReduce 模式編程最重要的一點就是支援函數式編程或者又稱為 Lambda 編程,所有的 Map 與 Reduce 操作都接受函數式編程作為參數。大資料的成功推動了函數式編程的複興,由此多數現代程式設計語言包括 C++與 Java 的新版本均支援函數式編程。JavaScript 在它出生的那一天就支援函數式編程,其回呼函數就是一種函數式編程模式。自然而然,支援 Map 與 Reduce 也不是什麼困難的事情,因此使用 JavaScript 做物聯網大資料分析與處理非常容易而高效。JSON 資料格式因為格式簡單、處理方便的特點而受到不少青睞,被大量應用於 HTTP 網路傳輸,現有互連網上的基礎設施與雲端服務也都採用 JSON 格式。以這些設施作為資料來源,就要使用 JavaScript 來處理大資料,這是因為 JSON 作為 JavaScript 程式碼片段,本質上來說一切基於 RESTful API 設計的介面幾乎都是對 JavaScript 友好的,當然為了效率,有時會使用 JSON 的二進位形式 BSON。
由於物聯網的對稱性,物理網的節點不僅可以是資料的收集者,同樣可以是資料的發起者,使用 JavaScript 來處理物聯網大資料,那麼每個物聯網資料節點也能夠發起大資料的處理,並利用後台大資料環境做出決策並響應環境的變化。這樣利用 JavaScript 將物聯網前端和後端資料處理直接無縫連結起來,實現了大資料的即時處理與響應的 Lambda 構架,並同時完成了批處理與即時處理構架的統一。在未來,可以用 JavaScript 設計基於 Node.js 的處理架構,把物理網節點當作大資料節點來統一物聯網中資料的處理與傳輸。
機器學習作為現在最熱門的大資料處理手段不得不提。由於 JavaScript 在瀏覽器端的支配地位,使用 JavaScript 做機器學習的嘗試也非常多,有了 JavaScript 的機器學習庫,就可以非常簡單地在瀏覽器上運行一些機器學習的小程式,同樣也可以將這些機器學習庫運行在 Node.js 上,使得物聯網節點也具有一定的機器學習能力及資料處理能力。當然使用 JavaScript 直接控制深度機器學習叢集也是一個不錯的選擇,JavaScript 在資料視覺效果方面的成功,協助了它能夠很方便地可視化機器學習的過程與結果,方便以遠程方式來控制機器學習叢集。
JavaScript 物聯網大資料開源項目
Eclairjs(https://github.com/EclairJS/eclairjs-node)是基於 Node.js 的 Spark 大資料處理平台前端,通過 Eclairjs,可以使用 JavaScript 來操作基於記憶體處理的巨量資料分析平台 Spark,通過 Spark 內建的調度器,實現了在整個叢集上調度資源,以最大化並行度來執行 JavaScript 的演算法。目前,Spark 是最主流和發展最快的大資料處理平台。
skale(https://github.com/skale-me/skale-engine)是一個完全使用 JavaScript 開發,採用 Node.js 作為執行環境的分布式資料處理系統,具有比 Spark 更快的效能。
MQTT 是為物聯網設計的輕量級通訊協議,協議基於 TCP/IP,適用於低頻寬不可靠環境。協議的開銷非常小,支援發布訂閱模式,是種非常高效的通訊協定。MQTT.js(https://github.com/mqttjs/MQTT.js)是 Node.js 的 MQTT 通訊模組,實現了 Node.js 收發 MQTT 資料。
Kafka 是大資料分布式訊息匯流排,提供了對海量訊息的持久化能力,通過將接收到的資料直接持久化到硬碟,提供了穩定的資料輸送量以及高可用性。Kafka Rest(https://github.com/confluentinc/kafka-rest)模組為 Kafka 訊息匯流排提供了 Restful API 的支援,無論是使用瀏覽器還是 Node.js 都可以方便使用 JavaScript 來收發訊息。
convnetjs(https://github.com/karpathy/convnetjs)是完全用 JavaScript 寫成的神經網路機器學習庫,可以運行在瀏覽器中或 Node.js 中。convnetjs 提供了許多有趣的例子,在瀏覽器上實現了對神經網路學習過程的可視動畫呈現與互動模式,對理解神經網路機器學習有非常好的協助。
作為深度神經網路學習方向最重要也是最熱門的項目,Google 的 TensorFlow 是深度學習開源的裡程碑。TensorFlow 的開源使得使用深度學習來做資料處理已經不再是一件高難度的事情。Node-tensorflow(https://github.com/node-tensorflow/node-tensorflow)是一個 NodeJS API,使用了 Google 的開源機器學習庫 TensorFlow。
物聯網 JavaScript 資料展示
在瀏覽器端,JavaScript 在資料的可視化方面早已處於支配地位,作為現在幾乎唯一可在所有瀏覽器上啟動並執行程式設計語言,使用 JavaScript 不僅可以給使用者提供互動環境,而且可以做出非常漂亮的圖表與動畫效果,包括兩維的圖表曲線以及三維的虛擬空間,都可以使用 JavaScript 控制瀏覽器來實現,現在許多基於瀏覽器的 VR 環境也可以通過 JavaScript 來開發了。使用 JavaScript 來做物聯網的資料展示實在太合適不過了。
當今互連網世界,JavaScript 已經是一種全棧網路開發語言。特別是 HTML5 興起以後,JavaScript 不再局限於瀏覽器端,而是將觸手伸到了網路的方方面面,包括物聯網端、手機的移動端和傳統的 PC 端。HTML5 為瀏覽器設計,很好地發揮了 JavaScript 的跨平台特點,真正做到了開發一次 JavaScript 代碼,從手機上的 iOS、Android 到電腦端的 Windows、macOS、Linux 的跨平台運行。雖然目前 JavaScript 在效能上仍然無法與原生開發應用相匹敵,但是僅使用單一的 JavaScript 來開發各種應用程式,開發成本與響應速度上是其他開發方式所無法比擬的。特別是在物聯網開發環境中,很多應用是輕量級的,對效能沒有特別高的要求,但是卻需要依照不同物聯網環境進行不同的定製與適配,JavaScript 來做這樣的資料展示工作再合適不過。根據網路的對稱性特點,甚至於,完全可以用 JavaScript 來實現在物聯網節點上完成資料展示的工作,一如我們用手機來進行資料展示與控制。
JavaScript 資料展示開源項目匯總
D3(https://github.com/d3/d3)是基於 SVG 的向量圖操作工具。通過使用 JavaScript,D3 將資料以向量圖形式展示出來並提供了任意伸縮的能力,在 HTML5 出現之前,D3 是二維可視化的底層標準。通常許多繪製圖表與資料視覺化工具都使用 D3 作為底層驅動引擎,在其之上提供方便使用的 API 介面。
three.js(https://github.com/mrdoob/three.js/)是基於 WebGL 的 JavaScript3D 繪圖工具。通過 WebGL 擴充,JavaScript 語言實現了直接驅動底層顯卡進行 3D 繪圖。three.js 在 3D 映像基礎上還提供了 VR 支援,可以方便的使用 JavaScript 來實現 VR 資料展示。
ionic(https://github.com/driftyco/ionic)是基於 AngularJS 的移動端跨平台開發環境,能夠在一個統一的架構下使用 JavaScript HTML CSS,同時完成開發 iOS、Android、Window Phone 程式,並根據各個環境的不同 UI 做自動適配。
Electron(https://github.com/electron/electron)是基於 Node.js 與 chrome 的跨平台案頭開發環境,electron 通過將瀏覽器核心和後台 Node.js 服務進行打包,實現了一個使用 JavaScript 的全棧開發環境,無需任何修改就能夠將程式部署到 Windows、macOS、Linux 平台上。
nw(https://github.com/nwjs/nw.js)是輕量級的 JavaScript 跨平台案頭開發環境,它實現了在 HTML 程式碼中直接調用 Node.js 的各種 API 函數,提供了一個平滑自然的案頭應用開發環境,隱藏了用戶端伺服器編程的細節。
物聯網 JavaScript 執行個體講解
為更好理解 JavaScript 物聯網開發,下面以筆者設計的物聯網系統為例,詳細介紹物聯網系統的設計。所有設計資料都是開源的,讀者可以對照源碼網頁與文檔。( http://openfpgaduino.github.io)
物聯網網關最小系統硬體設計
對於應用於物聯網的嵌入式系統,系統的硬體設計是重要的組成部分,通常來說應對不同的應用,嵌入式硬體的系統設計會有所不同,每個系統都會按照相應的應用情境進行調整。但是物聯網的核心系統通常是一個設計構架可以應用於一大類的系統,所需要調整的通常是外圍裝置。
圖 1
1 所示是筆者設計的物聯網網關最小系統,在系統設計思想上首先保證了核心系統的通用性,採用了 ARM 處理器。因為是網關節點,設計上需要網關直接連接 IP 網路並提供全功能的網路服務,因此選擇了能夠完整運行 Linux 系統的 ARM9 處理器,運行完整的 Linux 也是能夠運行 Node.js 與完整 JavaScript 的必要條件。由於採用了標準 Linux,雖然 Linux 核心提供了一些即時性補丁,但由於編程模型複雜而且也不適合與 Node.js 整合,因此在最小核心系統中加入了 FPGA。FPGA 能夠在硬體層面完成即時響應,解決了系統的即時響應需求,其次由於 FPGA 是一種可配置系統,能夠根據應用需要進行設計與配置,所以引入 FPGA 也極大提高了系統的適配能力,為靈活適配各種不同物聯網應用提供了基礎。
物聯網網關係統軟體設計
物聯網網關的軟體設計完全是基於硬體設計的構架,最大限度發揮硬體的功能,設計流程如下:
- 首先在 ARM9 處理器上運行完整的 Linux 系統,其擁有完整的網路服務,並能根據需要通過 APT-GET 命令來安裝所需要的軟體包。
- 在 Linux 系統基礎上,運行 Node.js+MongoDB 來提供所有網路服務。
- 在 Node.js 裡運行 HTTP 伺服器來提供基於 Restful API 的各種本地服務,包括各種外設與 I/O 的控制。
- 運行 HTTP 伺服器,基於 RESTful API,實現了基於 HTML5 的雲 IDE 開發環境。方便技術極客對網關的功能進行定製,這些 IDE 包括了 JavaScript 的 IDE,基於圖形編程的 Blockly IDE 和可以配置 FPGA 模組功能和引腳定義的 Web 設計工具,當然也包括較為底層的 C 語言識別碼E。
有了這些功能,使用者就可以根據自己的需要,編寫簡單的程式來控制與物聯網網關串連的任何裝置,實現自己的智能物聯網。
在板子內部,通過實現 Linux 核心驅動的使用者空間模式,實現了 Node.js 直接存取 FPGA 記憶體空間、控制 FPGA 內部邏輯,並最終控制與 FPGA 相串連的各種物聯網外設的功能。同時還實現了 Node.js 對 FPGA 的現場再配置,這樣直接通過網路下載 FPGA 設定檔,即可現場改變整個核心系統。
物聯網網關係統軟體設計
物聯網雲構建系統設計
3 所示是物聯網網關的雲構建系統,圖中可以看到物聯網雲構建系統由 GitHub,Docker Build 與七牛雲端儲存三部分組成。雲構建系統的想法來源於持續整合,在軟體工程裡,持續整合的概念已經非常普遍了,每次有代碼改動的提交都會觸發一個編譯測試的持續過程。模仿軟體持續整合,在雲端構建了一個對應於物聯網網關的持續整合環境,選擇雲端是因為嵌入式系統本身的能力與處理速度都有限,不適於做為持續整合的構建環境。在雲構建系統中,使用 GitHub 來管理代碼的基礎版本,使用 Docker Hub 的容器構建機制完成應用程式與 FPGA 程式的構建,最後使用七牛雲做為構建結果的分發平台。所有開發板通過 RESTful API 驅動雲編譯環境,並訪問七牛雲來實現程式配置的升級。利用這一套雲持續整合系統,不僅可以迅速對應用進行部署而且可以開放支援使用者進行自訂開發的雲開發環境,使用者利用這一雲環境,能夠輕鬆實現對 FPGA 的定製設計,實現一套雲端 FPGA 設計環境。
物聯網網關的雲架構
物聯網大資料處理系統設計
4 所示是物聯網大資料處理系統的設計構架圖,物聯網網關上收集到的物聯網資料被系統上的 Node.js 源源不斷地送往大資料訊息匯流排 Kafka 的 HTTP proxy,每一個 Kafka HTTP proxy 可以承接數千個這樣的物聯網網關,而 proxy 又將匯總的的資料發送到 Kafka 的叢集中做進一步匯總,然後在 Kafka 叢集內部實現對資料的 ETL 過程,包括資料異常值的過濾,重複資料的去除,資料格式的轉換。最後利用 Kafka 叢集,將資料發送到不同的下遊消費者那裡,先發送到大資料存放區系統 S3 或者 HDFS 做永久儲存,為將來用 Hadoop 或者 Spark 等離線分析系統提供資料;接著資料被發送到 Elasticsearch 中做索引,方便對資料進行快速的搜尋與查詢,並且利用 Kibana 做資料的可視化,提供整個資料流的健康狀態監控;最後資料被發送到即時線上大資料處理系統 Spark Streaming 中做資料線上分析、機器學習等任務,實現資料在線上分析與響應。
大資料處理系統的設計結構圖
參考文獻
- https://blog.jscrambler.com/javascript-the-perfect-language-for-the-internet-of-things-iot/
- http://fex.baidu.com/blog/2015/05/nodejs-hot-swapping/
- https://cnodejs.org/topic/5659a9e0c4fa25cb27cc3c23
- http://openfpgaduino.github.io/docs/index.html
- http://blog.csdn.net/brucesea/article/details/45937875
- https://www.burakkanber.com/blog/machine-learning-in-other-languages-introduction/
JavaScript —— 下一代物聯網全棧開發