OSSData:面向开源社区的分布式数据采集框架
2019-06-11林维陈曦王松
林维 陈曦 王松
摘要:近些年,开源软件发展迅猛,其应用领域和适用范围越来越广泛;与此同时,开源软件的成功也吸引了大量的开发者投入到开源软件的开发。因此,开源软件社区积累了大量的软件应用和开发数据。这些丰富的数据逐步引起了研究人员的关注,已经有相关工作对开源软件的群体开发模式和质量保证机制等展开了一系列研究。为了更好地支持此类研究工作的有效开展,面向开源社区提出了一个用户可定制的数据采集框架,该框架具有较高的灵活性和鲁棒性,能够根据用户的实际需求进行深度定制,并保持稳定持续的工作状态,从而提高数据采集的效率和质量。
关键词:开源社区;数据采集;网络爬虫;分布式框架
中图分类号:TM773
文献标识码:A
历经几十年的发展,开源软件已经取得相当瞩目的成就,许多像Linux和Android这样的优秀开源软件在各行各业发挥着重要的作用,他们的自由性、开放性以及较高的质量标准赢得了大量开发者和用户的良好口碑。与此同时,伴随着开源软件的成功,越来越多的开发者逐步认同开源理念并开始致力于开源软件开发。仅在GitHub社区,就已经有2400万注册用户和6700万版本库,开发者在开源社区的贡献热情空前高涨。
开源软件的快速发展同样也吸引了学术界研究学者的目光,已经有相关工作对开源软件和开源社区的演化模式[1,2]、群体协同贡献的激发和汇聚机理[3,4]、代码审查和质量保证机制[5,6]等问题进行了一系列研究。在这些研究中,有相当一部分工作是基于开源社区的历史数据开展的,例如代码实体、文本数据、开发行为数据、交互数据等。完整真实的数据源能够为学术研究提供强有力的分析基础和证据支持,使得研究成果更具说服力。因此,有效的数据获取是研究工作开展的重要前提。
目前,研究者经常通过抽取原始页面和访问网站官方API的方式采集数据,而无论哪一种方式都需要开发者在进行正式的数据分析前先编程实现数据采集系统,通常开发者要耗费相当一部分的精力用于处理网络访问、异常处理、数据库操作等復杂操作。因此,为支持研究人员更方便快速地开展学术研究,已经有相关工作尝试提供公开的数据源,供相关研究者直接应用,从而节省了重复编写程序采集数据的时间,加快了学术研究进展。例如Geogious[7]发布了GHTorrent系统,他设计了数据结构模式,通过GitHub官方API进行采集。较多研究[8,9,10]都引用了该数据集,但是它的数据量太大,使用其中一部分数据就需要下载完整的数据,并且其定义的数据模式有时并不能满足所有研究人员的实际需求,因为某些研究人员可能在GhTorrent中不能找到他所需要的字段。
为解决上述问题,面向GitHub社区提出了一个用户可定制的数据采集框架,该框架具有以下特点:
1.用户可定制性:用户可根据自己的实际需求进行精准的定向采集,在明确所需的数据后,结合官网提供的数据API接口,用户只需做简单配置即可方便地采集目标数据。
2.可扩展性:把数据采集流程分解为任务生成与任务执行两个模块,从而把耗时的任务执行过程剥离开来,便于利用分布式技术加速,提高数据采集效率。
3.鲁棒性:利用消息队列和数据库封装数据中间层,把业务逻辑所涉及到的各模块切分得更独立,从而使得系统拥有更强的容错能力和恢复能力。
剩余内容结构如下:论文第2节介绍相关工作,对基于GitHub社区的数据挖掘工作以及数据采集系统相关工作进行介绍;第3节介绍系统设计和实现,具体包括系统各模块的设计思路和功能作用;第4节报告系统评估结果,我们利用系统对几种常用的数据类型进行采集,并对采集效果进行了实际评估;第5节对本文进行总结,并展望了未来工作。
1 相关工作
本节将从两个角度出发,对已有研究工作进行系统总结。
1.1 GitHub数据挖掘相关研究
GitHub是众多开源社区中影响力最高、参与者最广泛、资源最丰富的一个,它在允许个人与组织创建、浏览公开的版本库的同时,还提供社区化的软件开发服务,这些服务包括允许用户关注其他用户,查看版本库的改动、issue和评论等;除此之外,GitHub也提供供版本库使用Wiki功能以及使用Git进行协同开发的功能。
由此可见,GitHub提供了一系列基于软件开发的用户行为数据以及软件开发的数据,研究人员可以充分利用GitHub的数据进行一些数据分析;杨波等通过对GitHub上的开源软件的开发过程进行分析,发现了开发过程中issue解决速度、issue增加速度等影响因素,并通过对这些影响因素关联性进行分析,证明了某些影响因素之间确实存在了一定的关联性,最后为基于GitHub的开源软件的开发过程提出了一些建议[11];
叶培根等通过对GitHub开源项目开发过程的数据进行挖掘,对软件开发团队当前进展进行量化分析,从而能够让管理者通过量化分析结果动态掌握开发团队的详细情况,从而合理分批资源、安排开发任务,最终达到提高开发效率的目的[12];
杨春花等通过对GitHub上的项目的缺陷数据进行分析,设计了一套软件缺陷数据预处理系统,通过使用该系统,用户可以简单方便的获取GitHub上自己想要分析的项目等缺陷数据集[13];
卢松等通过对GitHub中的Pull Request数据进行分析,实现了一种基于信息检索的代码审阅人推荐的方法,达到了优秀的结果,从而减少了大量的人力损耗[14];
Laura等通过对GitHub用户的社交网络进行分析发现,大规模分布式协作和开源社区的透明度具有非常高的价值,人们可以利用分布式协作提高自己的技术技能等[15];
Baishakhi等通过对GitHub上的软件项目分析编程语言对软件质量的影响,他们使用多元回归建模和可视化文本分析,来研究语言特性软件质量的影响,最终他们认为变成语言对软件质量有一定对影响,同时这些影响主要是由项目大小、团队规模和commit次数等因素为主导的[16];
Bogdan等为研究性别和职位多样性如何与团队生产力和人员流动率的关系,通过对GitHub的数据进行回归分析和调查发现性别和职位的多样性都是积极和重要的生产力预测指标,因此将这些结果告诉各个公司的决策层,从而在招聘和绩效方面得到良好的结果[17];
Bogdan等还通过对GitHub数据进行分析,探讨开发人员如何使用持续集成,以及贡献类型(直接与间接)和不同的项目特性(例如:编程语言和项目时间)是否与自动构建的成功相关[18];
1.2 数据采集系统
要对数据进行数据挖掘,那么第一步就是收集数据,只有拥有了大量的数据之后才能够对数据进行分析。
李海燕等为帮助用户尽早在网络中发现负面信息,设计了一套网络舆情爬虫系统,该系统利用ontology的抽取方式和基于HTML页面结构抽取方式相结合的方法获取网页关键信息,同时利用Nosql的数据库构建集群数据库,并实时对爬虫状态进行状态监控,从而满足了企业、个人、单位快速发现负面信息的需求[19];
为了企业、公司、个人能够及时发现自己关注的话题,避免不必要的损失,叶婷等设计了一种基于关键词的微博爬虫系统,该系统对需求关键词展开搜索,然后利用广度优先的爬去策略,解决了传统爬虫无法解决的动态页面、垂直爬取和自动登录问题[20];
网络爬虫在爬取数据时往往会因为数据提供商为控制访问频率对API进行一定限制,因此爬虫系统经常会遇到API访问受限的问题,为解决这个问题,卢杨、李华康等设计了一种基于P2P等爬虫系统,该系统避免新浪API等功能连接限制,使用基于模拟登陆的方式,根据用户地址位置划分任务,实现连续高效的数据采集爬虫系统[21]
李晨等为解决单机爬虫效率低、扩展性差的问题,设计并实现了一个基于MapReduce的爬虫系统,该系统利用HDFS和HBASE对信息进行存储管理,利用相似度分析的去重策略提高心性能,最终比单机爬虫的速度提高了4.8倍[22];
魏少鵬等为了应对目前网络爬虫实现过程复杂、使用不友好的问题,提出了一种基于Chrome扩展的爬虫系统,基于Netty框架实现中央服务器模块和主从库复制模块,同时引用Spring框架管理中央服务器类间依赖和提升爬虫系统的可扩展性;从而达到提高爬虫系统的友好度、可扩展性和可用性[23];
为了提高爬虫的性能,开发者在开发爬虫的时候希望爬虫只爬取那些尚未爬过的数据,也就是常说的增量更新,张雷等因此设计一种分布式爬虫系统,该系统由基于ZooKeeper的分布式服务、系统组件和数据库三部分组成,同时利用协调组件Co-ordinator定时向任务队列导入向任务,从而实现周期性增量更新[24];
2 系统设计与实现
2.1 系统架构
系统整体架构为如图1所示,系统主要分为任务推送器和任务执行器两个大板块,它们之间通过任务队列和数据存储进行连接和交互。任务推送器基于给定的采集需求生成采集任务并推送到任务队列中;任务执行器从任务队列中取出采集任务,然后从GitHub社区下载目标数据并存储到数据库中;其次,任务推送器还会对由于网络问题等未被成功执行的任务重新生成新的任务以保证任务的完整性。
2.2 任务推送器
任务推送器共分为三个模块:任务监控器、任务生成器和状态记录器
2.2.1 任务监控器
该模块根据执行器启动的节点数和任务队列中所剩余的任务数,来动态调整队列中的任务数。具体的,我们采用智能轮询方法,间歇性地观测任务队列状态,当任务数量小于预定义的阈值时,任务生成器继续生成任务并推送;当存量满足预设条件时,任务生成器则进行动态休眠,休眠时间为:
在上面的式子中,返回的是剩余任务数,是预定义的任务数量阈值,即剩余任务数越多,任务生成器休眠时间越长。
2.2.2 任务生成器
对于用户给定的项目列表或者已采集数据的列表,任务生成器会根据任务模板生成采集任务。以采集项目的Pull-request列表为例,用户首先指定要采集的项目集合PRJS,对于PRJS中的任一元素,任务生成器会应用以下所示的链接模板:
“https: //api.github.com/repos/[% s]/pulls?page=[%d]&per_page=lOO&state=all&direction=asc”
该链接模板对应着GitHub官方提供的API,符号“?”前面的部分用于指定目标项目,后面的部分是参数列表,例如per_page指定每一次访问返回Pull-request的数量,all表示所有状态的Pull-request都需要被采集。其中“口”中的参数需要根据项目名字和采集进度指定。对于用户来说,如果想要采集Pull-request的commit和diff信息,则需要根据系统的采集历史把项目的名称和Pull-request的编号分别应用到以下链接模板:
“https: //api.github.com/repos/% s/pulls/%s/com-mits”
“https: //patch -diff.githubusercontent.com/raw/%s/pull/%s.diff”
2.2.3 状态记录器
状态记录器负责记录任务生成器和任务执行器的历史处理状态。为保证系统的高可靠性,我们要求系统可以随时关闭以及随时启动,并且再次启动后可以正确地继续之前的工作。一条任务生成后,有两处可以停留的地方:一个是在任务队列中等待任务执行器执行;另一个是在任务执行器中被执行。这两部分的数据由于是在内存中,因此当采集系统停掉或重启后会丢失掉。为恢复这些丢失的数据,任务记录器采用”记录一确认”( Record-Then-Confirm,RTC)的策略。
如图2所示,RTC随时记录任务生成器和任务执行器以批处理形式进行的操作,当系统重启后,RTC首先取出最近的状态记录,然后把任务生成记录与任务执行记录进行比对确认,然后把那些被生成后但是没有被成功执行的任务重新放到任务队列中再次执行。
2.3 任务执行器
2.3.1 采集節点
为提高系统的采集性能,我们设计了分布式的任务执行器,具体的任务采集工作由分布式采集节点执行。如前所述,任务生成器把任务推送到任务队列中,而每一个采集节点从任务队列中取出任务去执行,并把执行结果进行持久化。由于每一个节点都是从任务队列中取任务,他们之间并没有发生交互和依赖,因此分布式节点集群具备非常灵活和强大的扩展伸缩能力。根据用户的需求,采集节点的数目可以随时添加以加快采集速率。
2.3.2 数据抽取器
任务执行器把采集任务完成后,获得的往往是原始数据,例如json数据、html文本或者纯文本数据等。为了便于后续的数据处理和分析,数据抽取器负责对原始数据进行解析和抽取。抽取方法采用的是基于规则的形式,用户根据具体要求指定待抽取字段和相应的抽取规则。抽取规则可以根据原始数据的格式进行调整,如可以使用XPath对html文本进行抽取,而利用键值嵌套路径对json数据进行抽取。
2.3.3 token池
GitHub为限制恶意访问,会对访问者单位时间内的API访问次数做限制,使其不能发起过多的访问请求,否则平台会拒绝响应并返回错误信息。若想获得更高的访问频率,GitHub要求访问者必须注册GitHub账户并申请认证token.并在每次请求访问时都附带上该token信息。认证token能够大幅度提高单位时间内的访问频率,因此我们为系统建立了智能认证模块。
如图3所示,首先,系统维护一批可用的token并建立token池,每次采集节点要进行网络访问时都要从token池随机取出一个token,使用完后立即放回到token池中。此外,为了保证token的有效性,智能认证模块随时验证token是否处于可用状态,如若检测到不可用的token则立即删除,使得token池中的任何一个token时刻保持在有效状态。
2.4 数据中间层
任务生成器和任务执行器通过数据中间层解耦合,中间层主要包括任务队列和数据库。
2.4.1 任务队列
任务队列通过消息队列技术实现,消息队列本身的一些原子操作特性保证了并行操作的有效性。就业务逻辑来讲,本文中的数据采集系统相当于生产者一消费者模式。任务生成器相当于生产者,而任务执行器相当于消费者。任务生成器的工作效率比较高,单节点模式基本可以满足需求,而消费者的工作效率比较低,需要用分布式多节点技术来加速。基于消息队列技术的任务队列可以非常巧妙地支持这种一对多的工作模式,任务生产器专注于向队列中推送任务,而执行器集群以并行的形式有条不紊地从任务队列中取出任务并执行。
2.4.2 数据存储
任务执行完毕所获得的原始数据以及抽取后的结构化数据都会存到数据库中进行持久化。底层数据存储方案采取的是关系型数据库,图4展示了以pull-request的提交信息和变更信息为例的数据模式图。
2.5 辅助工具
2.5.1 配置管理器
配置管理器负责系统中的各种配置工作,例如数据库链接、消息队列启动和连接、日志记录路径配置等。配置管理器作为单独模块,剥离了系统中与主要业务逻辑无关的工作,能够提升系统的迁移能力,便于系统部署到不同的环境。
2.5.2 日志记录器
日志记录器负责记录系统运行中的实时状态,例如对系统中关键节点的异常情况的记录。完备的日志记录是评估系统性能并进行针对性改进的重要前提,也是监控系统运行状态的有效数据源。
2.5.3 系统监控器
系统监控器以可视化界面直观地展示系统各模块的运行状态。如图5所示,结合进程运行状态和日记记录,系统监控器能够显示各模块是否处于正常运行状态以及模块的进度情况。此外,界面还提供了一些常用的交互功能,以允许用户方便地执行相关命令,如启动或者停止某个模块、动态增加或者减少采集节点的个数等。
3 系统评估
3.1 实验环境
硬件:双核3.6 GHz,8GB内存;运行操作系统:Ubuntu 16.04;单机限制带宽:IOOMB。
3.2 评估结果
3.2.1 资源占用率评估
实验过程中,我们对任务执行器分别运行了单个节点、5个节点和10个节点,并对比了它们的资源占用情况,其对比结果如下表所示:
通过表1我们看出,系统对资源的占用非常低,平均每个任务节点在服务器上占用的CPU资源和内存资源的比例分别为1%和1.2%左右。由此可见,系统仅需非常低的资源配置,在网络条件良好的情况下就可以正常运行,降低了系统对硬件配置的需求;与此同时,随着任务节点的增加,系统对服务器资源的需求是线性增长的,由此没有为系统增加额外的负担,说明系统的稳定性是良好的。
3.3 采集速率评估
实验测试中,我们分别在单节点、5个节点和10个节点的情况下让系统运行5小时,采集效率如图6所示,从图中我们可以看出,每个节点每小时采集的平均任务数量为1600个左右,该速率能够较好地满足用户的实际需求,同时又能够以一种友好的方式对目标网站进行持续采集。而且,随着任务节点数量的增加,爬虫系统的采集数量以线性递增,说明各个任务节点互不影响,系统能够保证在多个任务节点的情况下稳定爬取指定的资源,由此可见系统的稳定性以及鲁棒性是良好的。即采集系统可以在保证系统稳定性的前提下通过启用多个任务节点来快速获取指定资源的目的,从而满足用户的任务需求。