NightPxy 个人技术博客

数据平台设计思考

Posted on By NightPxy

概述

这是一篇个人对数据平台设计的一些思考
个人理解中,未来的大数据落地必然是以数据平台的形式的,这是未来大数据应用的发展方向

数据平台的本质是对外提供数据服务

  • 包含数据的计算以及存储等等基本数据服务
  • 包括数据管理,监控,统计报表等等衍生数据服务

数据平台首先的定位是SAAS

  • 面向用户屏蔽大数据技术 集群管理,大数据组件以及相关技术的应用,统统需要隔离
    在数据平台的用户端首先是易用的,这种易用首先就体现在屏蔽大数据技术的高学习成本
  • 多用户(或者说商户)隔离
    数据平台本身的成本也非常高,这代表只有一个数据平台以多用户形式提供数据服务
    这种隔离体现在:数据隔离,存储隔离,集群资源隔离等等

数据平台的基石是:计算,存储,调度以及元数据库

数据平台的对外呈现是:UI(用户以及管理),数据服务接口以及一些数据组件

  • Jar RPC 直传数据的SDK
  • 应用组件 Flume采集组件,BinLog采集组件等等

一个大致数据平台执行流程是

  • 用户建表
    确定Schema信息,数据源(流式采集还是离线定时采集),存储方式等等
  • 编写计算SQL,并确定该计算的定时触发

三大基石

计算层面

SQL解析引擎

数据平台的一个基础标准是屏蔽大数据技术细节,实现的手段就是SQL化
SQL一种非常简答非常利于上手的语言,平台使用人员只要稍加了解就可以很快掌握
所以数据平台的对外使用一定是SQL化的

SQL本身只是一种描述,一般来说SQL解析的基本步骤是

  • 通过某种方式,将SQL这种描述性语言转换为一种通用的编程模型抽象语法树
  • 抽象语法树进行校验
    基本语法校验,比如聚合函数必须有指定分组函数等等
    元数据校验,比如表,列甚至函数等等是否存在,这里需要元数据的支持
  • 生成物理执行计划
    根据抽象语法树翻译成某种执行代码执行(比如java,scala甚至Spark)等等

这里暂时跳过三个步骤

  • 抽象语法树的逻辑执行优化,比如列裁剪和下推
  • 物理执行计划优化,比如对分区列分组统计,可以不必真实执行,而是可以走元数据
    也就是元数据的一些统计信息可以直接满足查询(假如有的话)
  • 执行计划的代价优选过程
    对同一个抽象语法树生成多个执行计划,通过代价预测的方式选择一个更优计划

这里代表数据平台至少需要三个组件

  • SQL解析引擎
  • 计算执行引擎
  • 元数据库

流批统一

因为数据平台已经屏蔽了大数据细节,譬如大数据技术中的流批之分,就必须设法弥合

流批统一,是两个层面的事

  • 数据收集层面
  • 计算层面
数据收集层面

数据收集层面做法本质上不是弥合,而是做高纬抽象
这个高纬抽象就是数据源

也就是说,数据收集的定义上以数据源划分,而不关心流批
而在数据收集的执行上,通过数据源各自产生流批应用
比如

  • Kafka数据源,将会以流式收集
  • JDBC数据源,将会以批处理形式收集
计算层面

在计算层面,则是统统以批完成

这样做的考虑是

  • 绝对意义的实时处理是不存在的
    就是以真流形式运行的Flink,也必然有延时(毫秒级)
    而在绝大部分场景下,毫秒级其实没这个必要
  • 流式处理有瓶颈
    流式处理的吞吐量是远比不上批处理的
    流式处理的计算很难做复杂计算
    以Streaming为例,就算是秒级触发,在大数据量下很难想象此时因为计算走两个shuffle
  • 只要批处理的快,比如秒级,就可以认为是伪实时了
    所以以批处理做实时,最大的要点就是要快

批处理的快,体现在以下部分

  • 调度触发快 因为离线计算触发依赖调度触发
    这首先需要调度系统的支持 比如独立的快调度池
  • 资源申请的快 因为离线计算是一次独立执行,所以有独立申请
    因为YARN资源申请是始终有瓶颈的(至少15秒),还不算离线应用的Jar上传部分
    所以快离线,不应该是一个普遍意义上的离线任务,而是一种特殊的长尾服务
    即计算完毕之后不释放资源,而是直接进行下次作业,以此循环
  • 计算的快
    计算逻辑的部分很难做优化,因为这往往是由业务决定而无法变更
    所以计算的快是以并行计算实现的,用空间换时间的做法
    假设一分钟内每5秒产生一个数据批次,那么会有多个长尾服务,然后再调度产生多个任务交给多个长尾服务去执行

调度系统

作业调度是数据平台的执行的基石,所以数据平台必然有自己的调度系统
这个调度系统最好是专研或者是基于一种通用的调度系统进行改造

调度系统的本质是一个有序队列消费,可以实现的途径很多
主要的问题在于 外执行还是内执行
外执行的优点在于实现简单,缺点在于外执行中调度仅仅只是触发媒介,很难跟踪实际处理过程
内执行的优点在于准确感知作业结束与作业是否成功等,但内执行必然有存活感知,异常,HA等等
内执行的完整设计非常复杂,理论上一个内执行调度系统已经等价于一个分布式计算框架了

一个简化一点的做法是内外结合,或者说有特殊逻辑的外执行方案
内执行是指,所有的任务调度都是启动一个通用的应用程序.这个应用程序,接受启动任务执行SQL,用SQL来描述各种任务过程,并汇报执行结果,以此来完成各种复杂多变任务并得到任务执行结果
外执行是指,执行SQL的过程本质上不是在这个应用程序中,而是运行在YARN之类的集群,应用程序本身仅仅是任务中心概念

大数据平台的调度系统还必须具有

  • 用户隔离 用户调度使用的资源消耗有其上限
  • 任务隔离 任务的调度只能是定时调度,而不同任务的调度触发时间是不同(从秒级到月级不等)
    所以必然是需要区分不同的调度池来满足不同的任务调度要求
  • 随时触发
    数据平台的任务往往是链式的(ETL一环扣一环),调度任务可以不是链式的,但必须可以随时触发
    也就是可以执行计算层面的链式任务
  • 可干预
    任务的手动启动与重跑
    任务的中断(等待中断,执行中断)
  • 相应的告警策略
    诸如失败告警,超时告警等等

存储

数据存储,是数据平台的一个核心功能之一.而数据平台的存储必然是异构的
不同存储介质,数据的读取与写入速率的差别是非常大的,优缺点也各有不同,比如HDFS,HDFS(SSD),MySQL,MongoDB,Kafka(这里Kafka作为一种存储介质,即输出向)

所以在使用场景上,需要用的存储介质也完全不同,比如数据调度(冷,热,归档),或者对数据计算的时间有更高的要求等等,但仅仅是场景不同,或者说仅仅是介质不同,数据其实是同一份数据
同一份数据,在不同的介质之间迁移来迁移去,是数据平台非常正常也非常重要的功能,所以必然是需要在一种高纬层面对存储进行抽象

一个简单的设计是

  • 数据存储遵循库.表.列&块.分区结构
    库是表的分组或者说集合概念
    表是所有块的统一设置.比如列(Schema),分区(块分组),默认存储介质,调度策略等等
    分区是块级分区概念,基于性能考虑,原则上强制要求数据基于某个字段分区(或为空,基于创建时间)
  • 数据块
    数据块是数据平台数据操作的最小单位
    数据块有一个唯一ID
    数据块还标记该块如何使用(诸如存储介质,介质信息,文件格式,压缩等等.这里与Hive不同,Hive是存在于表上的,这里更加细化到数据块中,因为冷热调度之类很难以表为单位,而是以块为单位进行),这带来的问题是查询必须小心的控制查询范围(利用分区等),因为事实上是走多块加载Union,全表扫描性能极差,但在实际过程中,控制查询范围本身就是必要且必须的

MetaStore

元数据库是数据平台执行的依赖
从字面意义上说,元数据是描述数据的数据.在数据平台这个层面而言,个人理解可以稍微放大一点这个概念
数据平台元数据,是指为了让数据平台运行或者运行的更好,所需要的数据

元数据库,就是指存放所有元数据的仓库
元数据库可以用普通的RDBMS,例如MySQL完成
元数据库需要存放的数据非常多(所有数据平台运行)

  • 存储向
    存储结构 库.表.列&块,分区
    存储介质 存储类型,以及存储类型相关的信息(HDFS:HDFS头,路径,文件格式),JDBC:四元素,表等等
    存储统计 块:记录数,单条记录推测大小,创建时间,最近引用时间等等
    存储调度 默认存储介质,调度策略:调度时间,转移介质
  • 权限向
    用户管理(账户,登录),库.表.列.分区各级的读取与修改权限
  • 调度向
    任务生成:任务.步骤(详细执行过程:执行用户,执行SQL,推测数据量,推测资源耗用等)
    任务执行中:启动时间,任务终止等等
    任务依赖关系
    管理:用户的资源耗用上限,并行任务上限等等
  • 数据血缘
    ->,->表,->列`的依赖关系
  • 数据质量监控
    血缘->汇总计数
    通过列Schema要求的列格式以及补全策略完成的补全计数以及抛弃计数

应用层

数据权限

数据平台的本质是是提供数据服务,而数据权限又是数据服务中非常重要的一环

数据权限的落地是以应用程序用户两个维度进行组织

  • 数据的落地是应用程序,即应用.库,表.列&块
  • 用户权限是指是否可以读取&操作某个应用,某个库,某个表,某个列

数据权限的实现是架构在SQL化层面的
即在SQL的抽象语法树校验上最后加入一个权限判定
也就是在完成SQL解析之后,执行之前,对该SQL需要用到的库.表.列进行一次权限判定
如果判定失败即直接打回不允许执行,这样就可以实现对数据的保护

数据血缘

数据血缘是数据管理中非常重要的一环

  • 数据溯源 比如出现问题数据时
  • 数据热度 比如衡量是冷热等等的一个重要指标就是血缘依赖很多

数据血缘由两部分组成

  • 数据间的依赖血缘
    这部分的血缘产生是在SQL提交时编译检查部分完成(这样可以运行之前就能看见依赖)
    用以标记库->库,表->表,列->列的关系
  • 数据执行的依赖血缘
    这部分的血缘在运行时产生
    用以标记任务->块的依赖关系(块的元数据上标记标记一个TaskID)
    执行依赖血缘是用来做任务的幂等维持的

日志系统

数据质量分析

数据质量分析也是数据管理中的重要一环,质量分析是为执行监控
直白一点说,监控运行过程是否正常,有没有丢数据等等

数据质量分析的关键在于数据质量指标的搜集上
本质也是执行部分的统一信息搜集

  • 数据的进入计数和写出计数
  • 补全或异常计数

数据调度

冷热调度

冷热调度,是提升数据平台效率的重要一环
目的是为了变更存储介质,不同存储介质的性能是不一样的
HDFS与MongoDB的读取性能是不一样的
甚至不同HDFS的读取性能也是不一样的(比如专门搭建的SSD-HDFS)

冷热调度是就是切换数据的存储介质,将一些高热数据用更好的介质来存储
所以冷热调度的核心依赖是

  • 数据存储的高纬抽象 需要屏蔽掉不同介质带来的影响
  • 数据热度的区分方式:规则
    比如按时间划分,某个时间内热,某个时间之后冷,某个时间之后可以归档
    比如按使用量划分,当开始大量使用时从归档移出
  • 冷热调度的实现
    调度执行独立的数据迁移任务(备份方式迁移再移除,同时配合数据质量)

小文件合并

小文件合并视为一种特殊的数据调度

  • 自动扫描完成,且仅限HDFS介质,并且是满足小文件判定的块部分
  • 小文件合并是在相当长的时间之后才会产生
    因为小文件合并是破坏幂等依赖的行为
  • 小文件合并是一种特殊的作业行为
    读取-Union-写出 因为必然是有完全相同的Schema