2024年1月14日发(作者:)
摘要
摘 要
近年来,随着云计算、物联网、社交媒体等新兴信息技术和应用模式的快速发展,人类社会不断地向大数据时代迈进。大数据时代下的流式数据呈现出实时性、突发性、无序性等特点,这对流式数据处理系统就有了更高更严格的要求。如今,现有的实时流数据处理系统通常面临着业务扩展困难、数据流管理困难的问题,本文旨在解决实时流数据处理中所面临的这两大问题,在保证数据处理的实时性和高效性的前提下,提出了一套新的基于Node-red的数据流管理和Redis内存计算的实时流数据处理模型。
本文从总体架构上对该模型进行设计,重新设计了Node-red的数据输入节点、数据输出节点、数据处理节点以及Redis数据库访问节点,各个节点的开发使用异步编程语言,节点之间的通信是通过Redis的pub/sub机制以及的来完成。最后将这些节点重新安装部署到Node-red中,使其成为一个完整的实时流数据处理模型。在实时流数据处理过程中,经常会遇到最大值、最小值、累计求和、top(n)等数据指标的计算,而计算这些指标的基础就是去重统计,本文通过分析Redis有序集合的源码,结合Skip List的基本原理,提出了基于Redis有序集合的去重统计方法,并通过新设计的Redis数据库访问节点实现该方法在实时流数据处理模型中的应用。
实时流数据处理模型设计完成之后,一个重要任务就是对模型进行应用验证,因此本文设计并实现了一个实时的网站访问监控系统,并利用该模型对数据进行实时处理,最终将分析结果展示在前端可视化界面上。该系统主要包括三个模块,实时数据采集模块、实时数据分析模块以及数据可视化模块,其中,实时数据分析模块是利用本文所设计的实时流数据处理模型来实现的,数据可视化模块是利用的express框架实现的一个web应用,用户只需在浏览器上登录就可以访问监控页面,同时利用highcharts将数据可视化模块中的图表组件化,以此来适应因业务的不断扩展而带来的数据多样化。本文最后对设计的系统进行了功能测试和性能分析,测试结果均已达到要求。
综上所述,本文完成了从模型的设计到模型的应用的全过程,同时其可行性和有效性在实际的生产线上已经得到了验证。
关键字:实时流数据处理,Node-red,Redis,数据可视化,网站访问监控
I
ABSTRACT
ABSTRACT
In the last few years, the rapid developments of new information technique and
application modes such as cloud computing, Internet of Things and social media, are
keeping pushing human society towards the age of Big Data. In the age of Big Data, the
stream data is showing characteristics as real-timing, burstiness and disordering, which,
put higher and stricter request to the stream data processing system. As the current
real-time data processing systems are confronting difficulties of business expanding and
data stream managing, this paper is focused on the solution of the above two problems
by putting forward a new real-time stream data processing model based on flow
management of Node-red and memory computing of Redis.
This thesis designs the model from the overall structure, it redesigns the data input
node, data output node, data computing node for Node-red and access node to Redis, the
development of each node uses , which is an asynchronous programming
language, and the communication between nodes is completed through pub and sub
mechanism of Redis and of . Finally, this thesis resigns these nodes to
Node-red to make it a complete real-time data stream computing model. In the process
of real-time data computing, maximum and minimum values, cumulative sum and Top
(n) are often seen, which base on the removing of repetition and then computing. This
thesis comes up with the method of Redis based ordered set to remove repetition and
recount, by analyzing Redis ordered set source code and combining with Skip List, and
implements the application of this method in the real-time stream data processing model
through the newly designed Redis database access node.
One important task after the finishing of designing real-time stream data
computing model is to apply and testify; therefore this thesis designs and achieves the
web-site visiting monitoring system to apply and demonstrate the analyzing results on
screens. This system includes three modes: real-time data acquisition module, real-time
data analysis module and data visualization module. Among them, the real-time data
analysis module is finished using the real-time stream data processing model, data
visualization module is a web application with the use of express framework,
what users need to do is simply logging in on the browser to access the monitoring page,
while assembling the chart in data visualization module with Highcharts to adapt the
II
ABSTRACT
diversity of data brought about by the expansion of business. This thesis also provides
testing results and function analysis, which all meets the request.
In short, the whole process from designing to the functioning of the real-time data
stream computing model is covered in this thesis, feasibility and effectiveness in the
actual production line has been verified at the same time its.
Key words: real-time stream data computing, Node-red, Redis, data visualization,
web-site access monitoringIII
目录
目 录
第一章 绪 论 .................................................................................................................. 1
1.1 研究背景与意义 ................................................................................................ 1
1.2 国内外研究现状 ................................................................................................ 3
1.2.1 实时流数据处理模型的研究应用现状 ..................................................... 3
1.2.2 Node-red的研究应用现状 .......................................................................... 4
1.2.3 Redis的研究应用现状 ................................................................................ 4
1.3 论文主要工作和研究内容 ................................................................................ 5
1.4 论文章节结构概述 ............................................................................................ 6
第二章 实时流数据处理的基础理论和技术 ................................................................ 7
2.1 的事件驱动和非阻塞机制 ................................................................... 7
2.2 Node-red流式数据处理框架........................................................................... 10
2.2.1 Node-red概述 ............................................................................................ 10
2.2.2 Node-red的编程模型 ................................................................................ 10
2.2.3 Node-red的基本配置 ................................................................................ 12
2.3 基于内存计算的数据库. 13
2.3.1 Redis数据库概述 ...................................................................................... 13
2.3.2 Redis数据库的实现原理 .......................................................................... 14
2.3.3 Redis数据库的pub与sub机制 .............................................................. 16
2.4 本章小结 .......................................................................................................... 16
第三章 基于Redis有序集合的去重统计方法的研究 ............................................... 17
3.1 Skip List基本原理 ........................................................................................... 17
3.2 Redis有序集合的源码分析............................................................................. 19
3.3 基于有序集合的去重统计方法 ...................................................................... 23
3.4 本章小结 .......................................................................................................... 25
第四章 实时流数据处理模型的需求分析与设计 ...................................................... 26
4.1 需求分析 .......................................................................................................... 26
4.1.1 实时流数据处理模型的需求分析 ........................................................... 26
4.1.2 网站访问监控系统的需求分析 ............................................................... 27
4.2 模型的总体架构 .............................................................................................. 27
4.3 各数据处理节点的设计 .................................................................................. 28
IV
目录
4.3.1 数据输入节点的设计 ............................................................................... 30
4.3.2 数据输出节点的设计 ............................................................................... 33
4.3.3 数据计算节点的设计 ............................................................................... 36
4.3.4 Redis数据库访问节点的设计 .................................................................. 38
4.4 节点的重新部署 .............................................................................................. 39
4.5 本章小结 .......................................................................................................... 40
第五章 实时流数据处理模型在网站访问监控系统中的应用 .................................. 41
5.1 网站访问监控系统总体设计 .......................................................................... 41
5.1.1 实时数据采集方案设计 ........................................................................... 41
5.1.2 网站访问监控系统的模块层次结构 ....................................................... 43
5.2 数据分析模块的设计与实现 .......................................................................... 44
5.2.1 数据分析模块的总体设计 ....................................................................... 44
5.2.2 数据库结果集设计 ................................................................................... 46
5.2.3 数据分析算法的设计与实现 ................................................................... 48
5.2.4 在Node-red中的数据处理流程 .............................................................. 55
5.3 数据可视化模块设计 ...................................................................................... 60
5.3.1 数据可视化模块的功能需求 ................................................................... 60
5.3.2 可视化模块的架构设计 ........................................................................... 60
5.3.3 数据显示方法的设计 ............................................................................... 63
5.4 本章小结 .......................................................................................................... 64
第六章 系统测试与性能分析 ...................................................................................... 65
6.1 测试条件准备 .................................................................................................. 65
6.2 系统功能测试 .................................................................................................. 67
6.3 系统性能分析 .................................................................................................. 70
6.4 本章小结 .......................................................................................................... 72
第七章 总结与展望 ...................................................................................................... 73
7.1 本文总结 .......................................................................................................... 73
7.2 对未来工作的展望 .......................................................................................... 73
致 谢 ............................................................................................................................ 75
参考文献 ........................................................................................................................ 76
攻读硕士期间取得的学术成果 .................................................................................... 79
V
第一章 绪论
第一章 绪 论
1.1 研究背景与意义
近年来,随着云计算、物联网、移动互联、社交媒体等信息技术和应用模式的快速发展,人类社会不断地向大数据时代迈进。早在2010年,全球的数据量就已经具有ZB级的规模,有预测显示,到2020年全球的数据量将达到35ZB,大量数据无时无刻地影响着人们的生活、工作,甚至是社会的发展和国家经济,大数据时代已经到来。而近年来,有关大数据方面的研究和应用也越来越广泛,新形式下的大数据分析技术为我们分析问题和解决问题提供了新的思路和方法,其研究已经成为业界的热点。
大数据的分析计算模式主要分为批量计算(batch computing)、流式计算(stream
computing)、交互式计算(interactive computing)、图形计算(graph computing)等等。其中批量计算和流式计算这两种计算模式不管是在学术界还是在工业界都是主要的研究模式,同时各自都有广泛的大数据应用场景。其中批量计算是一种适用于大规摸并行批量处理作业的分布式计算模式,也就是我们大家都十分熟悉的MapReduce计算模式[1,2]。MapReduce本身是一种编程模型,这种分而治之的编程思想有着广泛的应用,尤其在大规模数据集的并行计算中,由于其简单易用的特点使其成为目前最为流行的大数据并行处理模型。后来,在开源社区的努力下,
Hadoop系统[3]应运而生,在Hadoop系统中包括HDFS(Hadoop 分布式文件系统)和MapReduce两个核心组件,HDFS用于存储海量的数据,而MapReduce是用于海量数据的并行处理。Hadoop平台的应用也十分广泛,国内外许多企业都在用它来进行大数据处理。此外,Spark系统[4]也具备批处理计算的能力。而对于流式数据计算,它是一种对实时性要求极高的计算模式,由于数据的到来具有不确定性、无序性、不间断性,因此,为了避免在数据处理过程中造成数据的大量堆积或者数据丢失,这就要求流式计算必须在规定的时间范围内对系统所产生的实时数据完成实时处理。在许多行业的大数据应用系统中都有流式计算的踪影,比如金融银行业的业务监控系统、政府政务管理系统、道路监控系统、互联网行业的访问日志处理等,不仅有大量累计的历史数据,同时还具有高流量的实时流式数据,因而在提供批处理计算模式的同时,系统还需要能具备高实时性的流式计算能力。因此,研究和设计一套高效、稳定的流式数据处理模型具有广泛的应用价值,目前也有比较流行的流式计算系统,有Twitter公司的Storm、Yahoo公司的S4以及Apache Spark Streaming[5]。
1
电子科技大学硕士学位论文
在传统的流式计算模型中,绝大多数都利用传统数据库来实现,而在大数据时代下的流式计算有了新的需求,表现在低时延、高流量、不确定性等。所以,如何构建一个低时延、高带宽、持续可靠、长期运行的大数据流式计算系统[6,7]成为了当前亟待解决的问题。Redis这种基于内存计算的、可进行数据持久化的Key-Value存储系统的诞生,为大数据流式计算提供了一个很好的解决方案。Redis数据库最初是为了解决像SNS这类网站在数据存取过程中的实时性等刚性需求的,而传统的关系型数据库很难完成这项工作,这也使得Redis也越来越受到人们的关注。如今Redis数据库已经得到了广泛的应用,不论是在高速缓存系统中,还是在海量文件的实时检索中,甚至是在如火如荼的各类推荐系统中,Redis都起着举足轻重的作用。Redis基于内存的数据计算和高效的数据存储策略也能够很好的满足实时流计算问题中的低时延、高流量的刚性需求。因此,研究Redis的内存计算以及存储策略并将其运用到实时流式计算模型中具有重要的研究意义和实用价值。
在流式数据处理中,因为无法确定数据什么时候到来,按什么顺序到来,因此,不需要事先对流式数据进行存储,而是当流动的数据到来后在内存中直接进行数据的实时计算和分析。就像我们熟悉的Twitter的Storm、Yahoo的S4就是典型的流式数据处理框架[8,9],数据在任务拓扑中被计算,最后输出有价值的信息。目前这些流行的流式处理框架都有一个共同的缺点就是,没有一个方便的能够快速根据业务构建数据任务的拓扑计算流程,也就是我们所说的数据计算流(flow),同时也缺乏数据的流化功能。Node-red是IBM Emerging Technology基于开发的一个新型开源工具,并且支持的事件驱动和非阻塞IO机制,它是一种可视化流程编辑框架,程序员可以直接通过浏览器上面的流程编辑器,来完成各个节点的连接,这些节点可以是外部设备、网络服务、API应用等。Node-red被广泛用于物联网领域,实现数据的流式传输。在Node-red中从数据的接入,到数据的解析分析,最后到结果的输出都是通过各种各样的节点来完成的,IBM
Emerging Technology团队在开发这个工具的时候只引入了少量的具有特殊功能的节点,比如常用的http节点、tcp节点、udp节点、debug等数据输入输出节点,还有一些用于数据分析的节点比如sentiment节点,也有一些用于访问存储设备的节点,如mongodb节点;Node-red除了原本已经提供的这些节点外,还允许用户自己按照开发原则开发自己需要的节点。为了能够充分利用Node-red的可视化流程编辑的直观性,以及Redis数据库的内存计算的特点,因此探索开发适应于流式数据分析的数据输入节点、数据输出节点、数据处理节点以及Redis数据库访问节点,这对流式数据分析有着重要的实际意义。
2
第一章 绪论
1.2 国内外研究现状
1.2.1 实时流数据处理模型的研究应用现状
大数据时代下的数据处理的两种主要方式就是实时流数据处理[10,11]和批量数据处理。实时流数据处理主要适合于那些无需事先进行数据存储,可以直接进行数据分析处理,实时性要求比较严格,但数据的准确度要求比较宽松的应用场景。而对于传统的批量数据处理,首先要进行数据的存储,然后再对存储的静态数据进行集中或者分布式计算。目前,对于传统的批量数据处理模型的技术和研究成果已经相对成熟了,最初有Google公司的MapReduce并行编程模型[12]的提出,再有后来在开源社区的努力下开发的Hadoop系统为代表的批处理系统,都已经是稳定而高效的批处理系统。而对于流式数据处理模型的研究仅仅处于初级阶段,在早期关于流式数据的研究也主要集中在以传统数据库为中心而开展的,主要是研究了数据计算的流式化,数据规模比较小,数据对象也比较单一,很难适应在大数据时代下流式数据处理所呈现出来的新特性。由于,在新时期的流式数据主要呈现出实时性、突发性、无序性等特点,因此对新的流式计算系统就有了更高更严格的要求。
在国外,Yahoo推出了S4流式数据处理系统,随后在2011年,Twitter也推出了自己的流式数据处理系统Storm,还有就是近年来开源社区新兴的MOA(Massive Online Analysis)、Spark Stream都是流式处理系统[13],这在一定程度上推动了流式数据处理的发展和应用。但是像S4、Strom这样的流式数据处理系统在可伸缩性、容错性、数据吞吐量等方面存在着明显的不足,而对于MOA,Spark
Stream这样的系统,虽然功能和API十分丰富,但是在稳定性和易用性上不尽如人意。所以,如何构建一个低延迟、高吞吐量、易用且能持续可靠地运行的流式数据处理系统,是一个亟待解决的问题。
在国内,目前关于流式数据处理模型的研究还比较少,但目前国内主要有百度公司自主研发的Dstream和TM实时计算平台,在学术界主要是有一些关于流式数据挖掘算法的研究。但是,流式数据的可视化分析已经在很多场景得到了应用,比如各大银行都陆续建立的大屏监控系统,就是实时地监控银行的业务状况、系统运行状况、用户行为分析等,又比如政府网站群的监控,也是通过实时监控网站的访问数据,分析用户的行为。在这些应用的背后,如何建立一个高效、稳定、易于维护的实时处理模型显得尤为重要。
3
电子科技大学硕士学位论文
1.2.2 Node-red的研究应用现状
Node-red作为一种在物联网时代的新型产物,是一种用来快速搭建物联网应用程序的流式处理框架[14,15],在信息无处不在的时代,Node-red也越来越受到业界的关注和研究。
它是由IBM Emerging Technologies团队发起的一个开源项目,其中Nick Leary
和Dave Conway-Jones工程师为Node-red的设计和开发做出了巨大的贡献。2013年,Node-red以开源项目的形式被发布,经过短短几年的发展,Node-red已经拥有了一大批活跃的用户和开发人员。时至今日,但凡用过Node-red的制造商、实验人员和一大批大大小小的公司,都已经见证了Node-red极具价值的应用之处。
在国外,IBM公司率先将Node-red应用到物联网领域,以实现各种服务之间的数据传输。Node-red被集成到IBM公司的最新的云产品Bluemix上,通过Bluemix提供的云服务,用Node-red来建立和管理一个应用流程(在Node-red中称为一个flow),实现消息的推送服务。Node-red与Bluemix中简单的Push服务相结合[16,17],使整个数据处理流程的管理变得十分简单,同时易于维护。
在国内,目前也有很多智能设备制造公司在使用Node-red,可以很方便地通过Node-red节点来控制硬件设备的状态,比如用Node-red搭配Arduino,是一个快速原型化的工具,例如控制RPI的某根管脚位去点亮LED,只要简单的利用四个节点,把他们连接在一起,再写一点数据处理的程序代码即可做到。由于Node-red还在进一步完善当中,原始开发的节点可能很难满足实际的需求,所以,我们在运用Node-red来管理数据流程的时候,还需要自己开发需要的功能节点。在这一点上,目前在不少银行的业务监控系统中引入了Redis数据库的访问节点。
1.2.3 Redis的研究应用现状
Redis作为存储系统[18]之中的后起之秀,由于其数据结构丰富、基于内存计算、支持事务操作又可进行数据持久化等特点,迅速为许多企业和开发者所爱戴。无论是在学术界还是在工业界,对Redis的研究都从未停止过。
Redis是由Salvatore Sanfilippo为实时统计系统LLOOGG量身定制的一个数据库,在2009年的时候将Redis开源发布,并开始与另外一位Redis代码贡献者Pieter
Noordhuis一起继续Redis的开发,直到现在,Redis的代码托管在GitHub上,并且开发也十分活跃。随着Redis内存数据库的发布,经过短短几年的发展,Redis已经拥有了一大批活跃的用户和开发人员。在国外,像GitHub、Viacom、Pinterest等都是Redis的用户,Github利用Redis集群[19],来统计用户项目的跟进状况。而在国内,新浪在研究了Redis数据库的源码后,搭建了号称史上最大的Redis集群,4
第一章 绪论
实现了传统的SQL数据库难以实现的计数分析(counting)、反向缓存(reverse
cache)、top 10 list等功能。近年来,也有不少银行,在自己的实时数据监控平台引入了Redis数据库,实现了数据的实时处理和分析,还有就是随着国家电子政务系统的逐渐推行,不少的地方政府也在自己的数据中心监控系统中引入了Redis数据库,来实现数据实时计算和流式处理。
1.3 论文主要工作和研究内容
本文对大数据背景下流式数据处理过程中所遇到的挑战和难题进行了研究分析,详细研究了Node-red流式处理框架的编程模型和消息推送机制,Redis数据库的实现原理及其基于内存计算的原理。设计了一种新的基于Node-red的流式管理和Redis的内存计算的流式数据处理模型,并通过实际生产线上的网站访问实时监控系统来验证该模型的可行性与高性能。主要工作内容如下:
(1)本文首先对当前实时流数据处理模型的研究应用现状以及Node-red与Redis的研究应用现状进行分析,结合的事件驱动与非阻塞机制详细阐述Node-red的消息推送原理,同时详细研究了Node-red的编程模型。
(2)对Redis数据库做了深入研究。因为在流式数据处理中,经常会遇到关于最大值,最小值,累计求和、top(n)等指标的计算,而去重统计是计算这些指标的基础。因此,本文通过分析Redis有序集合的源码,结合Skip List的基本原理,提出了基于Redis有序集合的去重统计方法。
(3)在研究分析了流式数据的特点和流式数据处理的基本原理后,结合Node-red的编程模型和消息推送机制,设计了一种新的基于Node-red的流式管理和Redis的内存计算的流式数据处理模型。由于原始的Node-red缺乏对Redis数据库的访问节点以及Redis的pub/sub节点,重新设计了新的数据输入、输出节点以及数据处理函数节点(function_node),并安装部署到Node-red框架当中,实现数据的流式处理和数据流的管理,使其成为一个完整的实时流数据处理模型。
(4)本文最后将设计好的流式数据处理模型,应用到实际生产环境中加以验证。使用该模型对某政府网站的访问流量数据进行实时分析,设计了一套实时数据监控系统,该系统包括了数据的实时采集、实时分析和处理,以及最后的数据可视化展示,并对结果进行了有效性分析,同时对整个系统进行了功能测试与性能分析。实现了从模型设计到模型应用的全过程。
1.4
论文章节结构概述
本文共分为七章,其章节结构安排如下:
第一章,绪论,首先介绍了本文的研究背景和意义,通过阅读大量相关文献和论文资料,总结了国内外流式数据处理模型的研究现状,以及Node-red、Redis5
电子科技大学硕士学位论文
的研究应用现状。然后简单的介绍了本文的主要研究内容和全文的章节结构安排。
第二章,实时流数据处理的理论基础和技术,本章详细介绍了的异步非阻塞模式与事件驱动机制,这是进行Node-red节点开发的理论基础,同时详细介绍了Node-red可视化流式处理框架及其编程模型,本章最后还介绍了关于Redis数据库的实现原理和Pub/Sub机制。
第三章,基于Redis有序集合的去重统计方法的研究,分析Redis有序集合的底层源码,结合Skip List算法提出了Redis有序集合在实时流数据处理中的去重统计方法。
第四章,实时流数据处理模型的需求分析与设计,本章首先对在实际场景中的流式数据处理应用做了详尽的需求分析,然后对模型的总体架构做了详细设计,最后对于Node-red中原本缺少的用于流式数据的输入输出节点、数据处理节点以及Redis数据库访问节点做了重新设计,并将设计的各个节点重新部署到Node-red框架当中,使其成为一个能够胜任流式数据处理的完整模型。
第五章,实时流数据处理模型在网站访问监控系统中的应用,本章主要是对设计的新模型加以应用,以此来验证模型的可行性与高性能。为此设计了一个网站访问的实时监控系统,其中的实时数据分析就用到了本文设计的流式数据处理模型,将数据处理的结果输出到前端页面做可视化展示。本章详细阐述了系统的功能,各个功能模块的设计与实现。
第六章,系统测试与性能分析,这一章是整个模型以及应用系统的测试环节,主要是分析了模型对流式数据的处理能力并对设计的应用系统进行功能测试。
第七章,全文总结与展望,是对本文的主要工作进行最后总结,并对后续工作做了一些说明。
6
第二章 实时流数据处理的基础理论和技术
第二章 实时流数据处理的基础理论和技术
2.1 的事件驱动和非阻塞机制
从2009年诞生至今,已近经过了八年的发展,目前已经进入了青年时期,在各大中小型IT企业中的应用十分广泛,尤其在web领域,不论是前端JS还是后端的web服务器,它都有用武之地。不仅仅是一种编程语言,更是一种工具和平台,为JavaScript提供运行环境[20,21]。它封装了google的V8引擎,由于V8引擎解释执行JavaScript的速度快、效率高等特点,再加上本身对其进行了优化,这使得的性能也非常好。而底层的代码执行模块利用C++编写,同时底层通过libuv库来实现对事件循环队列的处理,并将耗时较长的I/O请求交给libeio来处理,通过这种隔离的方式来提高运行效率。的优秀性能主要体现在其优秀的底层架构上,的底层架构图如图2-1所示。
JavaScriptNode standard libraryC/C++Node bindings(socket、http、etc)threadpoolV8eventloopCrypto(OpenSSL)DNS(c-areas)(libeio)(libev)
图2-1 的底层架构图
底层的事件循环机制是利用libuv来实现的[22],libuv是一种高性能的事件驱动程序库,它屏蔽了因为平台不同而带来的差异。在Windows平台中,直接利用Windows下的IOCP(I/O Completion Port)通常称为I/O完成端口来实现,在IOCP的内部其实是利用了线程池的原理,这些线程是由Windows系统内核自动管理,不需要手动加以管理。而在Linux平台上,通过自行实现的线程池来完成异步非阻塞I/O的处理工作。而libuv就是扮演这样一个平台间的过渡角色,对外提供统一的API接口,的事件驱动策略如图2-2所示。
7
电子科技大学硕士学位论文
v否是否windows是自定义线程池IOCP
图2-2 的事件驱动策略图
采用的是事件驱动、异步编程的模式[23]。事件驱动这个词,对于程序员来说并不陌生,比如在网络套接字编程中,当socket有数据到来的时候,就会触发之前所注册的callback函数的执行,而所提供的绝大多数API都是采用的这种编程模式。下面就来详细阐述一下的这种事件驱动编程模式。
我们可以与apache服务器的原理相比较一下,apache服务器采用的是单进程、多线程模型,一个用户请求对应一个线程,而是单进程、单线程模型,它是通过事件驱动的方式来实现并发的,不会为每一个客户请求创建单独的线程,而是通过事件监听器来判断,最后触发callback函数的执行。当的主线程运行的时候,就会创建一个事件队列(event queue),在这个队列中几乎保存了程序所需要的每一个I/O操作,由于线程会循环地去处理事件队列中的I/O操作,该队列也被称为循环队列。如果在程序的执行过程中,遇到了比如像文件的读写、数据库的查询等I/O操作来阻塞任务时,线程不会停下来等待这些操作,而是注册一个callback函数,转而继续执行队列中的下一个操作。而这里的callback函数,只有在这些阻塞任务执行结束之后通知主线程调用执行。在事件循环队列中,为了避免造成程序陷入类似于递归调用的无限循环中,要求所有的callback函数都必须经过一个tick周期,在程序中的具体表现就是所有的callback函数都要执行ck()。的事件驱动原理如图2-3所示。
8
第二章 实时流数据处理的基础理论和技术
Event ication(Get File(file) Open(file))(Get Data(db) Connect(db))(Open File(file) Read(file))(Connect(db) Query(db))(Read(file) Send(file))(Send(file) none)GetdataWhen the function is executed it
place the callback in the Event
Queue,order is based on how
fast functions finish.(Query(db) Send(data))(Send(data) none)
图2-3 的事件驱动原理图
从图2-3所示的的事件驱动原理图可以看出,在的应用中有读文件和查询数据看两种I/O操作,该应用的主线程会创建一个事件循环队列,在这个循环队列中有文件的打开操作、读文件、连接数据库、查询数据库等操作。举一个实际的例子来说明,假如在执行下面这样一段代码:
('SELECT * from test_table', function(result) {
();
});
程序的第二个参数就是一个回调函数,当程序运行到这里的时候,由于I/O操作会消耗大量时间而不会立刻返回查询的结果,而是将该事件插入事件队列中,转而继续执行下面的代码。而当数据库查询操作返回后,就会将该事件发送到事件循环队列中,直到下一次循环监听到了该事件,就会触发回调函数的执行。而只有当整个事件循环队列中的任务都执行结束后,应用才会终止。
对于的异步I/O非阻塞机制也是建立在事件驱动机制之上的,对堵塞I/O的处理,其底层是通过线程池来确保工作的正常执行。从线程池中取得一个线程来执行复杂任务,而不必占用主循环线程,这样就防止堵塞I/O占用空闲资源而造成效率下降。在堵塞任务执行完毕后,通过查找到事件队列中相应的callback函数来处理接下来未完成的工作。也就是说,对于那些相对耗时比较长的I/O操作,比如读写文件等,还有一些网络通信,比如套接字,会将这些操9
电子科技大学硕士学位论文
作交给一个称之为worker threads的线程池去执行,当这些操作执行结束后,通过事件通知,并执行回调函数,这就是异步I/O非阻塞机制。
正因为的这种事件驱动机制,使得那些十分耗时的I/O操作都可以异步执行,有效地解决了因为I/O操作而带来的性能和效率瓶颈问题。在许多轻量级、高实时、高流量的应用系统中,都能见到的身影。本文中各个数据处理节点的设计和开发都是基于的,同时前端可视化模块也是利用的express框架进行开发的。
2.2 Node-red流式数据处理框架
2.2.1 Node-red概述
Node-red是IBM Emerging Technologies团队开发的一个可视化的数据流程编辑工具。它允许程序员直接通过web浏览器就可以实现各种数据流程的编辑,同时可以实现对数据处理逻辑的编写。Node-red把这些数据流程称为flow,所编写的flow可以以json对象的形式保存在普通文件中或者形成js库,方便用户分享、修改。程序员在Node-red中可以通过组合各部件来编写应用程序,实现各个部件之间的数据传输,这些部件可以是一些硬件设备(如:Arduino板子)、网络服务的接口(如:WebSocket in和WebSocket out)、功能函数(如:range)或者在线服务(如:twitter)。利用Node-red进行编程十分方便,只需要在它提供的web界面中,通过拖拽已成功安装部署的节点(node)到workspace中并用线(Node-red中称为wire)把这些节点连接起来,就可以创建数据流实现编程。最后,程序员通过点击‘部署(Deploy)’按钮实现一键保存并执行。Node-red本身是基于开发的,它的执行模型和一样,也是通过事件驱动和非阻塞I/O机制来实现的,这一点在上一节关于的事件驱动和非阻塞机制已经作了详尽的阐述。理论上,的所有模块都可以被封装成Node-red的一个或几个节点(node)。
本文所设计的实时流数据处理模型是通过利用Node-red来完成数据流程的管理以及处理数据的业务代码的编写两项工作。接下来,详细阐述Node-red的编程模型及其数据流程管理。
2.2.2 Node-red的编程模型
本节我们通过介绍Node-red的一些关键概念和关键组件,并通过实际例子说明Node-red的编程模型。
(1)数据流程(flow),这是Node-red中最重要的一个概念,一个flow就是一个Node-red程序,它是多个节点连接在一起进行数据交换的集合。在Node-red10
第二章 实时流数据处理的基础理论和技术
的底层,一个flow通常是由一系列的JavaScript对象和各个节点的配置信息组成,通过调用底层的环境来执行JavaScript代码。
(2)节点(node),它是组成flow的最基本的元素,也是真正进行数据处理的载体。当一个编写好的flow运行起来的时候,节点主要对从上游节点接收到的消息(简称message)进行处理,并产生新的消息传递给下游节点完成后续的处理工作。一个Node-red的节点主要包括js文件这html文件,分别完成对节点功能的具体实现和节点UI设计。
(3)消息(message),它是节点之间进行传输的对象,也是数据的真正载体。本质上消息是一个JavaScript对象,包含了各种对数据描述的属性。消息是Node-red处理的最基本的数据结构,只有在节点被激活时消息才会被处理,再加上节点是相互独立的,这就保证了所有的数据流是互不影响且无状态的。
(4)连线(wire),它是节点与节点之间的连接桥梁,它们通常将节点的输出端点连接到下游节点的输入端,表示由一个节点生成的消息应该由下一个连接节点处理。
在了解了这些基本的Node-red组件之后,下面通过举例说明Node-red的编程模型。假设要实时发送一个消息到debug节点,来测试消息在节点之间的传输,用到了一个定时器timestamp节点,一个函数节点function_node以及一个debug节点,如图2-4所示。
图2-4 Node-red中的数据流程图
在图2-4所展示的flow中timestamp节点每隔两秒去触发test function节点,执行其中的代码,而d是一个debug节点,用于在debug面板展示test
function处理过的数据。这里仅仅是为了说明Node-red的编程模型,因此test
function节点并没有复杂的数据处理逻辑,仅仅是返回一个hello world的消息,其实现代码如下:
d=“hello world”;
return msg;
在function节点的内部可以编写任何JavaScript函数,用于处理上游节点发送过来的数据。
11
电子科技大学硕士学位论文
2.2.3 Node-red的基本配置
由于本文所设计的实时流数据处理模型,要对Node-red的数据输入节点,输出节点以及数据处理节点进行重新设计,同时新增Redis数据的访问节点,因此,需要对Node-red进行源码安装。为了能够有效地利用Node-red进行流式数据处理和数据流程的管理,有必要阐述一下Node-red的基本配置。经过源码安装后,Node-red的目录是十分清晰,各个模块的划分也是仅仅有条,Node-red的目录结构如图2-5所示。
slibclonecorsgrunt
sredresources
图2-5 Node-red目录结构图
各个目录文件存储的内容和作用如下:
(1)在/public目录下是一些关于Node-red本身的静态文件,包括资源文件、css样式文件、以及前端页面的html文件;
(2)/node-modules目录下面是一些外部依赖库,也就是Node-red需要的一些模块。
(3)/red目录下面就是真正的Node-red代码,主要是一些核心api、事件驱动程序、服务器端主程序、系统设计程序以及Node-red的入口程序等。
(4)/test目录下面主要是放了一些用于测试的node以及flow;
(5)/nodes目录是一个极其重要的目录,Node-red中所有的节点都是存放在这个目录下的,包括各个节点的html和js文件。
12
第二章 实时流数据处理的基础理论和技术
(6)文件是整个Node-red的系统配置文件,该文件描述了启动的参数细节、端口和IP设置以及各个启动目录的设置。
接下来阐述如何配置Node-red。Node-red几乎所有的配置信息都记录在文件中,首先要清楚各个配置选项的功能作用,Node-red的常用配置选项及其作用如表2-1所示。
表2-1 Node-red常用配置选项说明
选项名
uiPort
uiHost
debugMaxLength
flowFilePretty
userDir
functionGlobalContext
...
默认值
1880
127.0.0.1
1000
true
安装目录
undefined
...
作用
指定Node-red网页的端口号
指定Node-red网页的IP地址
指定debug节点调试数据的最大显示长度
是否保存编写的flow
指定flow保存的位置
用于加载外部依赖,其值是json对象
...
按照表2-1所示的配置选项说明进行配置,重新启动Node-red,并且在浏览器中输入127.0.0.1:1880,即可打开Node-red的可视化流程编辑界面。
2.3 基于内存计算的数据库Redis
2.3.1 Redis数据库概述
Redis是一个开源的高性能key-value存储系统,它通过提供多种键值数据类型来适应不同应用场景下的存储需求,并借助许多高级的接口使其可以胜任如缓存、队列系统等不同的角色。
Redis和Memcached类似[24],数据都是缓存在内存的,而不同之处主要有三点,第一,Redis支持的数据类型相对来说更加丰富,比如像string(字符串)、list(链表)、set(集合)、zset(有序集合)以及hash(哈希类型)。第二,Redis还提供了数据持久化的功能,因为在内存中的数据有一个典型的问题,也就是当程序运行结束后,内存上的数据将会丢失,所以Redis考虑到这点,提供了对数据持久化的支持,即将内存中的数据通过异步的方式写入到磁盘当中,同时也不影响它继续提供服务。第三,在实现上,Memcached采用的是多线程技术,而Redis采用的是单线程技术,所以在多核处理器上,Memcached的性能和资源利用率要高于Redis,但是针对这一点目前也有很好的解决方案,再加上Redis的性能已经足够优秀了,13
电子科技大学硕士学位论文
而且提供了许多Memcached无法提供的高级功能,我们相信在不久的将来,Redis将会在很多领域完全替代memcached。Redis与Memcached的对比如表2-2所示。
表2-2 Redis与Memcached的对比
数据库类型
数据类型
虚拟存储
过期策略
分布式
数据存储安全
灾难恢复
Redis
Key-value内存数据库
在定义value的时候
就要固定数据类型
不支持
支持
Magent
不支持
不支持
Memcached
Key-value内存数据库
不需要固定,支持字符串,链表,集合,有序集合,hash
支持
支持
Master-slave主从同步
备份到中
AOF用于数据容灾
2.3.2 Redis数据库的实现原理
我们已经知道Redis提供了五种数据类型,分别是字符串、链表、集合、有序集合以及哈希表。开发Redis数据库的作者,为了让Redis支持者五种数据结构,首先对Redis的内存模型进行了设计,如图2-6所示。
stringredis核心对象(redisObject)hashlist编码方式(encding)rawhtlong_intziplistskiplistlinkedlistziplistint_set数据类型(type)数据指针(ptr)setsorted set虚拟内存(vm)其他信息...
图2-6 Redis内存对象模型
从图2-6所展示的内存模型可以看出,Redis是通过一个叫做redisObject核心对象来管理这些数据类型的,在redisObject对象内部提供了一个type字段,用于表示value是属于哪种数据类型,而真正的值是通过一个数据指针来表示的。这里14
第二章 实时流数据处理的基础理论和技术
的编码方式也就是该类型的数据在Redis底层是使用的什么数据结构来实现的,比如在列表的底层是通过双端链表实现的,而有序集合是通过Skip List实现的。另外,模型中还提供了一个虚拟内存字段,而只有在该字段的值为true的时候,才会真正地分配内存,在默认的情况下该字段值为false。
在认识了Redis的核心对象后,接下来简单阐述在Redis数据库中这五种数据类型的底层实现原理。Redis数据库底层提供了八种数据结构,在源码中都是通过宏来表示的,也就是之前提到的编码方式,如表2-3所示。
表2-3 Redis底层提供的八种数据结构
编码常量
REDIS_ENCODING_INT
REDIS_ENCODING_EMBSTR
REDIS_ENCODING_RAW
REDIS_ENCODING_HT
REDIS_ENCODING_LINKEDLIST
REDIS_ENCODING_ZIPLIST
REDIS_ENCODING_INTSET
REDIS_ENCODING_SKIPLIST
对应的底层数据结构
long 类型的整数
embstr编码的动态字符串
简单的动态字符串
字典
双端链表
压缩列表
整数集合
跳表和字典
对于字符串来说,其编码方式可以是long类型的整数,也可以是embstr编码的动态字符串,还可以是简单的动态字符串。embstr编码的动态字符串是在Redis3.0中新增的数据结构,它的好处在于只需要进行一次内存分配,而简单的动态字符串需要进行两次内存分配。对字符串value的操作都是通过核心对象的数据指针进行的。
Redis中列表的底层数据结构可以利用双向链表实现,也可以利用压缩列表来实现,由于双向链表中的每个节点都具有直接前驱和直接后继,因此Redis的列表支持许多反向操作,但是有一个不足之处就是,每增加一个节点都会向系统申请一次内存,这无疑带来了额外的内存开销。但是对于压缩链表来说,它就要比双向链表更加节省空间,因为压缩链表只需要申请一次内存,而且是一块连续的内存空间,但是为了保证内存的连续性,每次插入一个节点的时候都需要realloc一次。
集合的内部实现是一个hashtable,只是其中的value永远是null,这实际上是通过计算hash的方式来实现快速重排,这也是集合之所以能够快速地判断一个元素是否在集合中的重要原因。Redis中hash类型的底层数据结构可以是hashtable,15
电子科技大学硕士学位论文
也可以是压缩的列表,由于压缩列表是一段连续的内存空间,所以在压缩列表中的哈希对象是按照key1:value1,key2:value2这样的先后顺序来存放的,按这种方式实现的hash,在对象的数量不多且内容不大的情况下,效率是非常高的。
Redis的有序集合的底层数据结构就是通过跳表来实现的,而没有采用hash和hashtable来实现,虽然hash可以实现快速的查找,但是无法保证有序。关于有序集合的底层实现原理我们将在第三章有序集合的源码分析中做详细阐述。
2.3.3 Redis数据库的pub与sub机制
pub/sub功能即publish/subscribe功能[25,26]。在基于事件的系统中,pub/sub是目前广泛使用的通信模型,它采用事件作为基本的通信机制,提供大规模系统所要求的松散耦合的交互模式:订阅者比如客户端以事件订阅的方式表达出它有兴趣接收的一个事件或一类事件,发布者比如服务器可以将订阅者兴趣的事件随时推送给相关订阅者。
Redis数据库也支持pub/sub机制,本文所设计的流式数据处理模型中,新引入了数据的输入节点也就是Redis的subscribe节点,以及数据的输出节点publish节点,这两个节点在采集数据和最终数据的推送服务中被广泛用到。订阅者可以订阅多个channel,而发布者可以通过channel,向订阅者发送消息[27]。但是发布者所发的消息是异步的,不需要等待订阅者订阅,也不关心订阅者是否订阅,简单地说就是订阅者只能收到发布者后续所发送到该channel上的消息,如果之前发送的消息没有接收,那么也再也接收不到了,下面是Redis数据库的发布订阅命令。
PUBLISH channel_test message;
SUBSCRIBE channel_test;
PUBLISH:向channel_test发布消息message。
SUBSCRIBE:订阅channel_test消息,会收到发布者所发送的message消息。
2.4 本章小结
本章主要对本文的相关技术进行了介绍,首先对 的事件驱动和非阻塞机制进行了详细阐述,为后面Node-red的节点设计与开发打下理论基础,然后对Node-red进行了详细介绍,最后还详细介绍了Redis数据库的基本概念、底层实现原理以及发布/订阅机制。
16
第三章 基于Redis有序集合的去重统计方法的研究
第三章 基于Redis有序集合的去重统计方法的研究
在实时流数据处理过程中,经常会遇到最大值、最小值、累计求和等指标的计算,而计算这些指标的基础就是去重统计。本文所设计的实时流数据处理模型是让Redis作为数据计算和中间结果集存储的中心,因此探索研究一种基于Redis有序集合的去重统计方法具有重要的研究意义和实用价值。本章将从“跳表”Skip
List的基本原理开始,再到Redis有序集合的源码分析,详细研究基于Redis有序集合的去重统计方法。
3.1 Skip List基本原理
Skip List是由William Pugh提出的一种基于关联链表、随机化的数据结构[28]。Skip List的查找效率与二叉查找树的查找效率差不多,可以实现平均时间复杂度为O(log(n))的插入、删除和查找操作。一般而言,跳表是通过在有序链表的基础上增加额外的链接来实现的,而这种链接方式的增加,并不是随便进行的,是以随机化的方式增加,同时对随机函数也有要求,必须是以对数函数的方式产生,所以在链表中的查找可以迅速地跳过部分链表,以提高查找效率,跳表也因此得名。众所周知,对于有序链表的查找操作,其时间复杂度为O(n),尽管真正插入与删除节点的操作的时间复杂度只有O(1),但是,这些操作都需要首先查找到节点的位置,换句话说,是查找拉低了有序链表的整体性能。而Skip List采用“以空间换时间”的设计思想,除了原始链表外还保存一些“跳跃”的链表,以达到加速查找的效果,可以有效解决有序链表查找特定值时效率低的问题。
接下来研究一下Skip List实现的原理,首先来认识一下Skip List。因为,“跳表”是在有序链表的基础上做改进的,所以我们从认识有序链表开始研究Skip List。T表示链表图3-1展示的就是一个有序链表的数据结构图(这里H表示链表头部,尾部,这两个节点都不是有效节点)。
H1234567T
图3-1 有序链表结构图
现在假设要在该有序链表中查找value为7的节点,那么,只能在有序链表中一步一步地从头到尾按照1->这样的顺序找下去,很明显查找效率是O(n) 。试想,如果是数组的话,可以利用二分查找,时间复杂度可以提高到O(log(n)) ,17
电子科技大学硕士学位论文
但是由于链表不支持随机访问,所以不能利用二分法进行查找。但是,如果我们确实想利用二分查找的思想,就可以考虑把中间位置的节点保存下来,重新构成新的顺序链表,经过重构的链表如图3-2所示:
0H4T1H2462H1234567T
图3-2 重构后的有序链表
毫无疑问,这是一种典型的以空间换时间的设计思想。原始的顺序链表,经过重构后变成了三个顺序链表,从上到下我们将这三个链表编号为0、1、2,不难发现,2号链表就是原始链表,1号链表就是原始链表的四等分节点构成的,而0号链表是原始链表的二等分节点构成的。现在,假设还是要查找value为7的节点则只需要如下三个步骤:
(1)初始的的搜索范围是(H,T),在0号链表中与4进行比较,7>4,将搜索范围更新为(4,T)。
(2)在1号链表中与6进行比较,7>6,继续更新搜索范围(6,T)。
(3)在2号链表中与7进行比较,结果7=7,查找成功。
很明显,在Skip List中保存了二分查找的信息,以此来提高查找效率。不难发现在具体的实现上,如果要开辟额外的空间来保存新链表的话,会造成空间的极大浪费。由于是链表,可以利用链的性质,通过增加额外的指针,改进存储结构,以达到节省存储空间,降低空间复杂度的目的,经过改进后的Skip List的存储结构如图3-3所示。
H1234567T
图3-3 改进后的Skip List存储结构
18
第三章 基于Redis有序集合的去重统计方法的研究
前面所讨论的Skip List结构是一种比较理想的结构,仅仅是为了说明Skip List的原理,实际的Skip List算法是一种随机算法,它非常依赖于所生产的随机函数。当然对随机函数的要求也比较严格,不能简单的按照rand()%MAX_LEVEL 的形式来生成随机数,而是必须要按照满足概率P1/2的几何分布来构造随机函数。可以设计出如下随机函数RandomLevel():
}
int SkipList::RandomLevel(void) {
int level = 0;
while(rand() % 2 && level < MAX_LEVEL - 1)
++level;
return level;
现在考虑MAX_LEVEL4的情况,可能的返回值有0、1、2、3四种情况,它们各自出现的概率是:P(0)1/2、P(1)1/4、P(2)1/8、P(3)1/8。也就是说,如果有16个元素的话,第零层预计有16个元素,第一层预计有8个元素,第二层约有4个元素,第三层约有 2个元素,从下向上每层元素数量大约会减少一半。因此,Skip List适合自顶向下进行查找,理想情况下,每下降一层搜索的范围就会缩小一半,可以达到二分查找的效率,时间复杂度为O(log(n))。最坏的情况是当前节点从head移动到链表的尾部,时间复杂度为O(n)。
3.2 Redis有序集合的源码分析
Redis的有序集合(zset)的底层数据结构就是通过Skip List来实现的,而没有采用hash和hashtable来实现,虽然hash可以实现快速的查找,但是无法保证有序。在了解了Skip List的基本原理后,接下来通过分析Redis有序集合的源码,详细阐述有序集合的底层实现。Redis中的有序集合所使用的Skip List与William Pugh提出的基本一致,只是做了部分改进,主要体现在以下三个方面。
(1)Redis中的Skip List可以有重复的分值score,这是为了支持有序集合中可能有多个元素具有相同的分值score这样的需求。
(2)在节点进行比较的时候,不仅仅比较它们的score,同时还要比较它们所关联的元素的value。
(3)在Skip List中每个节点还有一个前向指针,这就相当于在双向链表中的prev指针,通过这个指针,可以从表尾向表头进行遍历。正因为有了这个改进,zset就支持一些逆向操作命令,比如zrevrange、zremrangebyscore等。
19
电子科技大学硕士学位论文
在Redis的源码中,有序集合的Skip List的节点的数据结构是定义在redis.h头文件中,其具体定义如下:
/* 跳跃表节点定义 */
typedef struct zskiplistNode {
robj *obj;// 存放的元素值
double score;// 节点分值,排序的依据
struct zskiplistNode *backward;// 后退指针
struct zskiplistLevel {// 层
struct zskiplistNode *forward;// 前进指针
unsigned int span;// 跨越的节点数量
} level[];
} zskiplistNode;
有了节点的定义,那么就该是Skip List的定义了,Skip List同样也是定义在redis.h头文件中的。和定义链表的结构一样,需要头节点、尾节点,它们都是指向zskiplistNode 的指针,同时还需要定义节点的数量以及目前跳表的最大层数。下面展示的就是有序集合的跳表数据结构定义:
typedef struct zskiplist {
struct zskiplistNode *header, *tail;
unsigned long length;
int level;
} zskiplist;
其实,Redis的有序集合主要支持的编码方式有两种(所谓的编码方式就是底层的实现方式),一种是ZIPLIST(压缩列表)方式,另一种是SKIPLIST(跳表)方式。其中ZIPLIST方式可以表示较小的有序集合,而SKIPLIST方式可以表示任意大小的有序集合。如果有序集合当前使用的编码方式是ZIPLIST,只要满足下面两个条件之一就可以转换为SKIPLIST编码方式。
(1)当新增加的字符串的长度超过了_max_ziplist_value的时候(默认值为64)。
(2)当ziplist中保存的节点数超过了_max_ziplist_entries的时候(默认值为128)。
在有序集合的源码中这两种方式的转换可以通过zsetConvert函数来完成。这20
第三章 基于Redis有序集合的去重统计方法的研究
里主要阐述SKIPLIST编码方式,利用该方式实现的有序集合的数据结构是定义在redis.h中的,其定义如下:
typedef struct zset {
dict *dict;// 字典,维护元素值和分值的映射关系
// 按分值对元素值排序序,支持O(longN)数量级的查找操作
zskiplist *zsl;
} zset;
有了数据结构的定义,接下来就是考虑对这些数据结构的操作了。在Redis有序集合的实现中,将对zskiplist的操作都放在t_zset.c源文件中,所支持的操作有三十多种之多。包括创建层数为某一level的跳表节点、创建一个跳表、释放跳表、向跳表中插入一个节点、删除一个节点等基本操作。下面来看一下有序集合在创建一个空的跳表后是如何向跳表中插入节点的。首先,调用zslCreate()函数创建并初始化一个空的Skip List,一个空的Skip List如图3-4所示。
header nodezskiplistlevel 31NULLheadertaillength(0)...NULLlevel 1Level 0NULLlevel(1)...NULLbackwardscore(0)objNULL
图3-4 空跳表结构图
在该跳表的结构图中,level 0到level 31是一个长度为32的zskiplistLevel结构体数组,其大小由redis.h文件中的宏ZSKIPLIST_MAXLEVEL定义,值为32。在zskiplistLevel结构体中还包括了span和forward两个数据成员,这一点从该结构体的定义中可以看出,这里为了展示方便,忽略了span。
创建完跳表之后,调用zslInsert()函数,就向该空跳表中插入节点。插入一个新的节点的大致过程如下:
21
电子科技大学硕士学位论文
(1)按照跳表的结构按层数从上向下遍历。
(2)在当前level的当前节点向右遍历,如果发现分值score相同就比较value的值,否则进入下一步。
(3)调用随机函数,产生随机的层数。
(4)比较当前level与随机函数产生的随机level,记录最大的level,作为下一步遍历的level。
(5)插入节点,并更新跨度span
在第三步中调用随机函数,生成随机的层数,这一点在上一小节关于Skip List的实现原理中已经做了阐述。关于如何查找插入位置,在有序集合的源码中是这样实现的:
…
for (i = zsl->level-1; i >= 0; i--) {
//保存在查找出入位置过程中遇到的节点的序号
rank[i] = i == (zsl->level-1) ? 0 : rank[i+1];
//以下是得分相同的情况下,比较value的字典排序
while(x->level[i].forward&&(x->level[i].forward->score
orward->score==score &&compareStringObjects(x->level[i].forward->obj,obj) <
0))) {
rank[i] += x->level[i].span;
x = x->level[i].forward;
}
update[i] = x;
}
下面举例说明跳表节点的插入操作,假设要向跳表中插入A、B、C、D四个节点,它们对应的分值为3、5、7、9,则对应的跳表结构如图3-5所示:
22
第三章 基于Redis有序集合的去重统计方法的研究
header level 2level 1level 0backwardscoreobjlevel 2level 1level 0backwardscore 3objlevel 0backwardscore 5objlevel 0backwardscore 7objlevel 1level 0backwardscore 9objNULLNULLNULLNULLNULLABCD
图3-5 跳表节点插入步骤图
从图3-5中可以看出,跳表中的节点都是按照分值score来进行排序的。同时,每个节点的backward指针都指向它的前一个节点,因此,跳表和双向链表类似,支持许多逆向查找,提高了灵活性和操作的效率。
3.3 基于有序集合的去重统计方法
去重统计,在数据分析领域是一个耳熟能详的词语,在大部分数据处理过程中都要用到。众所周知,在大部分的数据分析的中间计算过程中,最终的数据指标主要呈现以下几种形式:最大、最小、稳定性、叠加、去重统计。在这五种数据指标中,前四种在大部分的实时处理框架和nosql中都可以使用相对较小的开销就可以完成计算。而对于去重统计,由于去重的数据有可能是多维的,所以不论是I/O效率上,还是计算的效率上都没有前四种指标高。
本文所设计的实时流数据处理模型中,也对这五种数据指标的计算做了设计。经过前两节对Skip List的基本原理和Redis有序集合的源码分析研究,本文认为不论是在I/O效率上还是计算查找效率上,利用Redis的有序结合来做数据去重统计是可行的,能够满足实时计算的要求。在许多流式数据处理的应用中都会涉及到最大值、最小值、累计求和等数据指标的计算,而要计算这些数据指标的基础就是去重统计,因此,涉及一种高效的去重统计方法显得意义也十分重大。
本文所提出的基于有序集合的去重统计方法,就是在流式处理模型中引入Redis数据库的访问节点,通过这些节点将产生的中间结果集存储到Redis的有序23
电子科技大学硕士学位论文
集合中,并根据上游节点提供的命令格式,对指定的集合进行zincrby操作。在Redis所提供的客户端进行zincrby操作的命令格式是这样的:zincrby zsetkey increment
member,如果在名称为zsetkey的有序集合中已经存在元素member,那么该元素的score增加increment,否则向该集合中添加该元素,其score的值为increment,若增加成功返回的是member增长之后的序列号。也就是说,在Node-red中进行去重统计的过程就是通过redis_in节点对相应结合进行zincrby操作的过程,关于redis_in节点的设计思路和具体实现将在第四章作详细阐述。
本文在设计redis_in节点的时候规定了上游节点传输过来的数据格式,因为redis_in节点操作数据库的命令就是从上游节点传输过来的数据中获取的。就以实际项目中一个功能来说明这一点,对于某一网站错误页面的统计这个功能,前端页面要求展示错误页面的URL、错误类型、错误页面所属的网站的域名、该错误页面是从哪个页面跳转来的等信息。很显然错误页面具有着四个维度,如果我们单独去统计每一个维度的信息,最后再来进行整合,这样会大大减低计算的效率。为此,我们要将多维统计转换为一维统计,同时也不能影响展示界面要求的四维信息。本文所采取的降低维度的做法是将这四个维度拼接在一起,每个维度之间用特殊字符间隔,这样就形成了只有一个维度的计算指标,然后将这个指标作为有序集合的key值,当有序集合在进行zincrby操作的时候,就会根据这个key来进行插入操作。在Node-red中redis_in节点所要求的数据格式如图3-6所示。
图3-6 redis_in节点要求的数据格式
在图3-6所编写的函数中,就用到了Node-red的function node,关于该节点的具体设计细节将在第四章作详细阐述,该节点将数据封装在msg对象的payload字段中,同时返回msg对象,而在该节点的内部通过调用()方法,将msg对象发送给下一个节点,供下一个节点接收并处理。在图中整个['zincrby','errPageDisplay',1,err],就是操作Redis有序集合的zincrby命令,其中24
第三章 基于Redis有序集合的去重统计方法的研究
errPageDisplay是有序集合的名字,err是通过降低维度后的一维指标。
上面这个例子展示了在实际项目中利用本文所设计的redis_in节点进行去重统计的过程。之所以说去重统计是一项基础计算,是因为,在进行去重统计的同时,只需要一些简单的操作就可以去计算最大值、最小值、累计求和等数据指标。比如要想知道有序集合中的最大值或最小值,只需要返回集合中的第一个元素或者最后一个元素,有时候需要返回排名前N的记录,也就是常用的top(n)操作,在去重统计的基础上也很容易实现。
3.4 本章小结
实时流数据处理中会经常遇到去重统计,而本文所设计的实时流式数据处理模型中引入了Redis作为数据计算中心,基于Redis有序集合的去重统计方法也被应用到该模型中。本章主要是对Redis的有序集合底层实现原理进行分析研究,同时研究分析了有序集合的底层实现源码,最后也阐述了基于有序集合的去重统计方法在该模型中的具体应用。
25
电子科技大学硕士学位论文
第四章 实时流数据处理模型的需求分析与设计
第三章对基于Redis有序集合的实现原理及其源码进行了分析研究,并提出了在流式数据处理模型中利用Redis有序集合来进行去重统计的方法。本章将从需求分析开始,再到模型的总体架构设计,最后是各数据处理节点的详细设计,从这三方面对该实时流数据处理模型进行详细阐述。
4.1 需求分析
4.1.1 实时流数据处理模型的需求分析
本文主要研究并设计了一种基于Node-red与Redis的实时流数据处理模型,应用场景为实际项目中的网站群实时访问监控。本项目旨在实时了解用户访问网站群的行为[29],捕捉用户请求并跟踪其所有响应,收集、处理并显示用户行为的细节数据,并将数据分析结果做可视化展示,挖掘数据背后的信息。针对该实时流计算模型在实际应用场景下的应用提出如下的需求。
(1)高实时性:在许多实时流数据处理的应用场景中,不论是数据的采集,还是数据的处理,都要求具有高实时性。高实时性,要求模型在进行数据采集的时候满足不低于每秒钟50笔的采集速度,以免造成数据堆积,同时也要求具备高效的数据计算和处理能力。
(2)高性能:随着业务的不断扩展,数据量也不断的增大,对实时流数据处理模型及应用系统的性能要求也越来越严格。因此,从数据采集到数据处理再到数据可视化展示,各个环节都要求系统具有良好的性能。最直观的表现就是在用户看到的可视化模块的数据更新延迟不能超过2秒钟。
(3)高可用:模型可以通过集群等方式实现分布式部署,避免单点故障。
(4)可扩展:数据量、计算量会随着业务的不断扩展而不断增大,这就要求模型需要有良好的扩展性。
(5)分布式:为了提高数据的处理能力和计算效率,模型还需要具备分布式的处理能力。
(6)安全性:数据安全是任何系统的一个首要前提,流式数据处理模型也必须要保证数据的安全性。
本文在这些需求的基础之上,提出一种新的实时流数据处理模型,要在Node-red上设计出高效的数据接入和输出节点,同时也要有高效的数据处理节点。26
第四章 实时流数据处理模型的需求分析与设计
结合Redis的内存计算的优势,设计出对Redis数据库访问操作节点,用于对中间结果集进行统计计算,以提高模型的数据计算效率。同时,充分利用Redis的pub/sub机制来实现数据的流式异步传输,最终将这套模型应用到实际应用系统中去加以验证。
4.1.2 网站访问监控系统的需求分析
本文所设计的应用系统是通过实时采集网站群的访问流量[30,31,32],利用本文新设计的基于Node-red与Redis的实时流式数据处理模型来解析处理实时数据,并从中挖掘出用户关心的有价值的信息,最后将分析出来的数据可视化地展示到前端界面。针对该系统的功能,提出如下需求:
1.用户行为监控[33]
实时了解用户访问网站群的行为,捕捉用户请求并跟踪其所有响应,收集、处理并显示用户行为的细节数据。
具体实现以下功能:
(1)用户终端类型统计,对用户访问网站群的终端进行统计。
(2)受访页面统计,对用户访问网站所浏览的页面进行统计。
(3)来路页面,统计用户是通过哪个页面跳转到所浏览网站。
(4)地区分布,根据用户IP统计访问网站群的地区分布,并区分内外网用户(内网IP地址范围及相关部门的对照表需信息中心提供)。
(5)IP/PV,一天之内独立IP数,相同IP数被计数一次。
(6)重复访问率,同一IP,在同一天内访问同一页面的访问量/总访问量。
2.网站群页面监控
(1)错误页面跟踪,对返回码为404,500等出错页面进行统计跟踪。
(2)关键词搜索频率,用户搜索关键词的频率。
(3)二级域名访问统计(需信息中心提供二级域名对照表)。
(4)频道访问统计(需信息中心提供频道名称对照表)。
(5)热点页面统计。
4.2 模型的总体架构
基于Node-red与Redis的实时流式数据处理模型是搭建在Ubuntu环境下的,也可以部署在分布式环境上以提高流式数据的处理能力和计算效率。该模型通过重新设计数据输入、输出以及数据计算节点,增加对Redis数据库的访问节点,以完成对实时流式数据的处理工作。整个模型的架构如图4-1所示:
27
电子科技大学硕士学位论文
实时流处理平台channelRedis serverchannelredisPub可视化模块发布实时展示订阅 subscribe统计查询http_tracerNode-red
redis_inredis_out网关redisSubfunction
nodefunction
function
nodefunction
node计算节点群集群(可能是 VM )
图4-1 实时流数据处理模型架构图
从该模型的架构图中可以看出,Redis数据库充当了数据交换的中心,而整个数据流的处理逻辑都交给计算节点群去完成。数据首先通过Redis的channel(通道)进入Redis server,然后Node-red利用redisSub节点去订阅相应通道(channel)的数据,交给计算节点(function nodes)集群进行数据计算,而计算节点集群所产生的中间结果集,通过redis_in节点传给Redis server进行统计,这些中间结果集在Redis server中完成计算后,还会通过redis_out节点取出进行进一步的数据封装,将其封装成前端可视化模块需要的数据格式,最后产生的最终计算结果通过redisPub节点发布到指定的Redis通道中,前端可视化模块再从指定通道去订阅数据做可视化展示。
在原始的Node-red中没有任何节点可以与Redis进行交互,为此,新增加了redisSub、redisPub、redis_in和redis_out节点。为了用户可以自定义数据的处理逻辑,引入了函数节点,多个函数节点构成了整个流式计算的计算节点群。有了这些节点,就可以方便快捷地在Node-red上编写流式数据处理的业务代码,更为重要的是,这些业务代码可以实现一次编写多次使用,方便移植和维护。
4.3 各数据处理节点的设计
节点是Node-red的重要组成元素,所有的数据流(在Node-red中简称flow)都是通过一个一个的节点组成的,在Node-red中有三类基本的节点,数据输入节28
第四章 实时流数据处理模型的需求分析与设计
点、输出节点以及数据处理节点。为了使用适合流式数据处理的节点,这里必须对这三类节点进行重新设计,在这一节中主要是对整个流式数据处理模型所需要的节点给出详细的设计方案。Node-red的节点本身主要包括两份文件:js文件和html文件,js文件主要定义了节点具体做些什么事情,有什么样的功能;html文件主要定义了节点的属性、节点编辑框格式和帮助信息等,Node-red中一个节点的设计方案如图4-2所示。
Editor
图4-2 Node-red的节点设计方案图
将设计好的新节点重新安装部署到Node-red中,就可以在Node-red的前端编辑界面使用该节点进行数据处理。Node-red强大的扩展能力就体现在用户可以设计Node-red没有提供的节点,来完成特定的任务。为了保证节点设计的正确性和有效性,在节点设计的时候必须按照如下原则来进行:
(1)要求创建的节点要对各种类型的输入数据进行必要的处理,即使某些类型并不是这个节点所需要的。这样做有两个目的,一是为了便于对原始数据进行追加额外说明信息,二是为了便于节点的扩展。
(2)由于Node-red在识别和处理节点的时候使用了大量的字符串匹配操作,所以在节点的定义中有一些名字的字符串必须和节点文件名保持一致,否则Node-Red在解析的时候就会出错。
(3)html文件分为3部分:节点的定义、节点的编辑模板以及节点的帮助信息。节点的定义主要用于确定节点的类型,可编辑的属性,在浏览器中显示的样式,是一段可执行的js代码,节点的编辑模板主要是用于生成用户编辑该节点的29
电子科技大学硕士学位论文
实例时的界面,用户的输入最终会保存在node的定义中,节点的帮助信息是提供一些对节点的使用说明。
(4)在html文件中,data-template-name、node-input-xx、data-help-name都是Node-Red系统保留字。data-template-name、data-help-name的取值必须和文件名字的name部分一致。erType的第一个参数也必须和文件名字的name部分一致,否则Node-red解析节点会出错。
(5)每个节点的可编辑域在defaults中声明,data-template-name所包含的node-input-xx负责生成输入框,defaults的每个域的名字必须和node-input-中的名字保持一致。在.js文件中使用可编辑域的值的时候,直接访问defaults的域就可以,不必添加defaults前缀。
(6)在js文件中,erType是用来注册一个node实例的生成函数,它的第一个参数必须是文件名字的name部分一致,传给生成函数的参数是node可编辑域的值及节点共享域的值。
(7)input事件的回调函数(callback)是节点输入的处理函数。需要注意的是,Node-red节点之间数据传输使用的是名字为payload的域,这个也是Node-red系统保留的。
4.3.1 数据输入节点的设计
数据的输入节点(input node),主要是用于从外部设备或者其他外部接口获取数据到Node-red中进行数据分析。在Node-red的一个flow中,输入节点是所有message的入口,为下一个Node产生新的message。由于Node-red自带的输入节点很有限,而且不适合流式数据的输入,所以在这里必须补充设计数据的输入节点。为了满足流式数据的输入需求,数据的输入节点的设计必须要满足以下几个原则:
(1)流式化数据,为了让成批到达的数据也能够在这样一个模型中得到计算,我们在设计数据输入节点的时候就要考虑到这点,也就是说让批量到达的数据逐条进入Node-red的flow中。
(2)统一的数据格式,在一个数据处理模型中,数据格式的好与坏意味着后序进行数据计算的简与繁。
(3)高吞吐量,由于流式数据的产生是源源不断的,所以在设计输入节点的时候要充分考虑节点的数据吞吐量问题,不然会造成大量数据的堆积,从而影响后续的数据分析与计算。
(4)高稳定性,输入节点是数据的入口,稳定性是必须考虑的一个因素。
30
第四章 实时流数据处理模型的需求分析与设计
(5)可移植性,为了能够将自己设计的数据输入节点共享给其他用户,节点的可移植性也十分重要。
为了设计出高效的适合流式数据传输的输入节点,考虑到流式数据的特点,结合Redis数据库的sub机制,可以为Node-red新增一个redisSub节点。从上一小节的总体架构图中我们可以看出,我们尽量让所有的数据通过Redis的发布订阅机制来进行收集,把采集到的数据按类别放到不同的Redis通道(channel)中,避免数据间的相互影响,然后在Node-red中通过我们新增加的redisSub节点去订阅相应通道的数据,这样就可以把数据引入到Node-red中,完成了数据的接入工作。同样redisSub节点也包括两个文件,一个是编写具体功能的实现代码的文件js文件,另一个是用于界面设计和帮助文档描述的html文件。由于Node-red原始节点的存在,所以在进行文件命名标号的时候从52号开始,因为文件名编号和节点的ID是紧密相关的,所以节点的标号必须唯一。设计好新的节点后需要重新安装部署新节点到Node-red中,在利用npm安装的时候,Node-red的节点注册模块会去检测配置文件,依次加载配置文件中的其他外部模块。redisSub节点的设计如图4-3所示。
redisSub节点的设计Redis server(可能是redis集群)subscribechannel52_52_读取配置信息Node-red注册模块html_loader生成redisSub节点的ID
图4-3 redisSub节点设计图
对于redisSub节点的界面UI设计,需要考虑有哪些信息需要用户输入该节点。因为每个节点都有自己的名字,所以首先需要的一个信息就是用户为该节点取一个名字,需要用户输入Name字段。由于数据是存放在Redis server上的,所以还需要redisSub节点记录Redis server的IP地址和端口号。当redisSub节点连接上Redis server后,不知道数据是位于Redis的哪一个通道上,因此还必须给出通道名称,这些都是redisSub节点所需要的最基本的信息。另外还有就是redisSub节点的帮助信息也必须给出一定的说明。UI界面主要是定义在52_文件中。
31
电子科技大学硕士学位论文
而对于redisSub节点的具体功能,是在52_文件中实现的。首先,要调用Node-red提供的节点创建函数createNode()创建一个节点,并把配置信息告诉节点。节点接收到这些信息后,创建一个数据库连接池函数redisConnectionPool,将Redis server的IP和port,以及在createNode函数内部所产生的uuid传递给连接池函数。数据库连接池函数主要是通过connections对象数组的_nodeCount来记录有多少redisSub节点连接Redis server,当有一个新节点连接Redis时,该值就会加一,同样当有一个节点断开的时候就会减一。当有close请求到的时候首先要判断_nodeCount的值是否为0,来决定是否删除connections对象数组。关于Redis数据库连接池函数的执行流程如图4-4所示:
开始close: function()closeclose or getgetget: function()连接的节点数减一connections[id]+=1并返回connectionsN节点对应的连接数是否为0Y连接数是否为0Ydelete
connections[id]N结束初始化connections[id]=0并createClient()
图4-4 Redis数据库连接池函数执行流程
有了数据库连接池函数,就可以来实现redisSub的功能了。redisSub节点的前端页面将用户输入的Redis server的信息保存起来,然后通过参数传给连接池函数连接Redis server。数据库连接成功后调用ibe()方法去订阅指定的通道,如果订阅成功,就让client去监听一个message事件,看通道是否有数据发送过来,如果有数据就封装在d中,让node的send()方法发送出来,供下游节点接收。与此同时,client还要去监听Redis的close事件,当redisSub节点断开与Redis server的连接的时候,就要调用()方法去断开连接。
redisSub的功能函数的伪代码如下:
32
第四章 实时流数据处理模型的需求分析与设计
function redisSub(config) {
Node(this,config); //创建节点
//将html文件中定义的节点属性保存下来。
l = l;
...
//为节点生成一个唯一的id
var uuid1 = uuid.v4();
= (,,uuid1);
...
ibe( l);
//监听相应通道的message时间,将通道发送过来的数据封装到
d中,并通过()方法发送出来。
}
("message", function (channel, message) {
});
("close", function() {
();
});
var msg = {};
d = message;
(msg);
4.3.2 数据输出节点的设计
数据进入Node-red后,经过各个计算节点的数据计算、封装等工作,然后打包成系统规定的数据格式后,需要从Node-red中输出,进入后续的数据展示等其他工作。数据的输出就用到了Node-red的输出节点,Node-red的输出节点允许把数据输出到Node-red的flow以外的其他服务和应用上去,对内有一个数据输入的左断点,对外暴露一个公共接口。
在Node-red中有一个常用的输出节点就是debug节点,这个节点是在编写flow的时候被用于调试数据处理流程,主要显示经过上一节点处理之后数据的具体信息。debug节点是一个具有开关的节点,允许程序员手动开启或者禁用该节点。debug节点的使用也非常简单,只需要在Node-red左侧的节点栏中找到该节点然33
电子科技大学硕士学位论文
后拖拽到相应节点的后面,并用线连接起来就可以实现数据的传输,最后开启debug的启动按钮,将所编写的flow成功部署后,就可以在Node-red的最右侧的debug面板中看到打印出来的具体数据。值得注意的是,debug节点的只有一个数据的入口,而没有数据的输出端,在设计debug的时候,重新封装了sendDebug()函数,用来发送消息,将消息直接发送到Node-red的网页编辑器debug视图上直接显示,而不是交由下游节点做数据处理。下面给出debug节点的设计逻辑的部分伪代码。
function DebugNode(n) {
...//创建节点并定义complete属性,用来判断数据封装是否完成。
("input",function(msg) {
if (te === "true") {
...//debug节点完成了msg的接收进行封装
} else {
...//debug的用户需要自己定义msg的属性
var output = msg[property];
if (te !== "false" && typeof te !== "undefined") {
output = (function (obj, i) ;
…
}
if ()
sendDebug({output});//调用sendDebug方法发送output数据
}
});
有了debug节点,可以方便用户在编写自己的flow的时候,及时查看数据的处理情况。本文在第五章中应用该模型来解决实际问题的时候,将大量应用到debug节点。
为了保证数据实时地输出到Node-red的flow以外的其他服务和应用上,这里我们新引入了redisPub节点。顾名思义,redisPub节点就是将Redis的publish功能嵌入到Node-red中,通过设计一个新的节点来将经过Node-red处理和计算过的数据输出来,这里之所以选择Redis的publis发布数据,一方面保证了数据的异步传输,另一方面也保证了数据的隔离(原因是各个Redis的通道数据是相互隔离的,互补干预)。在坚持节点的设计原则的前提下,下面给出redisPub节点的设计方34
第四章 实时流数据处理模型的需求分析与设计
案,如图4-5所示。
redisPub节点的设计53_53_ishchannelRedis server(可能是redis集群)读取配置信息Node-red注册模块html_loader生成redisSub节点的ID
图4-5 redisPub节点设计图
结合上一小节数据输入节点的设计可知,redisPub节点和redisSub节点的设计恰好相反,redisPub节点只具有一个数据的输入接口,也就是只有数据的输入端点,这一端是连接上一个数据处理节点的,用于接收从上游节点发送过来的数据,而对于该节点的输出端,已经固化在节点内部,就是Redis指定的通道。在redisPub节点中也必须定位Redis的位置,也就是Redis服务器的IP,端口号,不管是在Redis集群还是在单点的Redis服务器中都必须要指定,同时还要指定数据输出到Redis的哪个channel中。所以redisPub节点的UI设计与redisSub节点的UI设计十分相似,不同的是他们的功能代码不一样,体现在js文件中。redisPub节点的处理逻辑的具体流程如图4-6所示。
开始connection redis调用redisConnectionPoolstatus={connected}监听input事件Yconnected==trueNStatus={disconnected}通知Node-red调用client的publish方法发布新的msg到相应通道结束
图4-6 redisPub处理逻辑流程图
35
电子科技大学硕士学位论文
同样,在实现redisPub节点的时候,也用到了数据库连接池函数,关于这个函数的设计思想在上一小节redisSub的设计中已经做了详细阐述。从上面流程图可以看出,当redisPub节点成功连接Redis后,将去监听input事件,当有数据输入该节点后,就会调用h()发布函数,将封装好的数据(message对象)发布到指定的channel上。
4.3.3 数据计算节点的设计
数据计算节点在Node-red中起着举足轻重的作用,几乎所有的flow中都会用到数据计算节点。数据计算节点允许用户编写JavaScript函数来处理进入Node-red中的数据,编写自己的业务代码,将定义好的数据类型转化为在Node-red中流动的message对象。在Node-red中的message实际上就是一个JavaScript对象,message对象至少要包含payload属性,用来保存具体的数据。就像下面这样一个最基本的Node-red的massage数据格式:
msg={
payload:”massage payload”
}
计算节点接收到message后,主要处理的也是payload字段中保存的信息,处理后的数据也会封装成一个新的message对象传给下一个节点。然而,message对象不仅只具有payload字段,还可以扩展出更多的其他字段来补充说明message对象的属性。比如下面这个message对象:
}
msg={
payload:”massage payload”
topic:”error”
location:”somewhere in space and time”
计算节点通常包含一个数据输入端点和一个或多个数据输出端点,在Node-red中提供了部分具有特殊功能的数据处理节点,比如change_node,可以用来增加或者删除message的字段,再如switch_node,可以用来做开关节点使用,它是通过判断message对象的某一字段是否存在或者真假来决定最后输出什么样的message对象。为了能够进一步扩展Node-red的功能,方便利用JavaScript函数加载外部的js模块,这里引入function_node,也就是函数节点。可以说function_node在36
第四章 实时流数据处理模型的需求分析与设计
Node-red中就像一把瑞士军刀,可以使用户不必依赖于现有的数量有限的几个节点来处理数据。顾名思义,函数节点其实就是暴露出来的一个JavaScript函数,用户可用通过编写一个JavaScript函数来处理从上游节点传输下来的message,并返回处理后的一个或多个massage。函数节点是用来做数据处理和数据格式化的利器,引入函数节点使得Node-red对流式数据进行处理变得简单容易。function_node的设计方案如图4-7所示:
function_node的设计Node-red虚拟运行环境Context()上游节点Message对象=Node-red函数运行环境_RED_FUNCTION_send(result)module外部js模块
图4-7 function_node的设计图
用户可以通过function_node内置的编辑器sandBox,编写用户自己的JavaScript函数来处理message。在function_node内编写的JavaScript函数,底层是调用本机上的JavaScript运行环境来解释执行的,同时在函数节点中可以去调用外部的js模块,但是这首先会去配置文件文件中找到要包含的模块。所以function_node在执行每一个函数的时候首先会去检查这个配置文件,在这个文件中去查找全局的函数模块。在中,通过functionGlobalContext来指明要包含的全局模块:
37
functionGlobalContext: {
// bonescript:require('bonescript'),
// arduino:require('duino')
lodash:require('lodash')
}
电子科技大学硕士学位论文
对于自己编写的JavaScript函数要求每一个函数都有一个返回值,也就是一个message对象,即使没有显式地返回,每个函数都会默认返回一个payload字段为空字符串的message对象。
4.3.4 Redis数据库访问节点的设计
由于在原始的Node-red中没有与Redis数据库进行交互的节点,但是本文所提出的模型中用到了Redis server来存储中间结果集,并在Redis server中进行去重统计,比如计算最大值、最小值、累计求和等。所以为了能够让Node-red与Redis进行数据交换和数据传输,必须设计出对Redis数据库的访问操作节点。在该模型中,主要需要的就是redis_in和redis_out节点,它们分别完成从Redis读取数据和把数据存储到Redis中两项任务。
在redis_in中封装了几乎所有的Redis操作命令,该节点提供一个命令选择器,按用户指定的命令进行Redis操作。另外,redis_in节点是一个只具有数据输入端点的节点,它的数据同样来源于上游函数节点提供的message对象中的payload字段(d),用于指定命令的格式和所要操作的Redis集合。而对于redis_out节点,它既有数据的输入端,又有数据的输出端,数据的输入端是接收的数据和redis_in节点接收的类似,都是通过上游的函数节点发送过来,用于指明读数据的命令格式和数据所在的集合,而数据的输出端,就是将从Redis server上取得的数据封装成message对象发送给下一个节点,进行下一步的封装处理。
根据以上对这两个节点功能的分析,接下来就对这两个节点进行详细设计。首先是redis_in节点,该节点第一步工作就是要去连接Redis server,这里就会用到在4.3.1节中所提供的数据库连接池函数,连接成功后需要调用命令选择器,选择用户指定的命令,然后根据上游function节点提供的命令格式和指定的数据集合,将这些信息组装成一条完整的Redis命令,最后调用Redis客户端去执行该命令。redis_in节点的设计方案如图4-8所示。
38
第四章 实时流数据处理模型的需求分析与设计
调用redisClient执行相应命令55_redis_sserver连接redis数据库连接池connectPoolfunctionnode命令格式数据集命令选择器commandSelector指定命令55_redis_
图4-8 redis_in节点设计方案
redis_in节点在向Redis server存储数据的时候,主要的工作任务集中在命令选择器上。在命令选择器中保存了几乎所有的Redis写入操作的命令,是存放在一个数组对象中,首先要从这个数组中找到用户指定的命令,然后判断该命令是不是psubscribe或者subscribe命令,因为这两个命令在获取Rredis集合中数据的时候还需要监听message事件,而其他命令没有该事件,所以必须单独处理。最后,将用户指定的命令与上游节点传输过来的数据集拼接成Redis的命令交给redisClient执行。最终实现Node-red里的中间结果集存储到Redis server中,同时,通过上游节点指定的操作可以实现中间结果集在Redis中的统计计算。
对于redis_out节点的设计与redis_in节点类似,不同的是,在redis_out节点中同样封装了Redis命令,但是这些命令只是读取数据的命令,所以命令选择器中的命令与redis_in的不一样。另外,由于redis_out节点具有一个输出端,所以在input事件监听器中监听到的数据封装完成后,还要通过()方法发送出去,供下一个节点接收。
4.4 节点的重新部署
节点的设计和实现完之后,一步重要的工作就是要将新设计的节点部署到Node-red中。节点可以作为模块打包或者发布到npm库中,这使得它们易于安装其所有依赖的模块。为了解决安装包的依赖关系,在打包节点的时候就要严格按照npm包管理规则来打包。redisSub节点打包的目录结构如图4-9所示。
39
电子科技大学硕士学位论文
disSubREADME52_52_sLICENSE
图4-9 节点打包后的目录结构
本文采取的是本地模块安装的方式,在本地安装节点模块,就用到了npm link命令。将节点的本地目录,链接到一个本地Node-red安装目录,这和npm安装是一样的。本地部署节点按照如下两个步骤即可完成部署。
1、在包含有的目录下执行sudo npm link命令。
2、在Node-red的运行运行目录下执行npm link <节点模块的名字>。
部署成功后,重新启动Node-red,然后浏览器中打开编辑界面,在最右侧的节点视图就可以看到新增加的节点,这样就完成了节点的设计和部署工作。到目前为止整个模型的设计已经全部完成,接下来就是对该模型的有效性和高性能通过实际工程项目加以验证。
4.5 本章小结
本章首先对基于Node-red与Redis的实时流数据处理模型及其应用进行了详细的需求分析,同时也对整个模型的总体架构进行了设计,阐述了架构中各个模块的功能以及整个模型的数据处理流程。然后对Node-red新引入的数据输入节点、输出节点、数据计算节点以及Redis数据库访问节点给出详细设计方案。最后,将设计的新节点安装部署到Node-red中,使其成为一个完整的流式数据处理模型。
40
第五章 实时流数据处理模型在网站访问监控系统中的应用
第五章 实时流数据处理模型在网站访问监控系统中的应用
第四章已经对基于Node-red与Redis的实时流数据处理模型进行了详细设计,本章的重点是将所设计的流式数据处理模型应用到实际的工程项目中,设计并实现一个网站访问的实时监控系统。本章最开始提出了针对该系统的实时数据采集方案并对系统的总体架构进行设计,然后对系统的数据分析模块进行了设计并实现,该模块是利用第四章所设计的实时流数据处理模型来实现的,最后对数据可视化模块进行了详细设计。
5.1 网站访问监控系统总体设计
在各级地方政府的电子政务系统不断的发展过程中,政府的信息收集与数据分析能力还比较薄弱,急需要一个统一的实时数据收集、储存、分析、应用的平台。该系统的所有数据都是来源于某地方政府的电子政务网站群的访问流量,数据真实可靠、说服力强,具有重要的实际意义和研究价值。接下来将对网站访问监控系统的实时数据采集分案以及整个系统的模块层次结构进行详细设计。
5.1.1 实时数据采集方案设计
整个系统作为实时数据的交互处理中心,除了自己内部的数据通信以外,还需要对网站群的访问流量进行实时采集[34]。这种数据具有实时性、连续性、非结构化等特点,同时数据量也非常巨大。由于数据实时性明显,同时也要求系统能够可视化模块中实时展示出网站群的访问情况,所以不能采用传统的先收集后处理的方案,需要重新设计一套实时流式数据收集方案。在服务器的网关直接利用http_tracer拷贝一份访问流量,然后实时的发布到Redis Server的http_trace通道中。
考虑到访问流量数据是一种非结构化的数据,为了能够更加准确地收集有效信息,需要在采集数据的时候进行原始数据的预处理。因为原始的访问流量就是HTTP请求和响应报文,如果仅仅是收集到了这些报文,它都是以字符串的形式存在,字符串不论是在数据解析过程还是在最终的数据可视化过程都使得问题变得极为复杂,为了方便解析,更好更准确的处理这些数据,有必要进行初步结构化处理。由于json格式的数据能够有效地反映数据的特点,同时与JavaScript对象能够实现无损转换,所以在进行数据格式化的时候选择json格式,同时在后面处理和存储中间结果集的时候也选择json格式。选择json格式来表示数据,还有一个重要的好处就是方便数据可视化,因为在数据可视化模块采用了highcharts来绘制41
电子科技大学硕士学位论文
图表,而highcharts要求的数据格式也是json格式。因此,本文设计出如图5-1所示的实时数据采集方案:
Redis
serverSubscribe订阅ChannelredisSubmsgToJSON(解析模块)数据结构化http请求包http响应包http tracerNode-red中的message对象Node-red数据处理中心
图5-1 实时数据采集方案图
从该采集方案中可以看出,在客户的服务器端,我们将网站的访问流量做一份拷贝,利用http_tracer将这部分流量发布到Redis server中,专门设置一个Redis的通道(channel)用于接收从http_tracer发布过来的原始数据。由于原始的数据报结构混乱,难以分析,再加之有许多客户并不关心的信息,所以在进行下一步数据分析之前需要进行预处理。原始数据通过redisSub节点从Redis server上被订阅,交给msgToJSON模块(这个模块是利用Node-red中的function_node实现的)。msgToJSON模块把原始数据报文分为请求报文和响应报文两类,最后只是在message对象中增加一个type字段加以区分。最终产生的数据就是一个JSON对象,继续传递给下游的数据处理中心,进行后续的数据处理工作。下面展示的就是预处理前的原始数据报格式:
HTTP_TRACE_REP|82.825|172.16.1.1:18083|42.91.9.230:24735|#8|
HTTP1.1|GET|/emall/css/|304|NotModified|15.491943359375ms|Ac
cept:Referer:/emall/myorder/Accept-Language:zh-cnUser-A
gent:Mozilla/4.0(compatible;MSIE8.0;WindowsNT5.1;Trident/4.0)Accept-Encodin
g:gzip,deflateHost:nection:Keep-AliveCookie:JSESSIONID:9
986FBA4B93382AB77946439738F1714|emall_shop_car:""|jiathis_rdc: %7B%22ht
tp%3A///emall/goods/%3Fgoodsid%1798085429%2
2http%///emall/goods//98085429%22http%//
42
第五章 实时流数据处理模型在网站访问监控系统中的应用
通过msgToJSON模块进行初步的结构化处理后的HTTP报文变成形如下面这样的json对象。
{
{"type": "HTTP_TRACE_REP", //标识报文类型
"http_version": "HTTP1.1",
"http_method": "GET",
"userIP": "42.91.9.230", //用户的ip地址
"hostIP": "172.16.1.1", //服务器ip地址
"target": "/emall/css/", //请求的目标文件
"status": "304", //http状态码
"host": "", //网站域名
"user_agent":"Mozilla/4.0(compatible;MSIE8.0;WindowsNT5.1;Trident
/4.0)n",//用户浏览器类型
"referer":"/emall/myorder/"
}
5.1.2 网站访问监控系统的模块层次结构
整个网站访问监控系统包括三大功能模块,实时数据采集模块、实时数据分析模块以及数据可视化模块,整个系统的模块层次结构如图5-2所示。
Web前端可视化模块mongo数据库实时流数据处理模型计算节点群Redis数据库http_tracer数据报采集器通道
图5-2 系统模块层次结构图
43
电子科技大学硕士学位论文
在5.1.1节中已经对实时数据的采集方案做了详细设计,而实时数据分析模块是搭建在第四章所设计的实时流数据处理模型上,通过编写各个功能函数节点来实现数据处理,这些函数节点构成了整个实时数据分析模块的计算节点群。同时,系统利用mongodb数据库完成数据持久化和用户信息保存任务,而Redis数据库是作为数据计算和数据交换的中心,负责中间结果集的统计和保存。
5.2 数据分析模块的设计与实现
5.2.1 数据分析模块的总体设计
数据分析模块是搭建在第四章所设计的基于Node-red与Redis的实时流数据处理模型上,数据在不同模块之间的流动是利用Redis的publish和subscribe机制以及的通信机制[32,33,34]来完成。位于网关的抓包模块抓取到原始的报文信息后,把数据发布到Redis server的http_trace通道上,然后在Node-red中利用在第四章设计的数据输入节点redisSub节点,从Redis server的http_trace通道订阅原始数据。数据进入Node-red之后,经过计算节点进行数据处理和封装,最后通过redisPub将处理结果publish到Redis的指定通道中,供可视化模块去接收这些数据。在数据处理过程中,需要用到Redis进行中间结果集的保存和初步的去重统计工作,这里的去重统计就是利用第三章所设计的基于Redis有序集合的去重统计方法,与Redis进行通信的节点就是第四章所设计的redis_in和redis_out节点。在节点之间的数据是通过的事件循环机制进行,这种机制已经被集成到Node-red中,因为Node-red也是基于开发的。
在进行数据分析的时候,本系统主要通过三个flow来完成,分别完成用户行为分析、网站群页面监控以及定时清理Redis server上的中间结果集。在进行用户行为分析的时候,计算节点按照功能的不同划分为5个计算节点refererCount、countUserAgent、repeatVisit、userIP以及visitPage,分别完成来路页面统计、用户的浏览器类型统计、重复访问页面统计、独立访问的IP地址以及受访页面统计。而对于网站群页面监控,主要涉及5个数据分析节点,分别是errPage、keyWordCount、hotVisitPage、channelVisit以及hostCount,他们分别完成错误页面统计、关键词统计、热点页面统计、频道访问统计以及网站访问统计。这些节点一起组成了一个计算节点集群,除了这些用于数据处理和计算的节点外,还包括Redis数据库的访问节点用于传输中间结果集到Redis数据库中,还包括一个功能节点(定时节点)用于定时向前端可视化模块推送数据,以达到实时更新显示数据的变化情况,该定时节点也用于定时清理Redis的中间结果集,以减轻Redis
server的负担。整个数据分析模块的总体架构如图5-3所示。
44
发布者:admin,转转请注明出处:http://www.yc00.com/news/1705192523a1398204.html
评论列表(0条)