关于这些年以来学的大数据技术的一些简单的总结
一.关于大数据
1. 什么是大数据??
答:大数据讲的是无法在一定时间内用常规软件工具进行捕捉,管理和处理的数据集合.是需要新的处理模式才能具有更强的决策力,洞察力,洞察发现力和流程优化能力的海量,高增长率和多样化的信息资产;主要解决-->海量的数据存储的分析和计算问题.
大数据的特性:
- 数据量庞大主要是PB级别->EB级别-->ZB级别;
- 高速性:数据输入输出的速度要求快
- 多样性:多样性让数据分为结构化数据和非结构化数据.非结构化数据包括网络日志,音频,视频,图片,地理位置等等
- 价值性:价值密度低,商业价值高
应用场景:大数据无处不在,大数据应用于各个行业,包括金融、汽车、餐饮、电信、能源、体能和娱乐等在内的社会各行各业都已经融入了大数据的印迹。
制造业,利用工业大数据提升制造业水平,包括产品故障诊断与预测、分析工艺流程、改进生产工艺,优化生产过程能耗、工业供应链分析与优化、生产计划与排程。
金融行业:大数据在高频交易、社交情绪分析和信贷风险分析三大金融创新领域发挥重大作用。
汽车行业:利用大数据和物联网技术的无人驾驶汽车,在不远的未来将走入我们的日常生活。
互联网行业:借助于大数据技术,可以分析客户行为,进行商品推荐和针对性广告投放。
电信行业:利用大数据技术实现客户离网分析,及时掌握客户离网倾向,出台客户挽留措施。
能源行业:随着智能电网的发展,电力公司可以掌握海量的用户用电信息,利用大数据技术分析用户用电模式,可以改进电网运行,合理设计电力需求响应系统,确保电网运行安全。
物流行业:利用大数据优化物流网络,提高物流效率,降低物流成本。
城市管理:可以利用大数据实现智能交通、环保监测、城市规划和智能安防。
生物医学:大数据可以帮助我们实现流行病预测、智慧医疗、健康管理,同时还可以帮助我们解读DNA,了解更多的生命奥秘。
体育娱乐:大数据可以帮助我们训练球队,决定投拍哪种题财的影视作品,以及预测比赛结果。
安全领域:政府可以利用大数据技术构建起强大的国家安全保障体系,企业可以利用大数据抵御网络攻击,警察可以借助大数据来预防犯罪。
个人生活:大数据还可以应用于个人生活,利用与每个人相关联的“个人大数据”,分析个人生活行为习惯,为其提供更加周到的个性化服务。
大数据的价值,远远不止于此,大数据对各行各业的渗透,大大推动了社会生产和生活,未来必将产生重大而深远的影响。
具体流程:
答题要点:无法在一定时间内用常规软件工具进行捕捉,管理和处理的数据集合;海量的数据存储的分析和计算;数据量庞大;高速性;多样性;价值性:价值密度低,商业价值高
二.关于nginx
1、什么是Nginx?
Nginx是一个高性能的HTTP和反向代理服务器,及电子邮件(IMAP/POP3)代理服务器,同时也是一个非常高效的反向代理、负载平衡。
多进程异步非阻塞事件处理机制:运用了epoll模型
2、为什么要用Nginx?
优点: 跨平台、配置简单 非阻塞、高并发连接:处理2-3万并发连接数,官方监测能支持5万并发 内存消耗小:开启10个nginx才占150M内存,Nginx采取了分阶段资源分配技术 nginx处理静态文件好,耗费内存少 内置的健康检查功能:如果有一个服务器宕机,会做一个健康检查,再发送的请求就不会发送到宕机的服务器了。重新将请求提交到其他的节点上。 节省宽带:支持GZIP压缩,可以添加浏览器本地缓存 稳定性高:宕机的概率非常小 master/worker结构:一个master进程,生成一个或者多个worker进程 接收用户请求是异步的:浏览器将请求发送到nginx服务器,它先将用户请求全部接收下来,再一次性发送给后端web服务器,极大减轻了web服务器的压力 一边接收web服务器的返回数据,一边发送给浏览器客户端 网络依赖性比较低,只要ping通就可以负载均衡 可以有多台nginx服务器 事件驱动:通信机制采用epoll模型
3、为什么Nginx性能这么高?
得益于它的事件处理机制: 异步非阻塞事件处理机制:运用了epoll模型,提供了一个队列,排队解决
4.Nginx与Apache的区别?
Apache: 创建多个进程或线程,而每个进程或线程都会为其分配cpu和内存(线程要比进程小的多,所以worker支持比perfork高的并发),并发过大会榨干服务器资源。
Nginx: 采用单线程来异步非阻塞处理请求(管理员可以配置Nginx主进程的工作进程的数量)(epoll),不会为每个请求分配cpu和内存资源,节省了大量资源,同时也减少了大量的CPU的上下文切换。所以才使得Nginx支持更高的并发。
5、Nginx是如何处理一个请求的呢?
首先,nginx在启动时,会解析配置文件,得到需要监听的端口与ip地址,然后在nginx的master进程里面
先初始化好这个监控的socket(创建socket,设置addrreuse等选项,绑定到指定的ip地址端口,再listen)
然后再fork(一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程 )出多个子进程出来,然后子进程会竞争accept新的连接。此时,客户端就可以向nginx发起连接了。当客户端与nginx进行三次握手,与nginx建立好一个连接后此时,某一个子进程会accept成功,得到这个建立好的连接的socket,然后创建nginx对连接的封装,即ngx_connection_t结构体.接着,设置读写事件处理函数并添加读写事件来与客户端进行数据的交换。最后,nginx或客户端来主动关掉连接,到此,一个连接就寿终正寝了首先,nginx在启动时,会解析配置文件,得到需要监听的端口与ip地址,然后在nginx的master进程里面.先初始化好这个监控的socket,再进行listen,然后再fork出多个子进程出来, 子进程会竞争accept新的连接。
6、正向代理
一个位于客户端和原始服务器(origin server)之间的服务器,为了从原始服务器取得内容,客户端向代理发送一个请求并指定目标(原始服务器),然后代理向原始服务器转交请求并将获得的内容返回给客户端。客户端才能使用正向代理.正向代理总结就一句话:代理端代理的是客户端
7、反向代理
反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求,发给内部网络上的服务器.并将从服务器上得到的结果返回给internet上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器 反向代理总结就一句话:代理端代理的是服务端
8、动态资源、静态资源分离
动态资源、静态资源分离是让动态网站里的动态网页根据一定规则把不变的资源和经常变的资源区分开来,动静资源做好了拆分以后,我们就可以根据静态资源的特点将其做缓存操作,这就是网站静态化处理的核心思路 动态资源、静态资源分离简单的概括是:动态文件与静态文件的分离
9、为什么要做动、静分离?
在我们的软件开发中,有些请求是需要后台处理的(如:.jsp,.do等等),有些请求是不需要经过后台处理的(如:css、html、jpg、js等等文件) 这些不需要经过后台处理的文件称为静态文件,否则动态文件。因此我们后台处理忽略静态文件。这会有人又说那我后台忽略静态文件不就完了吗 当然这是可以的,但是这样后台的请求次数就明显增多了。在我们对资源的响应速度有要求的时候,我们应该使用这种动静分离的策略去解决 动、静分离将网站静态资源(HTML,JavaScript,CSS,img等文件)与后台应用分开部署,提高用户访问静态代码的速度,降低对后台应用访问 这里我们将静态资源放到nginx中,动态资源转发到tomcat服务器中
10、负载均衡
负载均衡即是代理服务器将接收的请求均衡的分发到各服务器中 负载均衡主要解决网络拥塞问题,提高服务器响应速度,服务就近提供,达到更好的访问质量,减少后台服务器大并发压力
三,关于hadoop
1. 谈谈你对hadoop的理解
Hadoop是Apache开源的一个处理大文件的系统,主要有三大核心件:HDFS;MapReduce;YARN它们的依据来源于谷歌的三大论文GFS----HDFS;MapReduce---MapReduce;BigTable----HBase它的模型主要有:Hadoop Common:基础型模块。RPC调用,Socket通信;Hadoop Distributed File System 分布式文件系统,用于存储大数据的信息;Hadoop YARN 资源协调框架;Hadoop MapReduce 大数据计算框架;Hadoop Ozone: 对象存储框架;Hadoop Submarine: 机器学习引擎
答题要点:他是什么,它的组成,它的作用
2.谈谈你对HDFS的理解
HDFS是分布式文件系统,它是一个基于硬盘之上的文件管理工具;可以实现和硬盘解耦;HDFS是MapReduce计算的基础;数据都是以字节数组的方式存放在硬盘上的;数据比较安全,会将数据备份多分;
在HDFS一旦文件被存储,那么就不能被修改.为什么这么说呢?因为修改会影响偏移量,会导致数据倾斜,会导致一系列的蝴蝶效益
有两个主要的节点:namenode和DataNode
元数据的信息:文件的描述信息-->名称,大小,权限,创建时间
HDFS主要有三个主要的核心:
- block:数据被切分后的一部分,默认大小是128M,拥有自己的元数据信息-->属于哪个文件,偏移量是多少,大小是多少;在上传时块的大小和备份数可以设置
- namenode:接收hfds客户端对数据的请求,管理分布式文件系统的文件信息(包括分布式文件目录,管理文件目录与文件的对应关系,管理文件与块映射关系);启动时与DataNode保持心跳,收集DataNode汇报的自身存储的block信息;启动后每三秒确定DataNode是否存活,如果失联超过十分钟,namenode会将block拷贝到其他节点上。
Namenode在启动之后会先进入安全模式,如果DataNode丢失的block达到一定比例,则系统会一直处于安全模式状态也就是只读状态;可以通过设置dfs.safemode.threshold.pct(缺省值0.999f)表示HDFS启动的时候,如果DataNode上报的block个数达到了元数据记录block个数的0.999倍才可以离开安全模式,否则一直是只读模式。
数据存储完全基于内存有明显的的优点:那就是计算速度快;缺点是掉电易失
- DataNode:直接与客户端交互数据,存储真实的数据文件,可以通过元数据信息校验数据块是否有损坏;与namenode保持心跳;启动时验证块的完整性并且向namenode汇报自己存储块的信息;启动后每隔三秒向namenode发送心跳,证明自己的存在
数据存储介质完全基于硬盘,数据的写入和写出速度慢
- secondarynamenode:主要是为了解决namenode的掉电易失问题-->存日志和生成快照
3.持久化流程
当集群运行过程中执行的很多操作都会被记录到edits文件中.
fsimage对应着当前系统镜像:
(1) 开机:当启动集群时namenode会将当前(上次关机时)的fsimage与最新的日志进行合并产生新的fsimage
(2) 关机:直接关机即可
(3) 当达到阈值时(fs.checkpoint.size 默认64M;fs.checkpoint.period 默认3600秒)secondarynamenode会将namenode的fsimage与edits文件拷贝到seconamenode主机上,然后进行合并,然后生成fsimage.ckpt,然后将其拷贝到namenode上,检查文件的完整性,修改fsimage.ckpt的名字为正确的名字;这样就解决了启动时间过长和异常关机的问题.
4.谈谈你对yarn的理解
Yarn是hadoop的集群资源管理框架,在hadoop2被引入,具有足够的通用性,同样也支持其他的分布式计算模式
Yarn的基本思想就是将jobtracker的两大主要职能:资源管理,作业的调度监控分为两个独立的进程.一个是全局的resourcemanager,另一个是每一个应用对应的applicationmaster
Resourcemanager是一个纯粹的调度器,它根据应用程序的资源请求严格限制系统的可用资源.在保证容量,公平性以及服务器等级的前提下,优化集群资源利用率,即让所有的资源都能被充分利用;主要作用:处理客户端请求;启动或监控ApplicationMaster;监控NodeManager;资源的分配与调度
ApplicationMaster负责与resourcemanager协商资源,并和namemanager进行协同工作来执行容器和监控容器的状态;主要作用:负责数据的切分;为应用程序申请资源并分配给内部的任务;任务的监控与容错
Nodemanager是yarn节点上的工作进程,管理集群中独立的计算节点.其职责包括启动应用程序的容器,监控他们的资源使用情况,并且汇报给resourcemanager;主要作用:管理单个节点上的资源;处理来自ResourceManager的命令;处理来自ApplicationMaster的命令
Container 是 YARN 中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等,当AM向RM申请资源时,RM为AM返回的资源便是用Container表示的。YARN会为每个任务分配一个Container,且该任务只能使用该Container中描述的资源。
总的来说,Container有以下作用:对任务运行环境进行抽象,封装CPU、内存等多维度的资源以及环境变量、启动命令等任务运行相关的信息
要使用一个 YARN 集群,首先需要一个包含应用程序的客户的请求。ResourceManager 协商一个容器的必要资源,启动一个 ApplicationMaster 来表示已提交的应用程序。通过使用一个资源请求协议,ApplicationMaster 协商每个节点上供应用程序使用的资源容器。执行应用程序时,ApplicationMaster 监视容器直到完成。当应用程序完成时,ApplicationMaster 从 ResourceManager 注销其容器,执行周期就完成了。
5. 谈谈hadoop写入文件的流程
客户端发送create请求到HDFS-->HDFS接收到请求通过PRC调用namenode.create方法-->namenode检查文件路径是否存在,是否有足够的操作权限(失败,抛出异常给DFS;成功在namenode上创建一个空的entry对象,给DFS返回成功信息)-->DFS接收到成功信息后,为客户端创建一个FSDataOutPutStream对象-->客户端用FSDataOutPutStream开始上传第一个快-->向namenode请求当前block的存放位置,namenode根据文件的副本数和机架感知策略,选择对应副本数量的节点;客户端开始和三个DataNode创建socket通讯.
该模式称之为管道:可以很好的解决IO阻塞问题;客户端开始读取要上传的文件到自己的内存中,并且在内存中构建缓冲区buffered(减少物理IO);
发送数据的级别为packet(默认大小64K);客户端从缓存中取出一个packet,从client通过FSDataOutPutStream传输给第一个节点,并设置一个ACK状态,该节点接收完继续传递给下一个节点.
最后一个节点接收完毕后开始返回响应状态,前一个节点接收到响应状态后继续向前发送直到第一个节点,最终client接收到响应转台说明当前片传输完成,重复执行packet的操作,直到整个快传输完成,告知DFS当前块传输完成;DFS通过RPC调用将当前块完成的信息传递给NN,NN将Entry中加入当前块的位置信息继续按照以上的流程传递剩余的块;当整个文件都上传文成,客户端关闭FSDataOutPutStream
这里需要讲一下pipeline管道:正向传输数据,逆向传递响应;将chunk和checknum都封装到packet中;当packet装满之后,将其放在dataqueue队列中等待发送;DataStreamer从dataqueue里面按照顺序依次取出packet;将要发送的packet放入到ackqueue里面然后才开始发送,每一个DataNode接收到数据之后都会进行校验:如果完整继续向后传递,如果不完整返回false状态;返回给客户端,其接到返回状态之后会去ackqueue查找回应的packet;将packet之后的数据重新挂载到dataqueue将会被重新发送
当发送数据时,加入DataNode挂掉,会向namenode汇报节点失效,namenode会记录下备份失衡.DFS会认为传输时只要有一个节点有完整数据,那么这个数据就是完整的
6. 谈谈HDFS怎样读取数据
首先客户端将请求发送给DFS,DFS通过RPC调用namenode的open方法,namenode会去检查该目录是否存在,是否有读的权限,成功之后,DFS会创建输入流FSDataInPutStream,从namenode获取块的datanode信息,然后直接从DataNode上读取数据即可,优先选择同机架不繁忙的节点,把block读取到客户端后,最终合并成一个大文件.
7. hadoop1.X和hadoop2.X的区别
(1) 没有了namenode节点,有activenamenode完全代替了namenode的功能;
(2) 增加了standbynamenode:备用namenode,删除了secondarynamenode,其功能完全由standbynamenode代替;
(3) 如果主节点挂掉,切换到standbynamenode节点上,该节点上的数据与主节点上的数据完全一致;
(4) 新增Journalnode:帮助我们拉取或者存放日志文件,简单地说就是当activenamenode生成edits的时候,拉取一份到journalnode上,standbynamenode会从journalnode集群上,获取到最新的日志文件,进行重做;
(5) 引入zookeeper协助管理主备切换
(6) DataNode功能一直没变.
(7) Hadoop2.X新增了联邦机制:使用命名空间划分namenode作用的范围;当然具体的数据还是放在DataNode上
(8) 联邦机制有个缺点:因为命名空间是相互独立的,所以当一个那么浓的挂掉后,其他命名空间是不会进行任何管理的,也就是说存在单点故障问题,故也要实现高可用;
四. 关于MapReduce
1. 浅谈MapReduce的流程
(1) map流程
这里就要说block,一个block大小默认是128M;再说的是split,它是map任务要梳理的数据的大小,默认等于block的大小;block过小会导致task的个数过多,过大会导致数据倾斜;每一个split对应着一个maptask读取的数据默认是一行;maptask对数据进行计算,分析,然后把临时结果放入到一个叫kvbuffer的环形缓冲区中,它的大小默认是100M,当达到其阈值80%时就会进行溢写,如果文件足够大,那么会溢写出很多的小文件,大概是80M左右;接下来说一下分区,分区数和reduce的数量完全相同,在溢写的时候会提前计算出key所对应的分区reduce;进行排序,先按照分区排序,再按照key进行快排;将溢写产生的多个小文件合并成一个大文件(这里的大文件是相对于前面的小文件来说的),先按照分区,再按照key进行归并排序;
(2) Reduce流程
先fetch,也就是从maptask上拉取reduce需要计算的数据;再按照key进行归并排序;我们必须将key相同的临时数据拉取到同一个reducetask中进行计算;最后经过output输出到HDFS上.
2. 看过MapReduce的源码吗??
简单的了解了一下:提交任务需要一个JOB主类,通过单例创建一个job类设置运行参数,此时job只有两种状态:defing和running,是用枚举定义的;先确定job的状态,再设置使用API的版本,创建集群对象,创建任务提交器;启用多线程正式提交任务,然后切换job运行状态;在提交任务之前,会作好切片(writeNewSplits)和设置好maptask的数量;在做切片的时候先获取到要处理的文件路径,确定切片的大小,获得第一个切片后,会记录下切片的偏移量,重新设置文件的大小(块的大小减去这个切片的大小),再判断一下最后一个切片的大小,一般不超过切片的1.1倍就不用再切割了,将这些切片放入集合中并返回;得到行记录读取器,创建收集器时会进行初始化,获取分区数量以及溢写的指数,设置环形数据缓冲区,防止出现负数,对其进行哈希取值再取余。读取数据时,每次向下多读一行,以防止数据被切割,除了最后一行。溢写时设置守护线程(是个服务线程,准确地来说就是服务其他的线程);reduce端,获得原生的keyvalue迭代器,创建拉取器,如果是本地文件就开启一个拉取器,如果是远端就开启5个拉取器,获取比较器,如果没有设置分组比较器,那么获取key比较器,若没有key比较器使用key类型自带的比较器;若果上面所有的比较器都没有则使用LongWritable.class。比较的时候会先判断key是否为本段的第一个,以及下一个key是否存在,并比较当前key和下一个key是否一样,如果相同返回false。也就是相同key只会写出一次。
五.关于HBase
1. 谈谈你对hbase的理解
Hbase是一个面向列的、开源的数据库。完全依赖于HDFS,用于存储数据,适合存储半结构化或者非结构化的数据。它是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用hbase可以在廉价的PCserver上搭建起大规模结构化存储集群。可伸缩性主要体现在基于HDFS,可以在保证数据安全的前提下完成存储的扩容。需要四个维度才能定位到数据,分别是RowKey(类似于关系型数据库的id,用来唯一标明对应列族的数据,一般占用64k的数据长度,按照字典序排序)、Timestamp(数据的版本,不同的列族可以有不同的事件版本)、Column Familly(有相同意义的集合体,一般设计不超过3列族)、Qualifer(列族中的一个属性)。所有存储在hbase上的数据都是无数据类型的,统一为字节数组。采用MapReduce处理数据。
2. 了解hbase架构吗??
连接hbase有多种方式如:shell、java、MapReduce等等。创建表时,我们会将表的信息存放在zookeeper中,主要是因为:防止HMaster节点故障,丢失数据;主从master共享数据;更快的访问数据;
HMaster接收客户端的DDL请求,并监控HRegionServer,了解其当前节点状态,接收到请求后,会选择一个空闲的节点执行表的创建。如果发现HRegionServer挂掉,会将其上的region切换到其他的HRegionServer上;
HRegionServer主要作用是负责管理当前节点的region,它上面可能有多个region,监控region的大小,达到阈值(10G)进行相对等分(保证数据完整为前提),新分的region会交给另外的HRegionServer维护,负责维护与客户端的IO请求;
HLog(WAL日志)隶属于HRegionServer,HRegionServer中所有的HRegion共享这个HLog;当达到阈值(内存的占比日志的条数)时,先写日志,然后将mem中的数据写到Storefile;
HRegion:初适一张表对应一个Region,后面有可能一张表对应多个region;
Store:多个store组成region;一个store对应一个列族;一个store由memstore和Storefile组成;一个store只有一个memstore,可以有多个Storefile;
Memstore:基于内存的数据存储;新增数据时先写入日志,再写入内存,提高数据插入速度;
Storefile:将memstore中的数据写到HDFS上,Storefile达到一定数量会进行合并,客户端进行数据查询时,优先查找memstore,然后才去Storefile中找。
3. hbase的热点问题是怎样产生的??怎样解决??
热点问题是这样产生的:检索hbase的记录首先要通过rowkey来定位数据行。当大量的client访问hbase集群的一个或少数个节点,造成少数regionserver的读/写请求过多、负载过大,而其他regionserver负载却很小,就造成了“热点”现象。
解决办法:rowkey设计是热点的源头,region有二个重要的属性:startkey与endkey表示这个region维护的rowkey范围,当我们要读/写数据时,如果rowkey落在某个start-endkey范围内,那么就会定位到目标region并且读/写到相关的数据。正常情况下,创建一张表时只有1个region,start-endkey没有边界,所有的数据都在这个region里放着,但是当数据越来越多,region的size越来越大时,达到阈值(10G)时,hbase认为再在里面放数据已经不合适了,就会找到midkey将region一分为二,称之为分裂而midkey则是这两个热功能的临界点。假设rowkey小于midkey数据放到1区中,反之放到2区中。随着数据的增大,数据往往会放到2区里,会一直这样持续下去,从而导致集群的资源得不到很好的利用。
4. 数据倾斜怎样产生的??怎样解决??
数据倾斜:Hbase可以被划分为多个Region,但是默认创建时只有一个Region分布在集群的一个节点上,数据一开始时都集中在这个Region,也就是集中在这一个节点上,就算region存储达到临界值时被划分,数据也是存储在少数节点上。这就是数据倾斜。
解决办法:(1)设置预分区:让表的数据可以均衡的分散在集群上;(2)加盐:在rowkey的前面增加随机数,具体就是给rowkey分配一个随机前缀以使得它和之前的rowkey的开头不同,这样rowkey就会分散到各个region上,以避免热点;(3)哈希:哈希会使同一行永远用一个前缀加盐。哈希也可以使负载分散到整个集群,但是读却是可以预测的。使用确定的哈希可以让客户端重构完整的rowkey,可以使用get操作准确获取某一个行数据;(4)反转:反转固定长度或者数字格式的rowkey,这样可以有效的随机rowkey,但是牺牲了rowkey的有序性;(5)时间戳反转:rowkey=哈希(主键<递增的id\手机号码等>)+Long.Max_Value - timestamp。
5. 谈谈hbase的优化
Hbase的优化主要从以下这几方面考虑:
(1)设置预分区:建表时设置预分区防止前期数据集中到一个regionserver上;(2)rowkey的设置:任意字符,最大长度64KB,一般设置为10~100bytes,主要防止出现rowkey冗余,rowkey是按照字典序排列的,rowkey设置的越短越好;(3)列族设置,不要在一张表中涉及过多的列族,因为一个store对应着一个列族,当memstore溢写时,会触发临近的列族进行溢写,若列族过多会导致IO数量庞大,如果我们按照rowkey查询数据时会把所有的列族的数据查询出来会导致读取store文件数过多;(4)在regionserver中有一片共享区域称之为memory,建立表时可以将其放入到memory中,增加缓存命中率;(5)数据文件的合并与拆分:合并文件可以大大提高查询数据的效率;数据文件随着数据的增加而变大,拆分可以减少HRegionServer的压力,提高查询效率,当然这些都在Storefile转换成Hfile过程中做的,也就是写文件到HDFS上时;(6)可以打开多个表链接增加写入速度,可以用事务完成所有数据操作,对不重要的数据可以不写入日志,批量插入数据或者多线程批量插入数据(htable属于线程不安全,需要创建多个htable连接才能使用多线程);(7)多客户端读取数据,使用池创建多个htable,设置scan缓存,批量读取数据,多线程批量读取数据,(Blockcache * 1+memstore * n < heapsize * 0.8,如果要求响应速度,就要增大Blockcache,如果要求写入速度,需要增大memstore)
Hbase中常见的过滤器有:KeyOnlyFilter、FirstKeyOnlyFilter、MultipleColumnPrefixFilter、ColumnCountGetFilter、ColumnPaginationFilter、InclusiveStopFilter。
过滤器:用来提高数据处理的效率,用户可以通过内置或自定义的过滤器来对数据进行过滤,所有的过滤器都在服务端生效,即谓词下推,减轻网络传输和客户端处理的压力。
主要分为三大类:比较过滤器、专用过滤器和包装过滤器;
比较过滤器:RowFilter、Family Filter、QualifierFilter、ValueFilter;
专用过滤器:setFilterIfMissing、setlatestversiononly、PrefixFilter、ColumnPrefixFilter、PageFilter、TimeStampsFilter;
包装过滤器:whilematchfilter。
6. 行转列和列转行
https://blog.csdn.net/qq_15973399/article/details/89281778
六.关于hive
1、了解hive吗??
Hive是一个基于hadoop的数据仓库工具,可以将结构化的数据文件映射成一张表,并提供简单的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行;主要进行OLAP操作,也就是通过历史的数据分析,对现在的业务挥着发展提供数据的支持;常见的模式有星型模型和雪花模型;
架构主要有:client(包括命令行、JDBC、ODBC模式以及webUI),metastore(元数据信息等等),驱动Driver(解析器《将SQL语句解析成语法树》、编译器《将语法树转成逻辑执行计划》、优化器《优化执行计划》、执行器《将逻辑计划转换成物理计划》);
Hive的数据类型也分为基本类型和复合类型,复合类型中多了一个struct类型;
内部表和外部表:内部表一般处理自己独享的数据,删除表时,数据文件会被跟着删除,外部表可以和别的表共享数据,删除表时,不会删除数据文件;
对表进行查询时,默认查询这个表下的所有文件,设置分区主要目的是减少每次文件的扫描范围,分为静态分区和动态分区;动态分区可以自动识别分区,插入数据时会动态的创建分区文件夹;
Hive数据分桶:为了提升我们查询数据的速度,经常被查询的列或者散列比较好的列进行分桶。
常见的数据存储格式:textfile、sequencefile、orc、rcfile、parquet、avro、json、自定义格式。如何选择数据格式:如果只读取部分列,考虑orc或者parquet,hive用orc,spark用parquet,需要读取多行使用avro
2、hive怎么优化???
Hive优化的核心思想就是把HiveSQL当做MapReduce程序去优化;select仅查询本字段和where仅对本字段进行条件过滤不需要转换MapReduce程序;(1)将HQL转换成MapReduce进行,map端进行join操作,小表join大表,大表join大表,过滤空的key;(2)对查询频率比较高的次建立分区表以减少数据扫描的范围;(3)在对待groupBy的数据倾斜的方面,我们设置hive.group.sviWind=ture,这表明它会自动进行负载均衡,去除了数据倾斜的问题;(4)map的数量要设置合适,过多会导致oom问题,过小会导致处理数据慢;(5)reduce数量设置要合适,数量过多会产生很多小文件,会对namenode产生压力,过少会导致单个节点压力大,会产生OOM问题;(6)JVM重用可以使得JVM实例在同一个job中时候使用N次,但是设置开启之后,task插槽会一直占用资源,不论是否有task运行,直到所有的task即整个job全部执行完成时,才会释放所有的task插槽资源;(7)排序:order by全排,数据太大时谨慎用;sort by对reduce里的数据做全排,局部排序;distribute by 按某个字段值,决定数据放入哪个reduce中;cluster by相当于sort by 加上distribute by。
3. hive的窗口操作
有时候我们想要既显示聚集前的数据,又要显示聚集后的数据,这时便引入了窗口函数;
(1)、聚合函数+over
七、关于kafka
1、什么是kafka??
Kafka是一个高吞吐量、低延迟、分布式的消息队列系统,每秒可以处理几十万条消息,它的延迟最低只有几毫秒;
Kafka提供了一个生产者、缓冲区、消费者的模型;kafka是由多个broker服务器组成,用于存储数据;不同的数据被分为不同的topic;producer往topic里生产数据,consumer从topic中获取数据;一个个消息组成partition,多个partition组成topic;每一个消息被标识了一个递增序列号代表其进来的先后顺序,将进来的消息追加到该partition的后面;每次消费之后会产生偏移量offset,它是唯一的标识该分区中的每个记录;kafka对消息默认保存7天,当然这个数据时可以调整的;每一个消费者唯一保存的元数据信息就是消费者当前消费日志的偏移量;该偏移量是由消费者控制,也就说消费者可以通过修改该偏移量来读取任何位置的数据;每个consumer都保留自己的offset,互相不干扰,不存在线程安全问题;partition均匀分配到集群server中。生产、消费消息时,会被路由到指定的partition,减少单台服务器的压力,增加了程序的并行能力;消息消费完成之后不会删除,可以通过重置offset重新消费;
应用场景:日志收集开放给各种consumer,比如hadoop、hbase、solr等;用户活动跟踪等等,可以装载到hadoop、数仓做离线分析和挖掘等等;
2、了解kafka的数据一致性是怎样做到的吗??
Producer往某个partition中写入数据时,只会往leader中写入数据,然后数据才会被复制进其他的replica中;kafka是由follower到leader上拉取数据的方式进行同步的;简单的说就是写都往leader上写,读也只在leader上读,flower只是数据的一个备份,只是为了防止leader挂掉,并不往外提供服务。
说到同步,在分布式架构中分为两种:第一种同步复制,即所有的follower把数据拿过去之后才commit,这样一致性好,但是性能不高;另一种是异步复制,只要leader拿到数据就立即commit,等follower慢慢复制,性能高,立即返回,但是一致性差;
我们kafka并不是同步也不是异步的,是一种独特的ISR机制;leader会维护一个与其基本保持同步的replica列表,被称之为ISR,每一个partition都会有一个ISR,由leader动态维护,如果一个follower比一个leader落后太多,或者超过一定时间没有发起数据复制请求,则leader将其ISR中移除;涉及到两个相关参数:replica.lag.time.max.ms和replica.lag.max.messages;当ISR中所有Replica都向Leader发送ACK时,leader才commit,当follower同时满足这两个条件时,leader又会将它加入ISR机制中,故ISR是一个处于动态调整的情况;
replica的作用:当partition的leader挂掉后,则会优先从ISR列表里挑选一个follower选举成新的leader,同时将旧的leader移除出ISR列表;
消费者API分为两种:highlevel consumer API偏移量由zookeeper来保存,使用简单,但是不灵活;simplelevelconsumerAPI 不依赖于zookeeper,无论从自由度和性能上都有更好的表现,但是开发很复杂。
3、kafka数据丢失和重复消费是怎样产生的,怎样解决???
先说数据丢失问题,有两种地方会数据丢失:第一种,producer端:有两种原因:第一,producer发数据给kafka时,它才开始将数据存储在服务器的pagecache中的,定期flush到磁盘上的,如果数据刚进来,这个时候断电的话,数据就会丢失;第二,是在使用kafka的备份机制时,producer的ack设置为0或1,最多只能保证leader有数据,假如producer发送的数据leader刚接收完毕,leader就挂掉了,那么partition的replica副本还未来得及同步,就会造成数据丢失;
这个问题怎么解决呢,我们可以提高flush的频率来减少数据丢失量,但这只是治标不治本,官方建议通过备份机制来解决数据丢失问题;
对于备份机制而导致的数据丢失问题,我们可以将ack设置为all,也就是所有的备份分区都同步到这条数据,再发第二条数据,但是这样就降低了性能,所以我们往往得结合业务来平衡数据的一致性和系统的性能;
第二种:consumer端导致数据丢失:在使用kafka高级API时,消费者会每个一段时间将offset自动保存到zookeeper上,假如刚提交完offset,数据还没消费,此时机器宕机,那么数据就丢失了;解决方案:关闭偏移量自动提交,改成手动提交,待数据每次处理完后再提交;
关于数据重复消费产生:消费者自动提交offset到zookeeper后,程序又消费了几条数据,但是还没到下次offset提交的时候。这个时候机器宕机。重启后,消费者会去zookeeper上读offset进行消费,这就会导致数据重复消费;解决方法就是关闭自动提交,改成手动提交。
4、kafka高吞吐的本质了解吗??讲讲
这个是kafka的一个最大的特点:为了保证数据写入性能,kafka是基于操作系统的页缓存来实现文件写入,即就是在数据写入文件时,先将数据写入OS cache中也就是仅仅写入内存中,接下来由操作系统自己决定什么时候把OS cache中的数据写刷入磁盘中;最重要的一点是:以磁盘顺序写的方式来写入文件的,也就是将数据追加到文件的末尾,不是在文件的随机位置来修改数据;磁盘顺序写的性能会比随机写快上几百倍;正因为这两点造就了kafka的超高性能;
另外一个原因就是零拷贝技术:正常的读取数据的顺序是:操作系统从磁盘将数据读取内核区的pagecache中;用户进程把数据从内核区copy到用户区的内存里;用户进程再把数据写入到socket,数据流入内核区socket buffer上;OS再把数据从socket buffer中copy到网卡上,最后发送给客户端消费者;
零拷贝技术就是直接让操作系统的cache中的数据发送到网卡后传输下游的消费者,中间跳过了两次拷贝数据的步骤;socket缓存中仅仅会拷贝一个描述符过去,不会拷贝数据到socket缓存。
这么说吧!!通过零拷贝技术,就不需要把OS cache里的数据拷贝到应用缓存,再从应用缓存拷贝到socket缓存了,两次拷贝都省略了,故叫零拷贝;对socket缓存仅仅就是拷贝数据的描述符过去,然后数据就直接从OS cache中发送到网卡上去了,这个过程大大的提升了数据消费时读取文件数据的性能;这样做之后相当于完全基于内存提供数据的读和写了,所以性能会极其的高。
5.kafka是怎样进行数据持久化的???
Kafka topic的数据存储在磁盘时会默认存储在/tmp/kafka-logs目录下,当然也可以自己设置,在该目录下会按topic的每个partition分区来存储,一个分区一个目录,一个partition目录下会有多个segment文件,分为.index和.log文件:其中.index文件为索引文件,命名从0开始,后续由上一个文件的最大的offset偏移量来开头;.log文件为数据文件,存放具体消息数据;kafka从磁盘上查找数据时,会先根据offset偏移量,对index文件名字进行扫描,通过用二分法的查找方式,可以快速定位到此offset所在的索引文件,然后通过索引文件里的索引,去对应的log文件种查找数据。
具体的相关参数:message.max.bytes (默认:1000000) – broker能接收消息的最大字节数;log.segment.bytes (默认: 1GB) – segment数据文件的大小;log.roll.hours (默认:7天) - 当segment文件7天时间里都没达到log.segment.bytes 大小,也会产生一个新文件;replica.fetch.max.bytes (默认: 1MB) – broker可复制的消息的最大字节数;fetch.message.max.bytes (默认 1MB) – 消费者能读取的最大消息;
八、关于Storm
1、什么storm??
Storm是一个实时的、分布式、高可靠性、可维护性以及具备高容错的异步流式计算框架;它是逐条处理数据的;它的架构主要有Nimbus,Supervisor,worker;编程模型:DAG、spout、Bolt;高可靠性体现在异常处理和消息的可靠性保障机制;可维护性体现在:提供UI界面图形化监控端口;它是一个基于内存的处理框架;
Storm的计算模型:
spout--数据源,拓扑中数据的来源。一般会从指定外部的数据源读取元组发送到拓扑中;一个spout可以发送多个数据流;spout中最核心的方法时next Tuple,该方法会被storm线程不断调用、主动从数据源拉取数据,再通过emit方法将数据生成元组发送给之后的Bolt计算。
Blot--数据流处理组件,拓扑中数据处理均由Bolt完成。对于简单的任务或者数据流转换,单个bolt可以简单实现,复杂的场景往往需要多个bolt分多个步骤完成;一个Bolt可以发送多个数据流;bolt中最核心的方法时execute方法,该方法负责接收到一个元组数据、真正实现核心的业务逻辑。
Storm grouping--数据流分组(数据分发策略),有shuffle grouping随机分组,field grouping按字段分组,all grouping广播发送,global grouping全局分组,nonegrouping不分组,direct grouping指向型分组,local or shuffle grouping本地或随机分组,customgrouping自定义分组。
2、了解storm的架构吗??
主要是Nimbus、Supervisor、Worker和zookeeper:Nimbus主要作用是--资源调度,任务分配,接收jar包;Supervisor--接收nimbus分配的任务,启动、停止自己管理的worker进程;worker--运行具体处理运算组件的进程,启动executor,一般默认一个executor负责一个task任务;worker的任务类型有spout任务和bolt任务;zookeeper负责管理集群;
具体的任务提交流程如下:
4. 了解storm的机制??
我看过他的通信机制和容错机制:
通信机制主要有这几个方面:ZeroMQ开源的消息传递框架,Netty基于NIO的网络框架,更加高效;worker内部实现了“队列”的功能,可以理解为一种事件监听或者消息处理机制,也就是队列当中一边由生产者放入消息数据,另一边消费者并行取出消息数据处理。
容错机制主要体现在这几方面:nimbus服务器上,配置集群防止服务器挂掉,非nimbus服务器发生故障时,该节点上的所有任务都会超时,nimbus会将这些task任务重新分配到其他服务器上运行;
进程挂掉时:worker进程挂掉后,supervisor会重新启动这个进程,如果一直启动失败,无法向nimbus发送心跳,nimbus会将该worker重新分配到其他服务器上;
Supervisor挂掉:无状态(所有的状态信息都存放在zookeeper中来管理),快速失败;
Nimbus挂掉:无状态(所有的状态信息都存放在zookeeper中来管理),快速失败;
消息的完整性:从spout中发出的tuple,以及基于它所产生tuple构成一棵tuple树,当其发送完成,并且树当中每一条消息都被正确处理,就标明spout发送消息被“完整处理”,即消息的完整性。实现机制--acker,负责跟踪每个spout发出的tuple的DAG。
九、关于Spark
1、什么是spark??
Spark是专门为大规模数据处理而设计的快速通用的计算引擎;spark计算主要是基于内存和DAG(有向无环图);spark处理数据的能力一般是MR的十倍以上;
Spark最核心的是RDD,那么什么是RDD呢?? RDD就是弹性分布式数据集;它主要有五大特性:RDD是由一系列的partition组成的(partition的数量,大小没有限制,体现了它的弹性)(partition是分布在不同的节点上,体现了它的分布式);函数是作用在每一个partition上的;RDD之间有一定的依赖关系(lineage血统);分区器是作用在K,V格式的RDD上的(RDD中存储的数据都是二元组对象);RDD提供一系列最佳的计算位置(体现了数据本地化和大数据中“计算向数据移动”的理念);一个application应用程序中有几个触发算子,就有几个job运行。
2. 了解持久化吗??
Spark的控制算子都可以将RDD持久化;持久化的单位是partition;cache和persist都是懒加载,需要触发算子才能执行,checkpoint不仅能持久化RDD到磁盘上,还能切断RDD之间的依赖关系;cache默认将数据持久化到内存上;persist持久化级别有12种级别;cache是persist的一种持久化;
Checkpoint运行原理:当RDD的job执行完毕后,会从finalRDD从后往前回溯,当回溯到某一个RDD调用了checkpoint方法,会对当前的RDD做一个标记;spark框架会自动启动一个新的job,重新计算这个RDD的数据,将数据持久化到HDFS上;
优化:对RDD执行checkpoint之前,最好对这个RDD先执行cache,这样新启动的job只需要将内存中的数据拷贝到HDFS上就可以,省略了重新计算这一步。
3. spark的任务提交模式有哪些??简单说说
(1)、standalone模式:有两种提交模式;
Standalone-client模式:
主要流程:client模式提交任务后,会在客户端启动driver进程;driver会向master申请启动application启动的资源;资源申请成功后,driver端将task发送到worker端执行;worker将task执行结果返回到driver端。
这种模式只适用于测试调试程序,因为driver每次都会从client端启动,如果在生产条件下会导致网卡流量暴增。
Standalone-cluster模式提交任务:
主要流程:cluster模式提交应用程序后,会向master请求启动driver;master接收请求,随机在集群一台节点启动driver进程;driver启动后为当前的应用程序申请资源;资源申请成功后,driver端发送task到worker节点上执行;worker端将执行情况和执行结果返回给driver端。
这种模式的主要特点是:driver进程是随机的在一台worker上启动,所以客户端无法查看task的执行情况;
总结这两种提交模式:driver的主要作用是:driver负责申请应用程序资源、分发任务、回收结果和监控task执行情况。
(2)yarn模式:主要有两种提交模式;
Yarn-client模式提交任务:
主要流程:客户端提交一个application。在客户端启动一个driver进程;driver启动后会向resourcemanager发送请求启动applicationmaster;resourcemanager收到请求,随机选择一台NodeManager启动ApplicationMaster;ApplicationMaster启动后会向resourcemanager请求一批container资源,用于启动executor;resourcemanager会找到一批NodeManager返回给ApplicationMaster,用于启动executor;ApplicationMaster会向NodeManager发送命令去启动executor;executor启动后,会反向注册driver,driver发送task到executor,执行情况和结果返回给driver端。
这种模式也会造成网卡流量暴增的问题。
第二种提交方式:yarn-cluster模式:
主要流程:客户端提交application,发送请求到ResourceManager请求启动ApplicationMaster;ResourceManager收到请求后随机在一台NodeManager上启动ApplicationMaster;ApplicationMaster启动后,发送请求到ResourceManager,请求一批container用于启动excutor;ResourceManager返回一批NodeManager节点给ApplicationMaster;ApplicationMaster连接到NodeManager,发送请求到NodeManager启动excutor;excutor反向注册到NodeManager所在的节点的driver;driver发送task到excutor;excutor将执行情况和执行结果返回给driver进程。
这种模式的特点:任务提交后不能查看日志,只能通过yarn查看日志。
4. 了解宽窄依赖吗??
父RDD与子RDDpartition之间的关系是一对一或者多对一,这样称之为窄依赖;父RDD与子RDDpartition之间的关系是一对多,称之为宽依赖;简单来说就是产生shuffle是宽依赖,反之是窄依赖。
说到宽窄依赖就不得说说DAG,那么什么是DAG呢。Spark任务会根据RDD之间的依赖关系,形成一个DAG有向无环图,DAG提交给DAGScheduler;DAGScheduler会把DAG划分为相互依赖的多个stage,依据就是RDD之间的宽窄依赖。遇到宽依赖就划分stage;stage切割规则:从后往前,遇到宽依赖就切割stage,它的计算模式也是pipeline管道计算模式;那么管道的数据什么时候会落地呢??有两种情况:对RDD持久化时;shuffle write的时候;
Stage的task并行度是由stage的最后一个RDD的分区数来决定的。
5. 聊聊spark的资源调度和任务调度
启动集群后,worker节点会向master节点汇报资源情况,master掌握了集群资源情况,当spark提交一个application后,根据RDD之间的依赖关系将application形成一个DAG有向无环图。任务提交后,spark会在driver端创建两个对象:DAGScheduler和TaskScheduler;DAGScheduler是任务调度的高层调度器,主要作用就是将DAG根据RDD之间的宽窄依赖关系划分为一个个的Stage,然后将这些stage以TaskSet的形式提交给TaskScheduler;TaskScheduler会遍历TaskSet集合,拿到每个task后会将task发送到计算节点executor中去执行;当task执行失败时,则由TaskScheduler负责重试,将task重新发送给executor去执行(其实就是发送到Executor中的线程池ThreadPool去执行),默认重试3次。如果过3次之后,这个task所在的stage就失败了。然后由DAGScheduler来负责重试,重新发送TaskSet到TaskScheduler;DAGScheduler默认重试4次。如果4次都失败了,那么这个job就失败了,application就失败了。
当然TaskScheduler不仅仅是重试失败的task,还会重试stragging(落后、缓慢),也就是一个task比其他task慢太多的话,它就会启动一个新的task与这个task执行相同的处理逻辑,哪一个先处理完,就一它的结果为准。这就是spark的推测执行机制。默认是关闭的;
因为对于ETL数据清洗时就要关闭,防止数据重复入库;若遇到数据倾斜的情况。开启推测机制,任务可能一直处于处理不完的状态。
粗粒度资源申请(spark):在application执行之前,将所有的资源申请完毕,才进行任务的调度;所有task执行完成后,才会释放这部分资源。这样的话task执行很快;但是资源无法充分利用。
细粒度资源申请(MR):Job中的每一个task在执行前自己去申请资源,task执行完成就释放资源;集群的资源可以充分利用;但是task自己去申请资源,启动会变慢,所有任务执行就慢。
6. spark-submit提交参数了解多少??
(1)、--master MASTER_URL,可以是spark://host:port,mesos://host:port,yarn,yarn-cluster,yarn-client,local;
(2)、--deploy-mode DEPLOY_MODE,driver程度运行的地方,client或者cluster,默认是client;
(3)、--class CLASS_NAME 主类名称,含包名;
(4)、--jars driver和executor依赖的第三方jar包;
(5)、--files 用逗号隔开的文件列表,会放置在每个executor工作目录中;
(6)、--conf spark的配置属性;
(7)、--driver-memory driver程序使用内存大小,默认1024M;
(8)、--executor-memory 每个executor内存大小,默认1G;
(9)、--driver-cores driver程序的使用core个数,默认为1,仅限于spark standalone模式;
(10)、--supervise 失败后是否重启driver,仅限于spark alone或者mesos模式;
(11)、--total-executor-cores executor使用的总核数,仅限于sparkstandalone、spark on mesos模式;
(12)、--executor-cores 每个executor使用的core数,spark on yarn默认为1,standalone默认为worker上所有可用的core;
(13)、--driver-cores driver使用的core,仅在yarn-cluster模式下,默认为1;
(14)、--queue QUEUE_NAME 指定资源队列的名称,默认:default;
(15)、--num-executors 一共启动的executor数量,默认是2个。
7. spark的一些边缘知识点
SparkUI界面了解;配置historyserver;
广播变量:只能在driver端定义,不能在executor端定义;diver端可以修改广播变量的值,在executor端无法修改广播变量的值;
累加器:在driver端定义赋初始值,累加器只能在driver端读取,在excutor端更新。
8. 讲讲spark的shuffle??
Spark的shuffle有两种类型:hashshuffle(1.2版本之前)和sortshuffle(1.2版本之后),spark2.0之后只有sortshuffle了;
(1)hashshuffle:
① 普通机制:
执行流程:每一个map task将不同结果写到不同的buffer中,每个buffer的大小为32K,它起到数据缓存作用;每个buffer文件最后对应一个磁盘小文件;reducetask来拉取对应的磁盘小文件;map task的计算结果会根据分区器(默认hashpartitioner)来决定写入到哪一个磁盘小文件中去;reducetask会去map端拉取相应的磁盘小文件;产生小文件的个数:maptask的个数*reducetask的个数;shuffle write会产生很多写磁盘小文件的对象,shuffle read会产生很多读取磁盘小文件的对象;JVM会频繁GC,若GC还无法解决运行所需要的的内存,就会OOM;数据传输时会有频繁的网络通信,那么出现通信故障可能性大大增加,会导致shuffle file cannot find 由于这个错误导致的task失败,TaskScheduler不负责重试,由DAGScheduler负责重试Stage。
② 合并机制:
产生小文件的个数:core数*reduce个数;
(2)Sortshuffle
① 普通机制:
执行流程:map task的计算结果会写入到一个内存数据结构里面,内存数据结构默认是5M,在shuffle时会有一个定时器,不定期的去估算这个内存结构的大小,会申请扩大内存,如果申请不成功,那么发生溢写到磁盘;溢写之前内存中的结构数据会进行排序分区,然后开始溢写,以batch的形式去写,一个batch是1万条数据;map task执行完成后,会将这些磁盘小文件合并成一个大的磁盘文件,同时生成一个索引文件;reduce task去map端拉取数据时,首先解析索引文件,再根据索引文件去拉取对应的数据;产生磁盘小文件的个数:2*map task的个数。
② Bypass机制:
Bypass运行机制的触发条件:shuffle reduce task的数量小于spark.shuffle.sort.bypassMergeThreshold的参数值。这个值默认是200;不需要进行map端预聚合。产生磁盘小文件为:2*map task的个数。
9. shuffle的寻址??
理解图:
Shuffle文件寻址流程:当map task执行完成后,会将task的执行情况和磁盘小文件的地址封装到MpStatus对象中,通过MapOutPutTrackerWorker对象向driver中的MapOutPutTrackerMaster汇报;在所有的map task执行完毕后,driver中就掌握了所有的磁盘小文件的地址;在reduce task执行之前,会通过excutor中MapOutPutTrackerWorker向driver端的MapOutPutTrackerMaster获取磁盘小文件的地址;获取到磁盘小文件的地址后,会通过BlockManager中的ConnectionManager连接数据所在节点上的ConnectionManager,然后通过BlockTransferService进行数据的传输;BlockTransferService默认启动5个task的节点拉取数据。默认情况下5个task拉取数据量不能超过48M。
10. 讲讲spark内存管理
Spark内存管理分为静态内存管理和统一内存管理,spark1.6之前使用的是静态内存管理,之后引入统一内存管理;
(1)静态内存管理:
20%用于task计算;20%中的80%进行shuffle的聚合内存,20%预留内存,防止OOM;60%中10%预留,防止OOM问题,60%中的90%中的20%用于解压序列化数据,剩下的存储RDD的缓存数据和广播变量。
(2)、统一内存管理
整个内存中空余出300M用于JVM自身运行;总内存数-300M的25%用于task计算;剩下的75%中的50%用于shuffle聚合,其余的用于存储RDD缓存数据和广播变量,这两部分是可以相互动态借用的。
那么reduce中OOM该如何处理呢?? 减少每次拉取的数据量;提高shuffle聚合的内存比例;提高excutor的总内存。
这里就要说一下shuffle调优了,可以在代码中设置配置项new SparkConf().set(“spark.shuffle.file.buffer”,”64”),不推荐,这是硬编码;推荐使用在提交spark任务时配置spark-submit --conf spark.shuffle.file.buffer=64 –conf …;在conf下的spark-default.conf配置文件中,不推荐,因为这个conf是所有的程序都要使用的。
11. 谈谈你对sparkSQL的理解
Shark是基于spark计算框架之上且兼容hive语法的SQL执行引擎,底层的计算是采用spark,性能比MapReduce的hive快上2倍左右;spark底层依赖于hive的解析器,查询优化器;spark on hive:hive只作为储存角色,spark负责SQL解析优化,执行;hive on spark:hive即作为存储又负责SQL的解析优化,spark负责执行。
说到这里就得谈谈dataset了,它是一个分布式数据容器,很像传统数据库的二维表;除了数据以外,还掌握了数据的结构信息,即schema;dataset的底层封装的是RDD,当RDD的泛型时Row时,也可称之为dataframe。
SparkSQL的数据源可以是json类型的字符串、JDBC、Parquent、hive、HDFS等;
创建dataset的方式:
读取json格式的文件创建dataset和通过json格式的RDD创建dataset;通过反射的方式将非json格式的RDD转换成dataset和动态创建schema将非json格式的RDD转换成dataset;读取parquet文件创建dataset;读取JDBC中的数据创建dataset;读取hive中的数据加载成dataset;
开窗函数:按照某个字段分组,然后取另一字段的前几个的值,相当于分组取topN,函数格式:row number() over (partition by XXX order by XXX)。
12. 讲讲spark streaming
Sparkstreaming是一个支持可扩展、高吞吐量、容错的准实时流处理框架,实时的数据来源可以是:kafka、flume、Twitter或者TCP sockets,可以使用高级功能的复杂算子来处理数据,比如map、reduce、join、window,处理后的数据可以放在HDFS、数据库等等。
13. spark streaming和storm的区别
Storm是纯实时的流处理框架,sparkstreaming是准实时的处理框架(微批处理),吞吐量比storm高;storm的事务机制要比sparkstreaming的完善;storm支持动态资源调度(spark1.2之后也支持);sparkstreaming擅长复杂的业务处理,storm擅长简单的汇总型计算。
这里还要说一下sparkstreaming的窗口操作,也就是窗口长度和滑动间隔必须是batchInterval的整数倍,反之会检测报错。
14. 了解sparkstreaming与kafka整合吗??
Sparkstreaming2.2(包含以前)+kafka主要有两种模式:
(1)、receiver模式
当sparkstreaming程序运行起来后,executor中会有receiver task接收kafka推送过来的数据,会被持久化,默认级别是MEMORY_AND_DISK_SER_2,当然这个级别也可以修改,receiver task对接收过来的数据进行存储和备份,完成之后去zookeeper中更新消费偏移量,然后向driver中的receiver tracker汇报数据的位置,最后driver根据数据本地化将task分发到不同节点上执行。
这样的话有个问题:如果driver进程挂掉后,它下面的executor都会被杀掉,更新zookeeper消费偏移量时,它挂掉了,就会存在找不到数据的问题,也就是丢失数据;当然,你也可以开启WAL预写日志机制,在接收数据时在备份到其他节点时,同时备份到HDFS上,这样就能保证数据的安全性,但是这样比较消耗性能,增加job的执行时间,提高了任务执行的延迟度。
Receiver模式的并行度设置:该并行度是由spark.streaming.blockInterval来决定的,默认是200MS想要提高并行度可以减少blockInterval的数值,但是最好不要低于50MS。
(2)、direct模式:
该模式下是主动去kafka中取数据,sparkstreaming内部对消费者偏移量自动来维护,默认存放在内存中,若设置了checkpoint,那么会保存在checkpoint中,也可以实现zookeeper来管理。
Direct模式的并行度是由读取的kafka中topic的partition数决定的。
如何优雅的停止sparkstreaming:spark.streaming.stopGracefullyOnShutdown设置成true,然后再杀死进程:kill -15/sigterm driverpid。
说了这么多,总结下来也就几点:
关于receiver模式:采用了receiver接收器模式,需要一个线程一直接收数据,将数据接收到executor中默认存储级别:MEMORY_AND_DISK_SER_2;自动使用zookeeper管理消费者offset;底层读取kafka采用 high level consumerAPI实现,不关心偏移量,只要数据;当driver挂掉后,有数据丢失问题,可以开启WAL机制防止,但是这样的话又加大了数据处理延迟,也会存在数据重复消费风险;并行度默认spark.streaming.blockInterval=200ms,可以减少这个参数增大并行度,最小不能低于50ms。
之所以不使用它:被动接收数据,有数据存储问题,不能手动维护消费者offset。
关于direct模式:主动接收数据,自己管理消费者offset,默认存在内存中,可以设置checkpoint,保存到checkpoint中;底层读取kafka使用simple consumerAPI,可以手动维护消费者offset;该模式的并行度与读取的topic的partition一一对应;可以设置checkpoint的方式管理消费者偏移量,使用StreamingContext.getOrCreate(ckDir,CreateStreamingContext) 恢复,但是这样有缺点:代码逻辑改变后,无法从checkpoint中来恢复offset;从checkpoint中恢复数据时,有可能造成重复消费,需要我们写代码来保证数据的输出幂等。如果代码逻辑改变,就不能使用checkpoint模式管理offset,可以手动维护消费者offset,可以将offset存储到外部系统。
Kafka0.11版本的改变:由于zookeeper集群不能扩展写能力,所以将消费者偏移量放在zookeeper中,每次写操作代价很昂贵,依次kafka0.11版本默认使用新的API,将offset更新到一个kafka自带的topic(_consumer_offsets)中,以消费者组groupid为单位,可以查询每个组的消费topic情况。
Sparkstreaming2.3与kafka0.11的整合:丢弃了receiver模式;采用了新的消费者API实现,并行度还是有topic中的partition来决定;大多数情况下sparkstreaming读取数据使用LocationStrategies.PreferConsistent 这种策略,这种策略会将分区均匀的分布在集群的Executor之间。如果Executor在kafka 集群中的某些节点上,可以使用 LocationStrategies.PreferBrokers 这种策略,那么当前这个Executor 中的数据会来自当前broker节点。如果节点之间的分区有明显的分布不均,可以使用 LocationStrategies.PreferFixed 这种策略,可以通过一个map 指定将topic分区分布在哪些节点中;新的消费者API可以将kafka中的消息预读到缓存区中,默认大小为64K,在executor中,可以通过参数设置spark.streaming.kafka.consumer.cache.maxCapacity 来增大,也可以通过spark.streaming.kafka.consumer.cache.enabled 设置成false 关闭缓存机制;
关于offset的处理:checkpoint有我们以前说的那两种缺点;依靠kafka存储offset有这样的缺点:数据默认保存一天,如果这一天内数据没有被消费,那么将会被清除,无法保证有且只有一次语义,因为offset的提交是异步的,所有结果的输出依然要自己实现幂等性;自己存储offset,在处理逻辑时,保证数据处理的事务,处理数据成功再保存offset,这样可以做到精准的处理一次处理数据。
15. spark调优有哪些方面??
Spark调优主要有一下几个方面:
(1)、资源调优:可以在集群中指定资源分配的默认参数;在conf目录下的spark-env.sh,提交命令时给当前的application分配更多的资源,也就是增加命令选项;动态的分配资源。
(2)、并行度调优:读取HDFS中的数据时,降低block的大小,相当于提高了RDD中partition的个数,或者代码中sc.parallelize(xxx,numPartitions)、sc.makeRDD(xxx,numPartitions)、sc.parallelizePaits(xxx,numPartitions)、repartions/coalesce、reduceByKey/groupByKey/join---(xxx,Patitions)、spark.default.parallelism net set、spark.sql.shuffle.partitions---200、自定义分区器;
如果读取数据时在sparkstreaming中:receiver模式中:spark.streaming.blockInterval--200ms,
direct模式中:读取的topic的分区数。
(3)、代码调优:避免创建重复的RDD;对多次使用的RDD进行持久化;尽量避免使用shuffle类的算子,当一个RDD大,一个RDD小时,可以将小的RDD用广播变量广播;4.使用map-side预聚合的shuffle操作:也就是尽量使用有combiner的shuffle类算子,可以降低shuffle write写磁盘的数据量,降低shuffle read拉取数据量的大小,降低reduce端聚合的次数,常见的这类算子有:reduceByKey、aggregateByKey和combinerByKey;尽量使用高性能的算子:reducebykey代替groupbykey,mappartition代替map、foreachpartition代替foreach;使用广播变量,每个executor中只保留一份副本,executor中task执行时共享这份副本,可以减少网络传输的性能开销,减少对executor内存的占用开销,降低GC的频率;使用kryo优化序列化性能,用到序列化的三个方面:在算子函数中使用到外部变量时,该变量会被序列化后进行网络传输,将自定义的类型作为RDD的泛型类型时会被序列化,使用可序列化的持久化策略;kryo序列化机制比java序列化机制高10倍左右,默认是java序列化机制,因为kryo要求要注册所有需要进行序列化的自定义类型,开发比较麻烦;优化数据结构:对象、字符串和集合类型比较占用内存,官方建议在spark编码中尽量用字符串代替对象,用原始类型代替字符串,使用数组代替集合类型,这样可以降低GC频率,提升性能;使用高性能的库fastutil。
(4)、数据本地化四个级别:PROCESS_LOCAL,task计算的数据在本进程的内存中;NODE_LOCAL,task所计算的数据在本节点所在的磁盘上或者数据在本节点其他executor进程的内存中;NO_PREF,task所计算的数据在关系型数据库中;RACK_LOCAL,task所计算的数据在同机架的不同节点的磁盘或者executor进程的内存中;ANY,跨机架;数据本地化调优:spark中任务调度时TaskScheduler需要依据数据的位置来分发task到数据所在的节点上,默认分发5次,每次等待3秒还是不能执行,那么TaskScheduler会降低一级数据本地化级别再次发送task;可以将发送task的等待时间调大,但是要适量,在保证application的执行时间可接受的范围内。
(5)、内存调优:JVM堆内存分为一块较大的Eden和两块较小的Survivor,每次只使用Eden和其中一块Survivor,当回收时将Eden和Survivor中还活着的对象一次性复制到另外一块Survivor上,最后清理掉Eden和刚才用过的Survivor,也就是说当Eden和其中一起使用Survivor区域满了之后就会触发minor gc进行清理,如果另一个Survivor满了,那么JVM就会将多余的对象放入到老年代中,若年轻代内存不是很大,就会频繁gc,当年龄过大(默认15岁),还是没有被回收就会跑到老年代中,老年代就会溢满进行full gc(使用消耗性能和时间的垃圾回收算法)不管是minor gc还是full gc都会导致JVM的工作线程停止;影响spark的性能的运行速度;调优方法:提高executor总体内存的大小;降低储存内存的比例或者降低shuffle聚合内存的比例。
(6)、spark shuffle调优:buffer大小(默认32KB)可以调大;shuffle read拉取数据量的大小(默认48M);shuffle聚合内存的比例(默认20%);拉取数据重试次数(默认5次);重试间隔时间(默认60S);spark shuffle的种类;sortshuffle bypass机制(默认200次)。
(7)、调节executor的堆外内存:spark底层shuffle传输方式是使用netty传输(零拷贝技术),堆外内存默认每一个executor的内存大小的10%,运行spark是调节这个参数到1G或者更大;如果executor由于内存不足或者堆外内存不足挂掉,怎样调节堆外内存的大小:在提交任务脚本中添加--conf spark.yarn.executor.memoryOverhead=2048 单位M(yarn模式),--conf spark.executor.memoryOverhead=2048 单位M(standalone模式);spark默认网络超时时长120S,如果超过那么task就失败了,会出现shuffle file cannot find错误;可以在提交任务脚本里添加:--conf spark.core.connection.ack.wait.timeout=300。
(8)、数据倾斜:使用hive ETL预处理数据;过滤少数导致倾斜的key;提高shuffle操作的并行度;双重聚合,核心实现思路就是进行两阶段聚合:第一次局部聚合,先给每个key都打上随机数,进行预聚合放入不同的分区内,再去掉各个key的前缀,再次进行全局聚合操作;使用广播变量代替join操作;采样倾斜key并分拆join操作;使用随机前缀和扩容RDD进行join。
十、关于中间插件
1. 简单讲讲impala
Impala是Cloudera公司推出,提供对HDFS、Hbase数据的高性能、低延迟的交互式SQL查询功能;基于hive使用内存计算,兼顾数据仓库、具有实时、批处理、多并发等优点;是CDH平台首选的PB级大数据实时查询分析引擎;
主要特点:无需转换为MR,直接读取HDFS及Hbase数据,从而大大降低了延迟;Impala没有MapReduce批处理,而是通过使用与商并行关系数据库中类似的分布式查询引擎(由Querry Planner、Querry coordinator和Querry Engine三部分组成);兼容HiveSQL,支持hive基本的一些查询;具有数据仓库的特性,可对hive数据直接做数据分析;支持Data Local,无需数据移动,减少数据的传输;支持列式存储;支持JDBC/ODBC远程访问。
主要劣势:对内存依赖大;完全依赖hive;实践过程中分区超过1万,性能严重下降;稳定性不如hive。
主要缺点:Impala不提供任何对序列化和反序列化的支持;Impala只能读取文本文件,而不能读取自定义的二进制文件;每当新的记录/文件被添加到HDFS中的数据目录时,该表需要被刷新。
Impala的核心组件:statestore Daemon,负责收集分布在集群中各个impala进程的资源信息、隔节点健康状况,同步节点信息;负责Querry的调度;catalog Daemon,从hive元数据库中同步元数据,分发表的元数据信息到各个impala中;接收来自statestore的所有请求;Impala Daemon(具有数据本地化的特性故放在DataNode上),接收client、hue、jdbc或者odbc请求、Querry执行并返回给中心协调节点;子节点上的守护进程,负责向statestore保持通信,汇报工作。
架构流程:客户端向某一个Impala发送一个Querry(SQL);Impala将Querry解析为具体的执行计划Planner,交给当前机器coordinator即为中心协调节点;coordinator根据执行计划Planner,通过本机executor执行,并转发给其他有数据的impala用executor进行执行;impala的executor之间可进行通信,可能需要一些数据的处理;各个impala的executor执行完成后,将结果返回给中心协调节点;由中心节点coordinator将汇聚的查询结果返回客户端;impala的执行计划:把执行计划表现为一棵完整的执行计划树,可以更自然地分发执行计划到各个Impalad执行查询,而不用像Hive那样把它组合成管道型的 map->reduce模式,以此保证Impala有更好的并发性和避免不必要的中间sort与shuffle;任务调度:Impala的调度由自己完成,目前的调度算法会尽量满足数据的局部性,即扫描数据的进程应尽量靠近数据本身所在的物理机器。但目前调度暂时还没有考虑负载均衡的问题。从Cloudera的资料看,Impala程序的瓶颈是网络IO,目前Impala中已经存在对Impalad机器网络吞吐进行统计,但目前还没有利用统计结果进行调度。
2. 讲讲oozie
Oozie是大数据中一个作业协调框架,它提供对hadoop、mapreduce和pig job的任务调度与协调;需要部署到java servlet容器中运行;功能相似的任务调度框架还有Azkaban和Zeus。
Oozie三大功能模块:workflow:定义job任务执行;coordinator:定时触发workflow,周期性执行workflow;bundle job:绑定多个coordinator,一起提交或触发所有coordinator。
Oozie工作流:本质就是一个作业协调工具,底层原理是通过将xml语言转换成MapReduce程序来做,但只是集中在map端做处理,避免shuffle的过程;执行workflow之前首先要进行相关配置:job.properties定义相关属性以及参数;workflow.xml定义控制流和动作节点;lib存放job任务的相关资料文件;
Oozie的工作流必须是一个有向无环图,实际上Oozie就相当于Hadoop的一个客户端,当用户需要执行多个关联的MR任务时,只需要将MR执行顺序写入workflow.xml,然后使用Oozie提交本次任务,Oozie会托管此任务流。
Oozie cli命令:使用oozie之前必须先启动HDFS、yarn和jobhistory; 所有的命令都是以oozie job -oozie oozie_url 开头的-config 制定job.properties文件夹的位置,-run 文件启动后会返回一个唯一的jobId,供之后使用。
3. 讲讲CDH
CDH是cloudera公司的发行版hadoop,我们将该版本称之为CDH(cloudera distribute hadoop)核心功能:可扩展存储,分布式计算,基于web用户界面操作。
优点:版本划分清晰;版本更新速度快;支持kerberos安全认证;文档清晰;支持多种安装方式。
Cloudera Manager是一个拥有集群自动化安装、中心化管理、集群监控、报警功能的一个工具(软件),使得安装hadoop集群的时间大大缩短,运维人员数大大降低,极大的提高集群管理的效率;
Cloudera Manager四大功能:管理:对集群进行管理,比如添加、删除节点等操作;监控:监控集群的健康情况,对设置的各种指标和系统运行情况进行全面监控;诊断:对集群出现的问题进行诊断,对出现的问题给出建议解决方案;集成:对hadoop的多组件进行整合。利用CM可以分厂方便快速的搭建CDH集群。
4. 讲讲redis
Redis是一个开源的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件;redis是键值对数据库,支持多种类型的数据结构,不仅可以是字符串,同时还提供散列、列表、集合、有序集合等数据结构,redis是一个内存数据库。
Redis的使用:key操作--为给定key设置生存时间(expipre key seconds);string操作;list操作;set操作;sorted set操作;hash操作--KV模式不变,但是V是一个键值对(hset key field value),返回哈希表key中给定域field的值(hget key field)。
Redis的持久化:
RDB:在指定的时间间隔内将内存中的数据集快债写入磁盘,恢复时就是将快照文件直接读到内存里;redis会单独的创建一个子进程来进行持久化,会先将数据写入到一个临时文件中,待持久化过程结束了,再用该文件替换上次持久化的文件;由于主进程不进行任何IO操作,所以拥有极高的性能;假如需要进行大规模的数据恢复,且对于数据恢复的完整性不是非常敏感,那么RDB比AOF更加高效;但是他有一个明显的特点:最后一次持久化后的数据可能丢失;RDB保存的是dump.rdb文件。
AOF:以日志的形式将记录每个操作,将redis执行过的除了读操作以外的所有写指令记录下来;只允许追加文件但不可以改写文件;redis重启的haul就根据日志文件的内容将写指令从前到后执行一次以完成数据恢复工作。
AOF有三种策略:always--同步持久化,每次数据变更会被立即记录到磁盘,性能差但数据完整性较好;everysec--出厂默认推荐,异步操作,每秒记录,有数据丢失;no--从不fsync==将数据交给操作系统来处理,更快也最不安全的选择。
AOF的rewrite:AOF采用追加方式,文件过大时就新增了重写机制,也就是aof文件大小超过所设定的阈值,redis会自动将aof文件的内容压缩,值保留可以恢复数据的最小指令集;重写原理:aof文件持续增长而变大时,会fork初一条新的进程来将文件重写,遍历新进程的内存中的数据,每条记录有一条set语句,重写aof文件的操作,不读取旧的aof文件,而是将整个内存的数据库内容用命令的方式重写一个新的aof文件。
触发机制:redis会记录上次重写的aof的大小,默认的配置当aof文件大小为上次rewrite后大小的一倍且文件大于64M触发。
AOF的优点让redis变得非常耐久;默认每秒fsync一次;它是以追加操作的方式来写日志文件,因此不需要seek;文件过大时发生重写,防止数据丢失。
AOF的缺点:对于相同的数据集来说,AOF文件的体积通常大于RDB文件的体积;使用fsync策略上AOF速度可能会慢于RDB。
Redis的主从复制:异步复制;一个主服务器可以有多个从服务器;从服务器也可以有自己的从服务器;复制功能不会阻塞主服务器也不会阻塞从服务器。
Redis的哨兵模式:管理多个redis服务器主要有三大任务:监控、提醒和故障迁移。
5. 聊聊flume
Flume主要由三大部分组成:source、channel和sink;
Source:主要的数据来源,用于采集数据,产生数据流的地方,将产生的数据流传输到channel;可以处理各种类型、各种格式的日志数据,包括:avro、thrift、exec、spooling directory、netcat、syslog、http、legacy等等。
Channel:用于桥接source和sinks,类似于一个队列;线程安全的,可以同时处理几个source的写入操作和几个sink的读取操作;自带两种channel:一种是memory channel内存中的队列,可以在不需要关心数据丢失的情景下使用;另一种是file channel 将所有时间写到磁盘上,这样不会因为程序关闭或者机器宕机而产生数据丢失
Sink:从channel收集数据,将数据写到目标源;sink不断地轮询channel中的事件且批量地移除他们,并将这些事件批量写入到存储或索引系统、或者发送到另一个flume agent;sink是完全基于事务的,删除数据前,每个sink用channel了启动一个事务。批量事件一旦成功写出到存储系统或下个 flume agent。Sink就利用channel提交事务,完成之后,该channel从自己的内部缓冲区删除事件;
Sink的输出包括HDFS、logger、avro、file、Hbase、kafka等
Flume event是数据流的基本单元,由一个装载数据的字节数组和一些列可选的字符串属性组成;
6. sqoop的理解
Sqoop是一个数据迁移工具,我曾经遇到两个问题:
(1)、sqoop导入数据事件日期类型错误:用sqoop import从MySQL数据库导入到HDFS时一直报错,后面才发现是一个事件日期类型的非法值导致的,在hive中执行select语句查询该字段的时候报错;解决办法是在创建hive表时用string字段类型;
(2)、sqoop导入导出null存储一致性问题:hive中的null在底层是以“\N”来存储的,而MySQL中的null在底层就是null,为了保证数据两端的一致性,转化的过程中遇到null-string,null-non-string数据都转化成指定的类型,通常指定成“\N”。在导出数据时采用input-null-string “\N”,input-null-string“\N”两个参数;导入数据时采用null-string“\N”null-non-string “\N”。
(3)、sqoop导出数据到MySQL一致性问题:使用 --staging table选项,将HDFS中的数据先导入到辅助表中,成功之后。辅助表中的数据在一个事务中导出到目标表中;
底层运行的任务中只有map阶段,没有reduce阶段。
十一、关于kylin
1.什么是kylin
Kylin是一个开源的首个完全由中国团队设计开发的分布式分析引擎,它提供hadoop之上的SQL查询接口及多位分析(OLAP)能力以及支持大规模数据,能够处理TB乃至PB级别的分析任务,能够在亚秒级查询巨大的hive表,并支持高并发。
Kylin的工作原理:指定数据模型,定义维度和度量;预计算cube,计算所有cuboid并保存为物化视图;执行查询时,读取cuboid,运算,产生查询结果。
Kylin的核心思想是cube预计算,理论基础是空间换时间,把高复杂度的聚合运算、多表连接等操作转换成对预计算结果的查询。
Kylin在数据集规模上的局限性主要取决于维度的个数和基数,而不是数据集的大小,所以kylin能更好的支持海量数据集的查询;也正是预计算技术,kylin的查询速度非常快,亚秒级响应。而hive的查询时间随着数据量的增长成线性增长。
2.kylin的优化
Cube的剪枝优化:聚合组,根据业务场景,将常用的维度组合定义到一个聚合组中,提高查询性能;强制维度:若一个维度被定义为强制维度,那么这个分组产生的所有cuboid中每一个cuboid都会包含该维度,降低预计算的维度;层次维度:比如:年月日,将它们设置为层次维度,cuboid数量将下降;联合维度:每个联合中包含两个或更多个维度,那么这些维度要么一起出现,要么都不出现;衍生维度;
Rowkey编码优化:kylin支持以下几种编码:data编码:将日期类型的数据使用三个字节进行编码;time编码:仅仅支持到秒,只使用4个字节,如果能够接受 秒级的时间精度,请选择Time编码来代表时间的维度;Integer编码:Integer编码需要提供一个额外的参数“Length”来代表需 要多少个字节。Length的长度为1~8。如果用来编码int32类型的整数,可以将Length设为4;如果用来编码int64类型的整数,可以将Length设为8。在更多情况下,如果知道一个整数类型维度的可能值都很小,那么就能使用 Length为2甚至是1的int编码来存储,这将能够有效避免存储空间的浪费;dict编码:对于使用该种编码的维度,每个Segment在构建的时候都会为这个维度所有可能的值创建一个字典,然后使用字典中每个值的编 号来编码。Dict的优势是产生的编码非常紧凑,尤其在维度值的基数较小且长度较大的情况下,特别节约空间。由于产生的字典是在查询时加载入构建引擎和查询引擎的,所以在维度的基数大、长度也大的情况下,容易造成构建引擎或查询引擎的内存溢出;fixed length编码:编码需要提供一个额外的参数“Length”来代表需 要多少个字节。该编码可以看作Dict编码的一种补充。对于基数大、长度 也大的维度来说,使用Dict可能不能正常工作,于是可以采用一段固定长度的字节来存储代表维度值的字节数组,该数组为字符串形式的维度值的UTF-8字节。如果维度值的长度大于预设的Length,那么超出的部分将会被截断。
十二、关于flink
1. 什么是flink
Flink是一个低延迟、高吞吐、统一的大数据计算引擎,flink的计算平台可以实现毫秒级的延迟情况下,每秒钟处理上亿次的消息或者事件,还提供了一个Exactly-once的一致性语义,保证了数据的正确性;也提供了有状态的计算,支持状态管理,支持强一致性的数据语义以及支持event time,watermark对消息乱序的处理。
Flink以流式处理为核心,用流处理去模拟批处理;支持流处理,SQL处理,批处理;对于流处理:实时性强,吞吐量高,延迟度低。
每个flink程序由source operator+transformation operator+sink operator组成;
Flink中的key:flink处理数据不是K,V格式编程模型,它是虚拟的key;批处理用groupby算子,流式处理用keyby算子。
虚拟key的指定:使用Tuples来指定key;使用Field Expression来指定key;使用 key selector Functions来指定key。
2. 讲讲flink的架构
Flink运行时包含了两种类型处理器:jobmanager(master):用于协调分布式执行,他们用来调度task,协调检查点,协调失败时恢复等等;flink运行时至少存在一个jobmanager,高可用模式中可能会存在多个,一个leader和多个standby;taskmanager(worker):用于执行一个dataflow的task(或者特殊的subtask)、数据缓冲和data stream的交换,flink运行时至少会存在一个taskmanager。
启动方式:standalone模式、yarn模式、meson模式以及container(容器)。
Flink on yarn有两种运行模式:yarn-session模式:预先在yarn上面划分一部分资源给flink集群用,flink提交的所有的任务共用这些资源;single-job模式:每次提交任务时,都会创建一个新的flink集群,任务之间相互独立,互不影响,方便管理;任务执行完成之后,flink集群也会消失。
Flink on yarn的运行原理:
流程:当启动一个新的flink yarn client会话,客户端首先会检查所请求的资源(容器和内存)是否可用,之后会上传包含了flink配置文件和jar包到HDFS;客户端的请求一个container资源去启动applicationmaster进程;resourcemanager选一台机器启动AM(JobManager 和 AM 运行在同一个容器中。一旦它们成功地启动了,AM 知道 JobManager 的地址(它自己)。它会为 TaskManager 生成一个新的 Flink 配置文件(这样它们才能连上 JobManager)。该文件也同样会上传到 HDFS。另外,AM 容器同时提供了 Flink 的 Web 界面服务);AM是为flink的taskmanager分配容器在对应的NodeManager上面启动taskmanager;初始化工作,从HDFS下载jar文件和修改过的配置文件。
3. flink的并行度
Flink程序的任务并行度设置分为四个级别:算子级别:可以通过调用其setparallelism方法来定义单个运算符,数据源或数据接收器的并行度;执行环境级别:执行环境级别的并行度是本次任务中所有的操作符,数据源和数据接收器的并行度,可以同显式的配置运算符并行度来覆盖执行环境并行度;客户端级别:提交作业时,可以在客户端设置并行度,通过使用指定的parallelism参数 -p;系统级别:通过设置flink/conf/flink-conf .yaml配置文件中的parallelism.default配置项来定义默认并行度。
4. 讲讲flink的窗口机制
Windows是flink处理无限流的核心,flink底层引擎是一个流式引擎,在上面实现了流处理和批处理。而窗口就是从streaming到batch的一个桥梁。基于不同事件驱动的窗口可以分为:
翻滚窗口:将数据流切分成不重叠的窗口,每一个事件只能属于一个窗口。具有固定的尺寸。基于时间驱动:我们需要统计每一分钟中用户购买的商品的总数,需要将用户的行为事件按每一分钟进行切分,这种切分被成为翻滚时间窗口。基于事件驱动:当我们想要每100个用户的购买行为作为驱动,那么每当窗口中填满100个相同元素,就会对窗口进行计算;
滑动窗口:可以有重叠的部分。在滑动窗口中,一个元素可以对应多个窗口。基于时间驱动:每30s计算依次最近一分钟用户购买的商品总数(timewindow);基于事件:每10个相同元素计算依次最近100个元素的总和(countwindow);
会话窗口:窗口不重叠,没有固定的开始和结束时间。当会话窗口在一段时间内没有接收到元素时,会关闭窗口,后续元素将分配给新的会话窗口。
5. 事件时间与水印
Flink中有三种时间类型:处理时间:当前机器处理该条事件的时间;事件时间:是每个事件时间在其设备上发生的时间。对于乱序、延时或者数据重放等情况都能给出正确结果;摄入时间:数据进入flink框架的时间,是在source operator中设置的。
流处理过程中由于网络、背压等原因,导致数据乱序;对于延迟数据,我们不能无限期的等下去,必须要有个机制来保证一个特定的时间后,必须触发window去进行计算,该机制就是waterMark。WaterMark是flink为了处理eventtime时间类型的窗口计算提出的一种机制,本质上也是一种时间戳;waterMark是用于处理乱序事件的,而正确的处理乱序事件,通常用waterMark机制结合window来实现。
具体流程:waterMark包含一个时间戳,flink使用waterMark标记所有小于该时间戳的消息都已流入,flink的数据源在确认所有小于某个时间戳的消息都已输出到flink流处理系统后,会生成一个包含该时间戳的waterMark,插入到消息流中输出到flink流处理系统中,;flink operator算子按照时间窗口缓存所有流入的消息,当操作符处理到waterMark时,它对所有小于该waterMark时间戳的时间窗口的数据进行处理并发送到下一个操作符节点,然后也将waterMark发送到下一个操作符节点。
产生方式:punctuated-数据流中每一个递增的eventtime都会产生一个waterMark,但是这样会产生大量的waterMark在一定程度上对下游算子造成压力,故只有在实时性要求非常高的场景才会选择punctuated的方式进行waterMark的生成;periodic-周期性的(一定时间间隔或者达到一定的记录条数)产生一个waterMark;在实际的生产中periodic的方式必须结合时间和积累条数两个维度继续周期性产生waterMark,否则在极端情况下会有很大的延时。
6. flink的累加器、广播变量和分布式缓存
累加器:可以在分布式统计数据,只有在任务结束之后才能获取累加器的最终结果;计数器是累加器的具体实现,有intcounter、longcounter和doublecounter;注意点:需要在算子内部创建累加器对象;通常在Rich函数中的open方法中注册累加器,指定累加器的名称;在当前算子内任意位置可以使用累加器;必须当任务执行结束后,通过env.execute(xxx)执行后的jobexecutionresult对象获取累加器的值。
广播变量:数据集合通过withBroadcastSet进行广播;可通过getruntimecontext().getbroadcastvariable访问。
分布式缓存:flink提供了一个分布式缓存,类似于hadoop;执行程序时,flink会自动将文件或目录赋值到所有worker的本地文件系统;用户函数可以查找指定名称下的文件或目录,并从worker的本地文件系统访问它。
7. 容错机制
Flink提供了一种容错机制,可以持续恢复数据流应用程序的状态,确保即使出现故障,经过恢复,程序的状态也会回到以前的状态;支持at least once语义和exactly once语义;flink通过定期地做checkpoint来实现容错和恢复,容错机制不断地生成数据流的快照;流应用程序的状态在一个可配置的地方;如果出现程序故障,flink将停止分布式流数据流,然后系统重新启动operator,并将其设置为最近一批的检查点;
flink的容错机制的核心部分是生成分布式数据流和operator状态一致的快照;这些快照充当检查点,系统可以在发生故障时将其回滚;分布式快照是由chandy-lamport算法实现的。
Flink的分布式快照的核心元素是stream barriers;这些barriers被注入到数据流中,作为数据流的一部分和其他数据一同流动,barriers不会超过其他数据提前到达;一个barrier将数据流中的数据分割成两个数据集,即进入当前快照的数据和进入下一次快照的数据;每个barrier带有一个id,该id为将处于该barrier之前的数据归入快照的检查点的id;barrier不会打断数据流的流动,所以它是十分轻量级的;来自不同的快照的多个barrier可以统一时间存在于统一个流中,也就是说,不同的快照可以并行同时发生;barrier是在source处被插入到数据流中的。
这些barrier随数据流流动向下游,当一个中间operator在其输入流接收到快照n的barrier时,它在其所有的输出流中都发送一个快照n的barrier;当一个sink operator(流DAG的终点)从其输入流接收到n的barrier,它将快照n通知给checkpoint coordinator(协调器);在所有sink都通知了一个快照后,这个快照就完成了;当快照n完成后,由于数据源中先于sn的数据已经通过了整个 data flow topology,我们就可以确定不再需要这些数据了。
恢复数据:flink选择最近的已经完成的检查点k,系统接下来重部署整个数据流图,然后给每个operator在检查点k时的相应状态;数据源则被设置为从数据流sk位置开始读取。
先决条件:对于flink的checkpoint机制一般来说,它需要:持续的数据源;状态存储的持久化,通常是分布式文件系统。
启用和配置检查点:默认情况下,禁用checkpoint;开启方式:调用env.enablecheckpointint(n),其中n是以毫秒为单位的检查点间隔。
8. 状态保存
流计算中在以下场景中需要保存状态:窗口操作;使用了KV操作的函数;继承了checkpointedfunction的函数。
当检查点机制启动时,状态将在检查点中持久化来应对数据丢失以及恢复;状态是如何持久化到检查点中以及持久化到哪里都取决于选定的state backed。
Flink在保存状态时,支持三种存储方式:memorystatebacked、fsstatebacked和rockedbstatebacked;若没有配置其他任何内容,系统默认使用memorystatebacked。
Memorystatebacked,此种存储策略将数据保存在java堆里,当进行checkpoint时,这种策略会对状态做快照;然后将快照作为checkpoint中的一部分发送给JobManager,JM也将其保存在堆中;避免阻塞,使用异步的方式进行快照;单次状态大小最大默认被限制5MB,这个值可以通过构造函数来更改;不论单次状态大小最大被限制为多少,都不可以大过akka的frame大小;聚合的状态都会写入JM的内存;适合用于本地开发和调试;状态比较少的作业等场景下。
fsstatebacked通过文件系统的URL来设置,当选择它时,会先将数据保存在任务管理器(taskmanager)的内存中,当做checkpointing时,会将状态快照写入文件。保存在文件系统;少量的元数据会保存在JM的内存中,默认配置为提供异步快照,以避免在写入状态检查点时阻塞处理管道;使用场景:状态比较大,窗口比较长、大的KV状态;需要做HA的场景。
rocksdbstatebackend通过文件系统的URL来设置;此种方式KV state需要由rockdb数据库来管理和保存数据,该数据库保存在taskmanager的数据目录中;rockdb是一个高性能的K-V数据库;数据会先放到内存中,在一定条件下触发写到磁盘文件上;在checkpoint时,整个rockdb数据库的数据会快照一份,然后存到配置文件系统中;同时flink将溢写最小的元数据存储在Jobmanager的内存或zookeeper中;默认配置为执行异步快照;使用场景:非常大的状态,长窗口,大的KV状态、需要HA的场景;它是目前唯一可用于支持有状态流处理应用的增量检查点。
rocksdbstatebackend能够持有的状态的多少只取决于可使用的磁盘的大小,允许使用非常大的状态,但吞吐量会受限。
Checkpoint的使用:程序的运行过程中会每隔env.enablecheckpointing(5000)时间产生一个checkpoint快照点,当程序失败,我们重启时,可以指明从哪个快照点进行恢复。
9. 讲讲savepoint
Savepoint由用户创建、拥有和删除;一般是有计划的进行手动备份和恢复;比如说有时候flink版本更新或者更改流处理逻辑,更改并行度等等,这个时候我们往往需要关闭一下流,这就需要我们将流中的状态进行存储;从概念上讲,savepoint的生成和恢复成本可能更高,并且更多地关注可移植性和对前面提到的作业更改的支持;保存命令:flink savepoint jobid target_directory。
10. operator chains--操作链
Flink处于分布式执行的目的,将operator的subtask链接在一起形成task(类似于spark中的管道);每一个task在一个线程中执行;将operator链接成task时非常有效的优化:它可以减少与线程间的切换户数据缓冲的开销,并在降低延迟的同事提高整体吞吐量。
Flink默认会将多个operator进行串联,形成任务链;我们也可以禁用任务链让每个operator形成一个task。
操作链其实就是类似spark的pipeline管道模式,一个task可以执行同一个窄依赖中的算子操作。
11. task slots--任务槽
Taskmanager是一个JVM进程,并会以独立的线程来执行一个task或多个subtask;为了控制一个taskmanager能接受多少个task,flink提出了task slot的概念。
每个task slot代表了taskmanager的一个固定大小的资源子集,会平均分配资源;将资源你slot化意味着来自不同job的task不会为了内存而竞争,而是每个task都拥有一定数量的内存储备;这里不会涉及到CPU的隔离,slot目前仅仅用来隔离task的内存。
每个taskmanager有一个slot,也就意味着每个task运行在独立的JVM中;每个taskmanager有多个slot的话,也就是说多个task运行在同一个JVM中;同一个JVM中的task可以共享TCP连接和心跳消息,可以减少数据的网络传输,也能共享溢写数据结构,一定程度上减少了每个task的消耗。
12. flink的一些其他知识点
(1)、flink提供记录历史任务运行情况的服务;
(2)、连接器:flink中内置了溢写基本数据源和接收器,Apache Kafka (source/sink);Elasticsearch (sink);Hadoop FileSystem (sink);RabbitMQ (source/sink);Apache NiFi (source/sink);Apache Cassandra (sink);Amazon Kinesis Streams (source/sink);Twitter Streaming API (source);这些连接器中,当启动了flink的容错机制之后,它分别能够保证不同的语义。
(3)、flink exactly once的实现需要两个阶段的提交;需要实现四种主要方法:开启一个事务;在预提交阶段,将本次事务的数据缓存起来,同时开启一个新事务执行属于下一个checkpoint的写入操作;在commit阶段,我们以原子性的方式将上一阶段的数据整整的写入到存储系统;一旦异常终止事务,程序的处理过程。
(4)、flink的CEP:是flink的复杂处理库;它允许用户快速检测数据流中的复杂事件模式;首先需要用户创建定义一个个pattern,然后通过链表将由前往后逻辑关系的pattern串在一起,构成模式匹配的逻辑表达;在事件流中药应用模式匹配,必须实现呢适当的equals和hashcode方法,因为flinkCEP用它们来比较和匹配事件。
(5)、flink支持table API以及批处理情况下的SQL语句和流处理情况下sql运距查询分析
13.flink与kafka整合
(1)、flink消费kafka数据起始offset配置:1.flinkKafkaConsumer.setStartFromEarliest()--从topic的最早offset位置开始处理数据,如果kafka中保存有消费者组的消费位置将被忽略;flinkKafkaConsumer.setStartFromLatest()--从topic的最新offset位置开始处理数据,如果kafka中保存有消费者组的消费位置将被忽略;flinkKafkaConsumer.setStartFromTimestamp(…)--从指定的时间戳(毫秒)开始消费数据,Kafka中每个分区中数据大于等于设置的时间戳的数据位置将被当做开始消费的位置。如果kafka中保存有消费者组的消费位置将被忽略;flinkKafkaConsumer.setStartFromGroupOffsets()--默认的设置。根据代码中设置的group.id设置的消费者组,去kafka中或者zookeeper中找到对应的消费者offset位置消费数据。如果没有找到对应的消费者组的位置,那么将按照auto.offset.reset设置的策略读取offset。
(2)、flink消费kafka数据,消费者offset提交配置:Flink提供了消费kafka数据的offset如何提交给Kafka或者zookeeper(kafka0.8之前)的配置;注意,Flink并不依赖提交给Kafka或者zookeeper中的offset来保证容错。提交的offset只是为了外部来查询监视kafka数据消费的情况;配置offset的提交方式取决于是否为job设置开启checkpoint。可以使用env.enableCheckpointing(5000)来设置开启checkpoint;关闭checkpoint:如何禁用了checkpoint,那么offset位置的提交取决于Flink读取kafka客户端的配置,enable.auto.commit配置是否开启自动提交offset;auto.commit.interval.ms决定自动提交offset的周期;开启checkpoint:如果开启了checkpoint,那么当checkpoint保存状态完成后,将checkpoint中保存的offset位置提交到kafka。这样保证了Kafka中保存的offset和checkpoint中保存的offset一致,可以通过配置setCommitOffsetsOnCheckpoints(boolean)来配置是否将checkpoint中的offset提交到kafka中(默认是true)。如果使用这种方式,那么properties中配置的kafka offset自动提交参数enable.auto.commit和周期提交参数auto.commit.interval.ms参数将被忽略。