作者简介:李知周,中国科学院微系统与信息技术研究所博士,物联网早期创业者,发起了开源物联网项目Openfpgaduino,目前在国际知名投资银行从事基于大数据与机器学习的网络安全开发。
本文为《程序员》杂志原创文章,未经授权,请勿转载
关注公众号“CSDN物联网开发”微信公众号,了解更多物联网资讯与干货
Jeff Atwood曾提出“任何能够用JavaScript实现的应用,最终都必将用JavaScript实现”他对JavaScript的推崇不言而喻。而当下这个物联网大热的时代,JavaScript支持HTTP和JSON、支持函数式编程、可提供交互式环境等特点堪称适用于物联网全栈开发。本文详解了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的开发应用已经有很长一段时间了,可以从服务器开发里借鉴不少工具。
OpenFPGAduino(https://github.com/OpenFPGAduino/)是笔者设计的基于Node.js与 FPGA的开源物联网软硬件开发平台,与Arduino等快速原型开发平台类似。基于Node.js提供了网络交互能力,特别包括用于开发的网络IDE以及类似于树莓派的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语言就能开发和组装一个机器人。
现在大数据技术方兴未艾,在这些技术中,最基本的思想是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在数据可视化方面的成功,帮助了它能够很方便地可视化机器学习的过程与结果,方便以远程方式来控制机器学习集群。
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控制浏览器来实现,现在许多基于浏览器的VR环境也可以通过JavaScript来开发了。使用JavaScript来做物联网的数据展示实在太合适不过了。
当今互联网世界,JavaScript已经是一种全栈网络开发语言。特别是HTML5兴起以后,JavaScript不再局限于浏览器端,而是将触手伸到了网络的方方面面,包括物联网端、手机的移动端和传统的PC端。HTML5为浏览器设计,很好地发挥了JavaScript的跨平台特点,真正做到了开发一次JavaScript代码,从手机上的iOS、Android到电脑端的Windows、macOS、Linux的跨平台运行。虽然目前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物联网开发,下面以笔者设计的物联网系统为例,详细介绍物联网系统的设计。所有设计资料都是开源的,读者可以对照源码网页与文档。( http://openfpgaduino.github.io)
物联网网关最小系统硬件设计
对于应用于物联网的嵌入式系统,系统的硬件设计是重要的组成部分,通常来说应对不同的应用,嵌入式硬件的系统设计会有所不同,每个系统都会按照相应的应用场景进行调整。但是物联网的核心系统通常是一个设计构架可以应用于一大类的系统,所需要调整的通常是外围设备。
如图1所示是笔者设计的物联网网关最小系统,在系统设计思想上首先保证了核心系统的通用性,采用了ARM处理器。因为是网关节点,设计上需要网关直接连接IP网络并提供全功能的网络服务,因此选择了能够完整运行Linux系统的ARM9处理器,运行完整的Linux也是能够运行Node.js与完整JavaScript的必要条件。由于采用了标准Linux,虽然Linux内核提供了一些实时性补丁,但由于编程模型复杂而且也不适合与Node.js集成,因此在最小核心系统中加入了FPGA。FPGA能够在硬件层面完成实时响应,解决了系统的实时响应需求,其次由于FPGA是一种可配置系统,能够根据应用需要进行设计与配置,所以引入FPGA也极大提高了系统的适配能力,为灵活适配各种不同物联网应用提供了基础。
物联网网关系统软件设计
物联网网关的软件设计完全是基于硬件设计的构架,最大限度发挥硬件的功能,设计流程如下:
有了这些功能,用户就可以根据自己的需要,编写简单的程序来控制与物联网网关连接的任何设备,实现自己的智能物联网。
在板子内部,通过实现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/