电竞大数据时代,数据对比赛的观赏性和专业性都起到了相当重要的做用。一样的,这也对电竞数据的丰富性与实时性提出了愈来愈高的要求。git
电竞数据的丰富性从受众角度来看,可分为赛事、战队和玩家数据;从游戏角度来看,维度可由英雄、战斗、道具以及技能等组成;电竞数据的实时性包括赛前两支战队的历史交战记录、赛中的实时比分、胜率预测、赛后比赛分析和英雄对比等。github
若是你想了解大数据的学习路线,想学习大数据知识以及须要免费的学习资料能够加群:784789432.欢迎你的加入。天天下午三点开直播分享基础知识,晚上20:00都会开直播给你们分享大数据项目实战。算法
若是你仍是认为写博客浪费时间,请参考Dave Robinson撰写的相关文后端
所以多维度的数据支持,TB到PB级别的海量数据存储与实时分析都对底层系统的架构设计有着更高的要求,亦带来了更严峻的挑战。api
本文将介绍电竞数据平台FunData架构演进中的设计思路及相关技术,包括大数据流处理方案、结构化存储转非结构化存储方案和数据API服务设计等。在其v1.0 beta版本中,FunData为顶级MOBA类游戏DOTA2(由Valve公司出品)提供了相关的数据接口。缓存
项目发展初期,依照MVP理论(最小化可行产品),咱们迅速推出FunData的初版系统(架构图如图1)。系统主要有两个模块:Master与Slave。markdown
Master模块功能以下:架构
Slave模块功能以下:并发
系统上线初期运行相对稳定,各维度的数据均可快速拉取。然而随着数据量的增多,数据与系统的可维护性问题却日益突出:负载均衡
在开始2.0架构设计与改造前,咱们尝试使用冷存储方法,经过迁移数据的方式来减轻系统压力(架构设计如图2)。因为数据表数据量太大,并发多个数据迁移任务须要大量时间,清理数据的过程一样会触发从新构建索引,方案的上线并无根本性地解决问题。
吸收1.0系统的经验,在2.0架构设计(架构图如图3)中,咱们从维护性、扩展性和稳定性三个方面来考虑新数据系统架构应该具有的基本特性:
2.0系统选择Google Cloud Platform来构建整个数据ETL系统,利用PubSub(相似Kafka)做为消息总线,任务被细化成多个Topic进行监听,由不一样的Worker进行处理。这样一方面减小了不一样任务的耦合度,防止一个任务处理异常致使其余任务中断;另外一方面,任务基于消息总线传递,不一样的数据任务扩展性变得更好,性能不足时可快速横向扩展。
任务粒度细化
从任务粒度上看(如图3),数据处理分为基础数据处理与高阶数据处理两部分。基础数据,即比赛的详情信息(KDA、伤害与补刀等数据)和录像分析数据(Roshan击杀数据、伤害类型与英雄分路热力图等数据)由Supervisor获取Steam数据触发,通过worker的清理后存入Google Bigtable;高阶数据,即多维度的统计数据(如英雄、道具和团战等数据),在录像分析后触发,并经过GCP的Dataflow和自建的分析节点(worker)聚合,最终存入MongoDB与Google Bigtable。
从Leauge-ETL的细化架构看(如图4),原有的单个Slave节点被拆分红4个子模块,分别是联赛数据分析模块、联赛录像分析模块、分析/挖掘数据DB代理模块和联赛分析监控模块。
同时全部的模块选择Golang重构,利用其“天生”的并发能力,提升整个系统数据挖掘和数据处理的性能。
分布式存储
如上文提到,1.0架构中咱们使用MySQL存储大量比赛数据及录像分析数据。MySQL在大数据高并发的场景下,总体应用的开发变得愈来愈复杂,如没法支持schema常常变化,架构设计上须要合理地考虑分库分表的时机,子库的数据到必定量级时面临的扩展性问题。
参考Google的Bigtable,做为一种分布式的、可伸缩的大数据存储系统,Bigtable与HBase能很好的支持数据随机与实时读写访问,更适合FunData数据系统的数据量级和复杂度。
在数据模型上,Bigtable与HBase经过RowKey、列簇列名及时间戳来定位一块数据(Cell,如图6)。
例如,在FunData数据系统中,比赛数据的RowKey以hash_key+match_id的方式构建,由于DOTA2的match_id是顺序增大的(数值自增量不惟一),每一个match_id前加入一致性哈希算法算出的hash_key,能够防止在分布式存储中出现单机热点的问题,提高整个存储系统的数据负载均衡能力,作到更好的分片(Sharding),保障后续DataNode的扩展性。
如图7,咱们在hash环上先预设多个key值做为RowKey的前缀,当获取到match_id时,经过一致性哈希算法获得match_id对应在hash环节点的key值,最后经过key值与match_id拼接构建RowKey。
时间戳的使用方便咱们在聚合数据时对同一个RowKey和Column的数据重复写入,HBase/Bigtable内部有自定的GC策略,对于过时的时间戳数据会作清理,读取时取最新时间节点的数据便可。
这里你们可能会有个疑问,Bigtable与HBase只能作一级索引,RowKey加上hash_key以后,是没法使用row_range的方式批量读或者根据时间为维度进行批量查询的。在使用Bigtable与HBase的过程当中,二级索引须要业务上自定义。在实际场景里,咱们的worker在处理每一个比赛数据时,同时会对时间戳-RowKey构建一次索引并存入MySQL,当须要基于时间批量查询时,先查询索引表拉取RowKey的列表,再获取对应的数据列表。
在数据读写上,Bigtable/HBase与MySQL也有很大的不一样。通常MySQL使用查询缓存,Schema更新时缓存会失效,另外查询缓存是依赖全局锁保护,缓存大量数据时,若是查询缓存失效,会致使表锁死。
如图8,以HBase为例,读取数据时,client先经过zookeeper定位到RowKey所在的RegionServer,读取请求达到RegionServer后,由RegionServer来组织Scan的操做并最终归并查询结果返回数据。由于一次查询操做可能包括多个RegionServer和多个Region,数据的查找是并发执行的且HBase的LRUBlockCache,数据的查询不会出现所有锁死的状况。
基于新的存储架构,咱们的数据维度从单局比赛扩展到了玩家、英雄、联赛等,如图9。
系统解耦
上文咱们提到1.0架构中使用In-Memory的消息队列作数据传递,因为内存中队列数据没有持久化存储并与Master模块强耦合,Master节点更新或者异常Panic后会致使数据丢失,且恢复时间冗长。所以,在2.0架构中采用了第三方的消息队列做为消息总线,保障系统“上下游”节点解耦,可屡次迭代更新,历史消息变得可追踪,基于云平台消息堆积也变得可视化(如图10)。
1.0系统的数据API层为实现快速上线,在架构上未作太多的设计与优化,采用域名的方式实现负载均衡,并使用开源的DreamFactory搭建的ORM层,利用其RESTful的接口作数据访问。
该架构在开发和使用过程当中遇到许多问题:
针对上述问题,咱们从两个方面重构了1.0数据API层,如图11。
链路的稳定性
全球链路上,咱们使用CDN动态加速保证访问的稳定性。同时利用多云厂商CDN作备份容灾,作到秒级切换。
在调度能力和恢复能力上,咱们搭建了本身的灰度系统,将不一样维度的数据请求调度到不一样的数据API,减小不一样维度数据请求量对系统的影响;借助灰度系统,API服务更新的风险和异常时的影响面也被有效控制。依赖云平台可用区的特性,灰度系统也能方便地实现后端API服务跨可用区,作到物理架构上的容灾。
另外,为保证内部跨洋访问链路的稳定性,咱们在阿里云的北美机房搭建数据代理层,利用海外专线来提高访问速度。
数据高可用性
接入分布式存储系统后,对外数据API层也根据扩展的数据维度进行拆分,由多个数据API对外提供服务,例如比赛数据和联赛赛程等数据访问量大,应该与英雄、我的及道具数据分开,防止比赛/赛事接口异常影响全部数据不可访问。
针对热点数据,内部Cache层会作定时写入缓存的操做,数据的更新也会触发Cache的重写,保障赛事期间的数据可用。
本文介绍了FunData数据平台架构演进的过程,分析了旧系统在架构上的缺点,以及在新系统中经过什么技术和架构手段来解决。
FunData自4月10日上线以来,已有300多位技术开发者申请了API-KEY。目前也在着力于新数据点的快速迭代开发,如联赛统计数据。比赛实时数据等。