鉴于临近空间探测的复杂性和探测数据的多样性及重大的应用价值, 中国科学院设立了临近空间探测科学实验项目. 临近空间探测数据实时可视化展示是临近空间探测项目的重要组成部分, 通过实时监控探测数据的变化, 为飞行任务决策提供支撑, 有利于提升临近空间探测任务安全、稳定的开展. JavaScript是目前最流行的客户端编程语言, 自2016年起就有逐渐取代Java和PHP的趋势[1]. NodeJS本质上是采用了谷歌浏览器V8引擎的JavaScript运行环境, 其非阻塞模式的I/O处理带来了相对低系统资源耗下的高性能与出众的负载能力, 非常适合用作依赖其他I/O资源的中间服务. 因此, NodeJS被认为是数据密集型分布式部署环境下的实时应用系统的完美解决方案[2,3]. 载荷/载荷舱监控系统实现需要考虑在有限带宽的高比特率条件下系统与临空飞行器实时通信, 同时保障数据展示的实效性. 使用UDP无状态协议连接, 使得资源消耗小, 数据传递快, 同时可以分配到不同机器处理, 做到完全无状态的横向处理[4]. 临近空间探测试验是高寒野外环境下开展, 其具有网络可靠性不高、数据流大的特点, 传统的同步阻塞I/O处理模式在对数据流进行处理时, 数据下传效率与数据处理能力很难同时得到效率上的提升, 线程很容易在做数据处理过程中阻塞数据传输的进行, 造成系统内资源的浪费, 进而导致在过程中无法处理其他任务, 例如数据块写入文件, 或者读取其他数据[5,6]. 因此需要设计一种改进的数据解析与展示方法, 在不阻塞数据下传的同时提高软件的数据处理能力.
2 基于非阻塞模式的数据解析与展示方法 2.1 NodeJS I/O与Java I/O处理模式比较理论上在处理计算方面, NodeJS单条主线程并没有太多优势, 然而如果涉及IO密集型任务, 由于NodeJS在每个级别强制支持非阻塞API规范, 因此能更高效地利用CPU和内存资源. 表1对比了NodeJS与Java在I/O处理中的特点.
近年来不少知名互联网公司包括阿里、腾讯、苏宁, 都有尝试用NodeJS代替Java应用于自身I/O密集型业务场景的成功案例[9].
2.2 NodeJS异步非阻塞I/O处理基本原理一般情况下, 异步非阻塞I/O处理流程是发送方向接收方发送请求后, 不等待响应可以继续其他工作. 接收方收到请求后, 进行I/O操作时如果不能返回结果. 其不是等待, 而是立刻返回去做其他工作. 当I/O操作完成时, 再将完成状态或结果通知接收方, 接收方再响应发送方[5-15].
异步非阻塞处理是基于应用程序重复调用I/O操作轮询线程池来完成[8-11]. NodeJS使用的是单线程异步非阻塞模型, 对所有的I/O都采用异步请求方式, 这种设计的底层依托的是C++高性能事件驱动libuv库, 该驱动库提供了线程池, 事件池, 跨平台, 异步I/O处理能力等[1]. 如图1所示, NodeJS的主程序只有一个主线程作为执行栈执行程序代码. 主线程通过libuv库对事件队列与系统线程池进行维护, 从事件队列取出相应的事件, 再从线程池中分配一个线程去执行该事件. 主线程会通过libuv库不断对事件队列轮询从而检查未执行的事件. 当子线程对事件执行完毕, 主线程执行回调, 子线程被释放归还给线程池. 因此基于NodeJS异步非阻塞I/O处理操作实际上是通过libuv维护的线程池完成的. 由于主线程将所有的事件通过libuv分配给了线程池中的子线程, 因此主线程基本只负责事件调度, 没有进行真正的I/O操作, 从而实现了异步非阻塞I/O.
2.3 数据实时解析与展示
在临近空间科学探测试验过程中, 载荷/载荷舱通过专用测控链路与地面测控舱通信, 数据通过服务端存储并通过UDP广播分发数据. 本文针对载荷/载荷舱下传的单帧数据的特征, 设计了针对载荷/载荷舱监控的异步非阻塞I/O模式处理方法[16-20]. 处理流程如图2所示.
客户端通过UDP协议与数据发送端建立连接, 并接收数据包数据流. 在该套接字模块中使用了数据报dgram模块, dgram提供了UDP数据包实时通信Socket的实现方法. 该模块的API包括事件和方法两大类, 事件类在UDP连接状态发生改变时触发, 包含关闭(close), 错误(error), 监听(listening), 消息(message); 方法类包含绑定端口主机(bind), 返回对象地址(address), 关闭实时通信(close), 广播发送数据报(send)等[21].
程序套接字处理部分通过引用NodeJS中的dgram模块建立基于UDP的网络通信, 模块通信流程如图3所示. 该模块可对服务端的发送地址和端口进行绑定, 注册监听事件. 在客户端连接服务端监听状态发生改变时, 客户端可接收服务端发送的数据. 客户端获取数据后,会触发NodeJS的异步非阻塞I/O处理流程, 主程序会通过libuv使用事件队列维护接收的数据[1].
非阻塞I/O模式处理方法利用NodeJS中的Buffer类来创建专用的二进制数据缓存区, 并利用其提供的一系列API接口对数据进行操作. 如图3中服务端send()与客户端recv()方法中传递的数据类型. Buffer类的内存申请并不是通过NodeJS V8引擎完成, 而是由C++实现. 底层是通过slab机制对碎片进行管理. 当数据小于8 KB时, 通过new Buffer(8000)申请一个可用空间为8000字节的slab. 在对服务端发送端口监听的过程中, 可直接对内存进行密集的I/O操作. 在这个过程中slab机制进行了预先申请和事后分配, 这使得JavaScript到操作系统之间没有过多的关于内存申请的系统调用, 提高了数据处理的效率.
非阻塞I/O模式处理方法利用dgram模块会将接收的二进制字节流封装成Buffer类, 根据预先约定的协议, 利用数据处理函数, 对Buffer按位解码. 再将十进制明码数据集合逐个赋给原型JSON数组. 表2是JSON数组的主要字段描述.
非阻塞I/O模式处理方法对二进制字节流解码时会读取原型JSON数组中的length属性, 该属性标识了二进制字节流中每个字段所占字节长度, 通过该长度对字节流逐位解码. 再将解码后的值返回给原型JSON数组. 最后将获得一维数组供后续模块使用.
页面渲染模块在获取一维数组前, 数据流传入验证函数, 数据通过有效性验证后, 再利用ECharts组件对数据进行可视化图表展示. 这里JavaScript类库ECharts其底层依赖轻量级的 Canvas 类库ZRender, 可以流畅的运行在 PC 和移动设备上, 并兼容当前绝大部分浏览器, 可提供直观的数据可视化图表[22]. 由于第三方开源组件ECharts对DOM的渲染效率不可控, 同时系统解码速率远高于图形渲染速率. 所以在获取等待展示的一维数组后, 系统采用了响应式处理方法, 使解码模块与DOM渲染模块解耦并通过异步数据流构建处理关系. 当渲染模块出现阻塞时, 不影响数据获取与解析, 以保障下传数据的完整和准确性.
载荷/载荷舱监控客户端的开发还引入了由Github发布的跨平台桌面应用工具ElectronJS. 该应用工具封装了谷歌的Chromium浏览器引擎作为图形应用界面, 允许基于NodeJS的载荷/载荷舱监控客户端通过ElectronJS在没有部署NodeJS开发环境的任意操作系统中使用NodeJS API, 从而实现了NodeJS网页应用到桌面应用的转换. 图4为载荷/载荷舱监控客户端在MacOS系统下的软件界面.
3 性能测试
性能测试编译工具使用的是ElectronJS内置的控制台. 实验机器为MacBook Pro (Retina, 15-inch, Mid 2015) CPU2.2 GHz intel corei7, 显卡Intel Iris Pro 1536 MB. 通过在试验机器搭建模拟服务, 通过UDP协议连接客户端并发送数据, 同时在数据解析模块与Echarts数据渲染模块中设置计时函数, 对软件解码及渲染的能力进行测试统计.
如图5所示, 服务端以22 B/s的速率向客户端发送二进制数据流. 数据解析模块完成二进制字节流转换一维数组耗时0.27 ms, 代入公式
该系统参加了临空2019年7~9月在青海省海西蒙古族藏族自治州大柴旦地区的外场试验. 系统通过Electron-Package打包为EXE可执行文件, 并部署在CPU2.5 GHz intel corei7 Windows10系统的移动工作站中, 数据传输率为100 Mb/s. 在试验期间系统运行34小时19分, 获取、解析并存储数据12万包, 各项功能工作状态稳定, 为各试验载荷及载荷舱系统的监视与控制提供了可靠的数据支持.
4 总结
本文使用NodeJS+ElectronJS+EchartsJS架构, 采用固定码率数据非阻塞模式实时解析与展示方法, 实现了对临空探测试验载荷/载荷舱的实时监控, 实时解析并展示数据理论可达80 MB/s. 由于利用封装好的libuv库维护线程池, 因此相对于手动维护多线程的方法能有效地节省开发成本, 在保障下传数据准确性的同时, 能有效利用CPU和内存资源. 经过临空野外试验的验证, 该解析与展示方法适用于资源受限环境下的野外科学试验. 在需要I/O密集型场景下进行可视化数据展示架构中, 本模式非常值得推广.
[1] |
Ciszewski B. Node. js Performance: How Your Web App Can Benefit from Node. Js? https://www.netguru.co/blog/nodejs-performance-web-application-benefit. [2020-09-21].
|
[2] |
Peterson C, Cook V, Dechev D. Practical progress verification of descriptor-based non-blocking data structures. Proceedings of 2019 IEEE 27th International Symposium on Modeling, Analysis, and Simulation of Computer and Telecommunication Systems. Rennes, France. 2019. 83–93.
|
[3] |
Kiessling M. The Node Beginner Book. https://www.nodebeginner.org. [2020-09-25].
|
[4] |
陈冈, 夏火松. 基于异步文件通道的Java Web多任务分块文件上传. 河南理工大学学报(自然科学版), 2015, 34(3): 400-405. |
[5] |
李汝佳, 胡婧. 基于Nodejs的异步非阻塞服务器研究. 计算机科学与应用, 2013, 3(3): 191-194. |
[6] |
贺杰. 非阻塞输入输出在信息交换系统中的应用. 软件导刊, 2011, 10(5): 135-137. |
[7] |
许会元, 何利力. NodeJS的异步非阻塞I/O研究. 2014年全国工业控制计算机技术年会论文集. 重庆, 中国. 2014. 151–156.
|
[8] |
龚黔芬. 解析Java中的阻塞I/O与非阻塞I/O控制. 重庆文理学院学报(自然科学版), 2006, 5(1): 18-20. DOI:10.3969/j.issn.1673-8012.2006.01.007 |
[9] |
林力文. 探究Node. js技术特性在电信IT支撑领域的应用. 计算机产品与流通, 2019(12): 32-33. |
[10] |
袁劲松, 马旭东. 基于阻塞与非阻塞I/O网络模型的Java语言实现. 计算机系统应用, 2008, 17(9): 98-101. DOI:10.3969/j.issn.1003-3254.2008.09.026 |
[11] |
程超, 杨风召. 基于Java非阻塞I/O开发高性能网络应用程序. 电子工程师, 2006, 32(10): 71-73. DOI:10.3969/j.issn.1674-4888.2006.10.024 |
[12] |
陈刚. 非对称数据率网络下的无阻塞连接算法. 计算机时代, 2013(7): 11-12, 16. DOI:10.3969/j.issn.1006-8228.2013.07.004 |
[13] |
刘晓建, 吴庆波, 戴华东, 等. 一种用于并行系统的非阻塞消息队列机制. 计算机工程与科学, 2011, 33(4): 75-80. DOI:10.3969/j.issn.1007-130X.2011.04.014 |
[14] |
边耐政, 刘玄. 基于非阻塞的分布式事务提交协议的实现. 计算机应用与软件, 2014, 31(7): 89-92, 104. DOI:10.3969/j.issn.1000-386x.2014.07.024 |
[15] |
熊安萍, 唐巍, 蒋溢. 一种非阻塞读文件系统的实现方法. 计算机工程, 2011, 37(5): 71-73, 76. DOI:10.3969/j.issn.1000-3428.2011.05.024 |
[16] |
钟德福, 张良国, 艾红, 等. 基于NodeJS的渔业资源调查数据采集系统框架重构. 渔业现代化, 2019, 46(6): 104-109. |
[17] |
张海龙, 张萌, 王杰, 等. 基于MPI和Taurus高性能计算系统的Jacobi并行迭代算法. 吉林大学学报(工学版), 2019, 49(2): 606-613. |
[18] |
李正学, 许捍卫. 异步非阻塞瓦片地图服务器的实现. 测绘科学, 2015, 40(10): 128-132. |
[19] |
冉从敬, 徐晓飞. 基于NodeJS+ECharts的专利权人引证关系可视化方法研究. 情报科学, 2018, 36(8): 77-83. |
[20] |
徐瑞. 基于WebSocket与WebGL的城市三维协同规划. 测绘地理信息, 2019, 44(6): 96–98, 102.
|
[21] |
雷津, 赵寅. VC++环境下的UDP网络通信实现. 电子测试, 2017(13): 36-38. DOI:10.3969/j.issn.1000-8519.2017.13.016 |
[22] |
Tsigas P, Zhang Y. Non-blocking data sharing in multiprocessor real-time systems. Proceedings of the 6th International Conference on Real-Time Computing Systems and Applications. Hong Kong, China. 1999. 247–254.
|