多用户环境下流式数据处理方法与流程

文档序号:15615169发布日期:2018-10-09 21:11阅读:268来源:国知局

本发明涉及计算机数据处理技术。



背景技术:

流式数据,又叫做流水数据,是一组顺序、连续到达的数据序列,一般情况下,流式数据可被视为一个随时间延续而无限增长的动态数据集合;严格意义上讲,由数千个数据源持续生成的数据,通常也同时以数据记录的形式发送,数据规模时时变化的数据形式。同时,流式数据的特点:

1)数据传输实时性;

2)数据传输顺序独立性,不受外部因素所控制;

3)数据规模不确定性,不能预知其最大值或者最小值;

4)数据回溯难度高,一经处理,除非特意保存,否则不能被再次取出,或者再次提取数据代价高。

基于流式数据自身的特点,其在内存中处理难度就显得尤为突出。随着互联网、物联网的不断发展,同时在网络监控、传感器网络、航空航天、气象测控和金融服务等领域广泛存在,人们对流式数据的处理需求也日渐增多。

在多用户的环境下,不同的用户对数据流中的元数据有不同的要求,共享内存机制是现阶段比较常见的流式数据内存处理方式如图1所示,以共享内存方式实现用户间数据的处理(ipc),用户a创建内存块,映射共享内存数据,把指定的共享数据映射到用户的地址空间用于访问;用户b创建共享内存,映射共享内存数据,把指定的共享数据映射到用户的地址空间用于访问,映射成功后就能从用户的内存中读出数据,以此类推。这样能够有效保护元数据的完整性和正确性,但也不可避免的造成了系统资源的过多消耗,降低了系统效率,随着数据量的不断增大,该问题越发明显和严重。同时由于该机制是动态地从内存中申请,在数据量操作频繁的系统中,也带来了系统实时性和内存碎片等问题。

共享内存机制实现用户间通信,一般采用的步骤有:

a用户:

1)创建命名的共享内存,包含n个固定大小为x的块区域。

2)创建内部线程同步机制阻止多个线程同时获得数据块,创建运行条件;

3)等待信号,当前块可读;

4)从内存中读取该内存块,读完之后标识它们再次可写;

5)转到步骤3)。

b线程:

1)创建命名的共享内存,包含n个固定大小为x的块区域;

2)创建内部线程同步机制阻止多个线程同时获得数据块,创建运行条件;

3)等待信号,当前块可读;

4)从内存中读取该内存块,读完之后标识它们再次可写;

5)转到步骤3)。



技术实现要素:

本发明所要解决的技术问题是,提供一种具有更高处理效率的流式数据处理方法。

本发明解决所述技术问题采用的技术方案是,多用户环境下流式数据处理方法,其特征在于,包括下述步骤:

1)自数据流中读取数据内容,按读取顺序存储到内存环中的存储区,所述内存环为遵循先进先出原则的、由至少8个存储区构成的内存区;

2)若接收到用户数据请求,则根据用户请求的优先级,将用户请求加入请求队列;

3)按照队列顺序处理用户请求,在内存环中检索请求中的数据内容,

若检索出符合请求的数据,进入步骤4);

若未检索出符合请求的数据,则进入步骤5);

4)向该用户返回其请求的数据在内存环中的地址指针;

5)等待预定时长后将该用户请求重新加入请求队列,若经过预定次数或预定时长后依然未检索出符合请求的数据,则向用户返回提示信息。

进一步的,所述步骤4)包括:

(4.1)向该用户返回其请求的数据在内存环中的地址指针,并记录该数据所在的内存地址与提出请求的用户,然后进入步骤(4.2);

(4.2)若该数据已被全部用户请求过,则释放该数据所占用的内存地址。

本发明所述的“先进先出原则”是指按照写入内存区的顺序,先写入的数据所占的内存先释放(即设置为可写入新数据的状态)。

本发明的有益效果是,降低了系统资源的消耗,特别是内存空间的消耗;避免了用户频繁的申请和释放内存;减少了内存碎片的产生;降低了造成内存泄漏的几率;提升了系统的运行效率。

附图说明

图1是现有技术的应用示意图。

图2是本发明的应用示意图。

图3是本发明的内存环的原理图。

图4是本发明的数据共享机制的结构框图。

图5是本发明的用户请求数据时序图。

图6是本发明的数据存储时序图。

图7是本发明的内存环数据存取算法示意图。

图8是本发明的内存环数据搜索示意图。

具体实施方式

本发明采用环形内存零拷贝处理机制。改机制在传统的数据共享机制的基础,对核心模块进行了重新设计和封装,同时引入了内存环的概念。如图2所示,与传统机制相比,最大的不同是用户在从内存缓存去获取数据时,得到的不是具体数据,而是数据对应的内存地址。

参见图3。环形内存数据共享机制的原理:预先从内存中分配一块内存来构建内存环,该内存环的初始大小计算公式:ncount=(rear-front+nsize)%nsize。

rear:表示队列尾偏移量,该量放置在共享内存head中,对所有组件可见;

front:表示当前进程的头偏移量,该量为进程私有变量,对当前组件可见;

nsize:表示队列最大单元结构数目,该量放置在共享内存head中,对所有组件可见。

内存环创建完成之后,后面的组件直接映象即可。在使用时为了防止非法操作,在映射时可验证名称和结构单元的长度。

环境内存数据共享机制在软件中以一个组件的方式运作,该组件的结构框图如图4所示。

用户调度模块:环形内存处理器对外接口层,为外部提供必要的接口,同时也完成用户的调度管理。

环形内存管理模块:环形内存处理器中内存缓冲区管理,负责日常的内存申请和释放,以及内存数据的维护。

环形内存数据模块:元数据存储层,环形内存处理器内部存储结构区。

图5和图6示出了本发明的内存环数据共享机制时序。

在元数据进行写入时候,运用循环队列构建缓存区,按顺序依次写入数据,即原始数据的缓存。若缓冲区被写满,即可写入的缓存空间为0时,则新写入的数据自动覆盖最早写入的数据,此时会有数据写溢出告警,即数据读取处理的速度小于了数据写入速率,需要根据情况调整数据读取的速率。

在提取数据时,采用零拷贝的方式,即一份数据在经过缓存以后不再拷贝即可被多个数据消费者同时使用,

数据消费者使用数据时先申请指定长度的数据,查询成功后再在数据缓冲区添加此数据消费者需求数据的指针,数据使用完成后释放该消费指针。

同理,多个消费者并发访问同一份数据时,构建多个指针指向同一缓存区的不同地址,以满足不同消费者消费同一类数据的需求。如图7所示。

在元数据进行写入时候,此时运用循环队列来实现缓存区。

此算法有两个重点:内存环,实时操作的内存容量。

内存环申请的大小可以自定义,每个单元结构也可以自定义进行构造。

进队列(写入数据):

pucwrite=(pucwrite+写入数据大小-puchead)%ibuffersize+puchead

出队列(读取数据):

puclastread=(puclastread+读取数据大小-puchead)%ibuffersize+puchead

每次写入或者读取的大小也是可根据需要进行变化的,减少内存空间的浪费和内存碎片的产生,如图4所示。具体的原则如下:

当pucwrite大于puclastread(最后读取缓冲区共享数据地址)时:

可写入数据内存=puclastread+ibuffersize–pucwrite–1

当pucwrite小于puclastread(最后读取缓冲区共享数据地址)时:

可写入数据内存=puclastread–pucwrite–1

当pucwrite等于puclastread(最后读取缓冲区共享数据地址)时:

可写入数据内存=ibuffersize–1

当pucwrite大于reader(有多个读者,每一个读者位置可能不同)时:

可读取数据内存=pucwrite-reader

当pucwrite小于reader(有多个读者,每一个读者位置可能不同)时:

可读取数据内存=pucwrite+ibuffersize-reader;

当pucwrite等于reader(有多个读者,每一个读者位置可能不同)时:

可读取数据内存=0

注:写入数据时减去1的原因:牺牲一个字节的内存来辨别当前读者是没读还是读完。

读者未读时:reader==pucwrite

读者已读时:(reader–puchead+1)%ibuffersze+puchead==pucwrite

环形内存数据共享机制的搜索特殊性体现在内存环中倒数第二个结构体上。当释放读者资源和读取完数据时,对应的元数据指针地址等于puclastread(最后读取缓冲区共享数据地址)时,需要倒数第二的读取缓冲区共享数据地址代替puclastread。如图8所示。

具体步骤:

因为循环队列里不能通过直接比较读者指针的大小来排序,所以把循环队列从逻辑上换算为两个队列。

新建一个list<unsignedchar*>,然后对读者指针先进行处理:在writer右边的地址直接插入list中;在writer左边的地址的值加上ibuffersize后插入list中;等于writer的地址直接插入list中。

用两趟冒泡排序,得出最小的两个地址,倒数第二位为所求地址。

把所求地址又进行处理,如果该地址大于puctail,则减去ibuffersize,如果小于等于puctail,则不做处理。最后得出的地址为倒数第二个读者的地址。

环形内存数据共享机制接口设计:

为了在软件中该机制能够比较好的迎合各个模块对元数据的不同要求,设计了以下接口。

1)intcdatashareline::dataapiinit()

功能描述:完成模块初始化。

2)intcdatashareline::dataapidestroy()

功能描述:销毁该模块对象。

3)intcdatashareline::datacreate(intidatatype,intichannelid)

函数功能:在数据共享总线内存空间申请共享数据空间,即创建一个cdatashare类对象,并完成相应的参数初始化设置。

函数逻辑:

加write锁;

判断ichannelid是否重复或者小于等于0,若重复或者小于等于0,则解锁后返回失败;

新建cdatashare对象并初始化赋值(申请缓冲区内存等)。往m_pchannelpool(通道管理池)插入数据,key为ichannelid,value为新建的cdatashare对象;

解锁;

返回ichannelid(ishareid=ichannelid)

4)intcdatashareline::datarelease(intishareid)

函数功能:数据共享释放,数据读取者保证不再使用所读取内存块的数据,根据其他数据读取者使用情况释放数据内存,即销毁一个cdatashare类对象。

函数逻辑:

加write锁;

判断ishareid是否存在,若不存在则解锁后返回失败;

获取cdatashare对象,判断相应mtaskreadinfo(共享数据任务列表)中是否有任务执行,如有,则先释放读者,写者资源后释放cdatashare对象;

解锁;

返回成功;

5)intcdatashareline::adddatareadid(intishareid);

函数功能:为已创建的共享数据增加一个共享数据读取者。

函数逻辑:

加read锁;

判断ishareid是否存在于m_pchannelpool(通道管理池)中,若不存在则解锁后返回失败,反之获取cdatashare对象后加锁;

创建一个唯一的isharereadid插入mreadcntchannel中,key值为isharereadid,value为ishareid;

维护mtaskoverflowinfo,插入数据key为isharereadid,value为0;

往mtaskreadinfo(共享数据任务列表)插入数据,key为isharereadid,value为pucwrite(最后写入缓冲区共享数据地址);

解锁后返回isharereadid;

6)intcdatashareline::deletedatareadid(intisharereadid);

函数功能:共享数据读取释放

函数逻辑:

加read锁;

判断isharereadid是否存在于m_mreadcntchannel(通道管理池)中,若不存在则解锁后返回失败,反之通过isharereadid获取对应的ishareid;

判断ishareid是否存在于m_pchannelpool(通道管理池)中,若不存在则解锁后返回失败,反之获取cdatashare对象后加锁;

在mtaskreadinfo(共享数据任务列表)中,通过isharereadid获取value(执行到当前的缓冲区的地址),判断value(该任务当前执行到的缓冲区的地址)是否等于puclastread;(最后读取缓冲区共享数据地址),若是,则把puclastread(最后读取缓冲区共享数据地址)设置为倒数第二位的读者地址;

维护mtaskoverflowinfo,删除key为isharereadid的数据;

mtaskreadinfo(共享数据任务列表)中移除key为itaskid的数据;

解锁;

返回成功;

7)intcdatashareline::writedata(intishareid,byte*pbdata,intilen);

函数功能:共享数据写入pbdata:写入数据的指针ilen:写入数据长度。

函数逻辑:

加read锁;

判断ishareid是否存在于m_pchannelpool(通道管理池)中,若不存在返回失败,反之获取cdatashare对象;

通过cdatashare对象获取puchead;(数据缓冲区),并加锁;

判断puchead;(数据缓冲区)是否有足够内存写入数据,若不够则解锁后返回失败并且维护好溢出信息记录;

把pbdata的数据写入puchead(数据缓冲区);

把相应的pucwrite(最后写入缓冲区共享数据地址),iunusedsize;(未使用缓冲区大小),iusedsize(共享数据已使用缓冲区大小)更新;

给puchead;(数据缓冲区),解锁;

返回成功;

8)intcdatashareline::readdata(intisharereadid,byte*pbdata,intilen);

函数功能:共享数据读取pbdata:读取数据的指针ilen:写入数据长度

函数逻辑:

加read锁;

判断isharereadid是否存在于m_mreadcntchannel(通道管理池)中,若不存在则解锁后返回失败,反之通过isharereadid获取对应的ishareid;

判断ishareid是否存在于m_pchannelpool(通道管理池)中,若不存在则解锁后返回失败,反之获取cdatashare对象后加锁;

通过cdatashare对象获取puchead;(数据缓冲区),并加锁;

判断puchead;(数据缓冲区)是否有足够数据读取,若不够则解锁后返回失败并且维护好溢出信息记录;

把相应的puclastread(最后读取缓冲区共享数据地址),iunusedsize;(未使用缓冲区大小),iusedsize(共享数据已使用缓冲区大小)更新;

给puchead;(数据缓冲区),解锁;

返回成功;

9)intcdatashareline::datarelease(intisharereadid)

函数功能:共享数据缓冲区数据释放

函数逻辑:

加read锁;

判断isharereadid是否存在于m_mreadcntchannel(通道管理池)中,若不存在则解锁后返回失败,反之通过isharereadid获取对应的ishareid;

判断ishareid是否存在于m_pchannelpool(通道管理池)中,若不存在则解锁后返回失败,反之获取cdatashare对象后加锁;

在mtaskreadinfo(共享数据任务列表)中,通过isharereadid获取value(执行到当前的缓冲区的地址),判断value(该任务当前执行到的缓冲区的地址)是否等于puclastread;(最后读取缓冲区共享数据地址),若是,则把puclastread(最后读取缓冲区共享数据地址)设置为倒数第二位的读者地址;

维护mtaskoverflowinfo,删除key为isharereadid的数据;

mtaskreadinfo(共享数据任务列表)中移除key为itaskid的数据;

解锁;

返回成功;

10)intcdatashareline::shareidoverflowinfo(intisharereadid);

函数功能:获取读取id共享总线溢出信息

函数逻辑:

加read锁;

判断isharereadid是否存在于m_mreadcntchannel(通道管理池)中,若不存在则解锁后返回失败,反之通过isharereadid获取对应的ishareid;

判断ishareid是否存在于m_pchannelpool(通道管理池)中,若不存在则解锁后返回失败,反之获取cdatashare对象后加锁;

在mtaskoverflowinfo中通过isharereadid获取读取id溢出次数;

返回读取id溢出次数;

11)intcdatashareline::getsharechannlecount(int&icount)

函数功能:获取所有共享空间个数

函数逻辑:

加read锁;

获取pchannelpool的个数写入icount地址;

解锁;

返回成功;

12)intcdatashareline::getalloverflowinfo(_schannleinfo*poutinfo,inticount)

函数功能:获取所有通道共享总线溢出信息

函数逻辑:

加read锁;

判断icount是否等于m_pchannelpool.count(),如果不等于就解锁后返回失败,并做好日志记录;

通过poutinfo指针写入icount个schannleinfo结构的数据;

解锁;

放回成功。

当前第1页1 2 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1