2020.11.16大数据中的SQL组成原理
什么是SQL?
sql在分布式环境中,第一个想到的产品是hive
为什么hive出现?
元数据!在传统数据库的时候被隐藏了
把数据都存储到hdfs中,各个部门,各种类型的数据,以文本的形式存放的。会有很多目录和文件,做数据库的时候都希望人为干预的压缩,表常使用0和1来表示,如果要知道某某文件第某某列代表的是什么意思,外挂字典表来翻译0和1分别代表什么
面向数据的时候,数据存成模型/模式的特征,站在文件这个模式下,把数据以文件来存储,文件可以得到两类数据,data(打开文件看到的一大堆字符)和元数据(文件级别的,文件的大小,创建时间,归属,属主,权限…)。元数据交给了namenode,数据切割成块打散了交给了集群datenode。但是丢失了一批数据。也叫做元数据,是数据的元数据,data metadata,描述它有多少个列,每个列怎么分隔,多少个类型,代表什么意思。hdfs并没有能力来维护,也可以说成是这个数据的二级索引。(一级索引是找到这个数据,二级索引是找到这个数据的细节的数据)
无论是想成元数据还是二级索引,hdfs并没有帮你去维护。索引更强调定位找到那个数据,元数据大于索引可以包含索引的信息偏移量,还有描述体积、大小、种类、类型。需要人工的来维护。
实例:
在银行里工作,准备一个SVN,项目组很多又是在数据部门,数据是要支撑很多的项目组的,数据在所有项目中游来游去,在决策支持这块比如用户交易的流水会被很多的项目业务中频繁的调用,还有杂七杂八维度的几千张表。做了一件事情,很多项目组有自己的库,数据部门有数据中心的库,会要求所有人,将所有的库表,落成excel文件。项目部门的人员,只要打开SVN的目录,都会有按照项目组分的目录,按照项目各个维度会有很多的excel表格,当想去分析什么模型的时候,可能需要用户信息的年龄,存款,流水,需要某个人的工商信息,这些表可能来自不同的项目组,就先人工的找那些excel表格,每个sheet里面描述的是表的schema元数据,选中哪些列,再去维护一张新的表格来做映射,如果做开发的话,需要哪些表,查询哪些数据,总结出一个东西,多数90%以上的工作量是人肉来完成的。当一个需求下来,往往是要拿超出一周的时间来分析哪个数据是来自哪个业务的,哪个项目组的先找库。再去走ETL流程,把数据汇聚过来之后,再由这里的数据库平台做数据分析,产生结果给数仓或下游的库表里去。
如果第一步解决了知道要找哪些数据,数据源定了,要回到文件模型,读取哪些目录的哪些文件,这两件事情加起来,通过读取文件,根据元数据描述做切割,选出一批需要的数据,整个事情是由人参与完成的。工作量的复杂程度是比较高的,虽然大部分是体力劳动。取决于元数据的管理和对数据模型的定位。
人是懒惰的,懒惰促进科技的进步。软件工程学,有一种统一接口,统一的定义来抽象出一种层次来应付未来所有用户对不同数据的不同行为,因为这些行为一定有一个特征,抽象成table表这种形式,是对原始复杂操作的包装,SQL领域发展的意义
除了文件模型如果能用另外一种形式展示,table模型,相同的数据除了放在一个文件里,还可以放在一个table,维护一个table,表格首先有schema字段的定义,文件数据的元数据就在schema里(name,age,size,多大,什么类型),另外一个是所有的行row数据,表的模式schema+row,不考虑表与表之间的关系(关系型数据库),只考虑table结构化方式来存储数据。可以附加一个东西作用在上面而不是肉体劳动,sql而不是肉体劳动(文件模型只能读写read/write)。
table是虚的,用dir来抽象这件事情,数据会在location文件位置,schema和location都算元数据,dir也是文件,只能read/write。可以理解成在文件read/write模式下,向上又包装了一些东西,包装的东西是为了让人的使用趋向于简单,从底层read/write的原子操作,扩展到复杂操作
写的sql也是文本,最终可以完成一个复杂的过程,既读了这个文件,又完成了整合、过滤、计算等一系列查询,但本质是文本,C java本质也是文本,牵扯到编译器和解释器,是编译执行还是解释执行。SQL是个文本字符串,最终要交给执行引擎。(语法解析→最终的物理执行)
举一个例子:
用户写了一条SQL语句,
select name,count(*) as cc from ooxx where age>30 group by name
首先会认为这个sql语句是一个文本字符串,由人肉来完成的时候:
1.from ooxx : 必须先判定是否有这张表
源于曾经有没有触发过DDL(create table创建过这张表),ooxx只是字符串,内存中有没有定义过ooxx,要找DDL定义的元数据,
把SQL分了4类语句:DDL(数据定义语言,在hive中DDL极其复杂)、DML(load)、DCL(权限管理)、DQL(查询语句)
如果hive将SQL转化成MapReduce程序,如果想执行MapReduce,要给定哪些参数?
hadoop-jar class文件 jar包 inputPath(未来sql如果执行的话,ooxx定义的时候给的location,hive建表时要分为内表,管理在统一目录下,warehouse,外表给出目录位置在哪,dir到文件映射的过程。如果没有这个元数据,第一步启动的时候就会报错,没有数据来源) outputPath
2. where age > 30 :过滤
MapReduce跑起来,第一个任务是MapTask,之后才是ReduceTask,是线性的关系。
filter过滤是单记录的行为,过滤一条的时候是不考虑其他记录的,非相干计算。age>30发生在map阶段,但是,虽然知道文件在哪了,还少了一步,这个inputPath定义的location只是个目录,里面的文件格式是什么格式的(文本文件,csv文件,json文件),每种文件读法是不一样的。
条件反射:文件格式是由inputFormat输入格式化类来决定的,有两个知识点:1.可以知道分区的切片,2.可以得到RecordReader,如果将不同的文件格式变成一条条记录
在定义的时候除了给出location位置,还可以定义存储类型asTextFile存成文本文件,csv文件,DDL表的定义语句和过程很多是为了支持后续计算的参数和行为的。inputformat换成具体的哪个实现类,会影响到后续的计算。元数据的重要性。
还有一件事情,age是这一行的哪个列,哪些位置,哪笔数据,又要和DDL关联起来,因为在DDL定义表的时候,都要给出字段按顺序逗号分隔,且要跟上它的类型,在hive中还刻意给出了row format delimited,fields terminated by字段分隔符。
location,存储类型,数据分割,列顺序,列的类型,都是在使用DDL建表语句得到的列的元数据
3. group by + UDF 函数
相同的key为一组,这一组数据调用一次函数,reduce函数对这一组数据进行迭代计算:
基于key做分区计算换组的过程,group by 后面拿什么做key,基于框架走shuffle,相同的汇聚在一起。UDF是什么计算行为是在reduce端发生的
4. select …
在输出环节触发select
hive的架构和角色
为了完成把sql转换成MR或者Spark计算引擎,在物理进程划分了如下几种角色:
1.metastore 元数据存储
也是一个JVM进程,自己不存元数据,只是对外暴露查询接口,把元数据存在更可靠的地方,数据库db里,生产环境中会使用MySQL来承载真正元数据的持久化过程。
2.driver
未来要解决sql的问题,sql是一个文本,要交给driver,driver会收到用户的sql,拿着sql走上面的流程,driver会调用资源层(yarn)来产生mapReduce(推送一个mapReduce程序的提交)的过程,driver起到了中间的环节,driver也是一个JVM
driver和metastore之间有一个基于元数据沟通的过程
3.hiveserver2
用户的sql到达driver的过程
1.已经被淘汰的hive cli command line interface 命令行接口
约束:必须要登录到这台机器启动它
2.hiveserver2
hiveserver只能支持一个用户,hiveserver2支持多用户连接,对外暴露jdbc的连接,thrift协议的通信,需要客户端启动beeline,用户把sql交给了beeline,走的是jdbc on thrift的形式,sql就可以到达hiveserver2,hiveserver2里面带着driver
如果公司有500T的数据,开始成立了一个部门做了一个基于hive的数仓,把500T的数据以文件的形式存在了hdfs,且在hive里加了一个元数据的映射包装了一下,建出了5000张表,元数据已经对这一批文件有了管理了,这时候出现了Impala、spark、flink任何的其他的计算框架如果也想对这批数据操作,也想以table这种结构化的方式来操纵这批数据的话,这时候是需要造轮子各自再去创建metastore么?可以,但就这一批数据,再怎么抽象,table应该长得一摸一样。还不如整间公司所有项目组不同的技术,所有的功能使用一个元数据!!
hive中最值钱的是metastore,如果hive中的metastore能既提供给自己的driver使用,也能提供给spark的driver使用,这事就完美了,只要维护一份元数据,大家都能看到相同的元数据,剩下的事情就是driver上的sql怎么解析了。
hive on spark:
基于driver的两端,一端是sql解析,一端是物理执行的计算框架。MapReduce最大的特征就是慢!!能不能把它换成其他的计算框架,能!API级别的适配的过程,只需要在driver里面有一个基于api的适配,可以适配任何的计算框架,只要sql解析适配就可以了,就能换底层计算框架了。但是有个小瑕疵,如果spark只有RDD,那么暴露的api趋向于固定的,只有RDD的api,如果spark有野心,可以在sql文本解析的时候,可以根据不同的sql再做一次优化,拿着计算特征,是不是要触发钨丝计划,使用堆内内存,堆外内存,只用api很难适配的。
shark 过渡阶段
暴露出一个问题,spark被研发出来的时候,出现了一个词,叫做RDD,最后一个D是dataSet,但是模仿的是Scala里的collection,集合的函数,是比较low level的,偏于技术原生,这时候,RDD不是非常的向上适配sql,因为sql里没有flatMap,只有groupBy,适配比较远。
spark on hive:
spark学习到了sql向编程模型转化中间确实的知识点,分析完了hive的所有过程,(这个能力的老大是微软,曾经图形界面和鼠标是施乐,乔布斯参观的时候看到了,找了比尔盖茨微软做了苹果的外包公司做图形界面,微软发布了windows),出现了dataFrame或dataSet,不是说low level就是错误,是万能的,能完成任何的编程需求,如果编程语言给你提供非常底层、原生的操作的接口的话,只要有能力能够开发出任何产品。但是low level代表成本很高,效率很低,优化策略很难实现,因为未来组合是未知的。所以一定是趋向于high level,这时候出现了真正的DataSet,摒弃了一些底层的算子,比如原理有10个算子,现在只剩8~6个了,远低于RDD里算子的数量了,但是够用了。
一个软件底层的接口可以变化,但是对用户的接口是变化最少的,公司里元数据是趋向于稳定的,公司就这批数据,所以在hive当中,HQL是趋向于稳定的(metastore是趋向于稳定的,分区表,分桶表,所有那些定义关键词DDL是趋向于稳定的)。这个时候spark重写了hive的driver,顺从了metastore的调用,结合了自己内部高阶api的研发,整体充分利用内存。spark自己做主了,driver解析、sql解析,spark自己做了,但是自己没必要再研发一个存储层,就可以复用hive的存储层,所有现在只剩下hive on spark (用的不多)和 spark on hive 了
这个时候想学spark-sql的话,已经非常灵活了,是一个灵活的小胖子,比刚才得出的结论再稍微的灵活一点点
面向元数据这块,有三种形式:
1.可以是临时的,在一个application生命周期里,所有的表,所有的东西没有固化元数据的过程,不需要持久化
2.on hive可以自主的启动一个metastore集成到进程里去,不污染数仓,又可以持久化存储,别人查不到,你也查不到别人的
3. on hive可以完全基于公司整合的,只需要把一个metastore地址给它,它自己的driver和meta store接口进行通信,整个公司的所有元数据是可见可看的
spark有一个产品catalog 编目、目录
类似于metastore起解耦的作用,维护元数据信息,也可以维护对别人元数据的引用,只要接口调通就可以了,站在spark这里就分层解耦了,全都面向catalog去获取元数据。
后面还会学一个cloudera公司开发的用C语言写的impala(小众的,内存计算速度快),实现的内存计算更偏流式计算,也是on hive,里面也有一个东西叫做catalog,神似。
平台化的时候要搞定一个技术kylin,整合技术使用的。最终结果是以存储换时间,完成快速的sql查询。不止占用磁盘,还有hbase的内存,做了N个笛卡尔积的结果,如果有关系型的需求是走它,如果没有关系型,数量很大,复杂度又比较多可以走ES。