|
| 1 | +1.Hive数据倾斜 |
| 2 | +造成的原因: |
| 3 | +(1)key值分布不均匀 |
| 4 | +(2)业务数据不均匀 |
| 5 | +比如少数数据过少,另外数据过多 |
| 6 | +分桶字段的空值过多 |
| 7 | +(3)建表时考虑不周 |
| 8 | +(4)某些SQL本身就有数据倾斜 |
| 9 | +比如:join的相关操作、groupby的相关使用、count(distinct)某些特殊值过多 |
| 10 | +解决方案: |
| 11 | +(1)参数方面调节 |
| 12 | +a.hive.map.aggr=true,map端的预聚合,相当于combiner |
| 13 | +b.hive.groupby.skewindata=true,有数据倾斜的时候自动进行负载均衡,当选定true是会生成查询 |
| 14 | +计划会有两个job,第一个map job中的map输出结果集会随机分发到reduce中,到reduce端做部分聚合 |
| 15 | +这样reduce输出的结果是等量的,groupbykey有可能被分发到不同的key中,从而达到负载均衡,第二个 |
| 16 | +map job将预处理的结果完成最后的结果聚合 |
| 17 | +(2)sql方面的调节 |
| 18 | +a.选取key分布比较均匀的表作为驱动表,然后将表加载到内存再与其他表进行join |
| 19 | +b.大小表join时,让小表先进内存,然后再与大表进行join |
| 20 | +c.大表join大表时,将有空值的key加上随机数,将倾斜的数据分布到不同的redcue上, |
| 21 | +d.count distinct 大量相同的特殊值,将key为空的数据单独处理 |
| 22 | +e.如果导致倾斜的数据对计算的结果没有太大的影响可以直接加where调节过滤掉,或者 |
| 23 | +将这些结果单独处理 |
| 24 | +2.Hive的外部表和内部表区别、分桶、分区 |
| 25 | +内部表和外部表的区别: |
| 26 | +创建: |
| 27 | +内部表创建时不需要指定数据存储目录,直接默认存储在user/hive/warehouse |
| 28 | +外部表创建时需要自己指定数据存储目录 |
| 29 | +删除表: |
| 30 | +内部表删除时,直接将数据和元数据直接删除了 |
| 31 | +外部表删除时,只是将元数据删除了 |
| 32 | +修改: |
| 33 | +内部表对分区和表结构进行修改时,会直接同步给元数据 |
| 34 | +外部表对分区和表结构进行修改时,不会同步给元数据,需要修复元数据,msck repair table_name |
| 35 | +3.你们公司Hive中metastore元数据仓库里放的什么数据? |
| 36 | +业务数据映射成表,存放这些表的表名、字段、分区、location等 |
| 37 | +4.你们公司使用Hive元数据的服务是什么? |
| 38 | +hiveserver2 |
| 39 | +beeline -u jdbc:hive2://[ip]:10000/db_name -nroot password |
| 40 | + |
| 41 | +!connect |
| 42 | + beeline jdbc:hive2://[ip]:10000/db_name -nroot |
| 43 | +5.Hbase架构原理、优化 |
| 44 | +Hbase架构: |
| 45 | +client:提交请求 |
| 46 | +zookeeper:存储-root表,root表里存储着-meta表的信息位置信息,以及regoin的元数据信息 |
| 47 | +master:协调regoinServer,当regoinServer挂掉时,让其他regoinServer去寻找存储在HDFS上的数据 |
| 48 | +重新加载到内存 |
| 49 | +regoinServer:regoin是存储在regoinServer节点上的 |
| 50 | +regoin:也就是表,一张大表存储数据到达一定的阈值时可以分裂成很多个regoin,存放在regoinServer上 |
| 51 | +memtore:内存缓冲,当写数据时,首先进入memtore中 |
| 52 | +hlog(wal):预写日志,将数据写入memtore是会向HLOG中写,这样即使memtore中的数据即使丢了, |
| 53 | +也可以通过HLOG恢复 |
| 54 | +storeflile:溢写后的文件,有hfile组成 |
| 55 | +hfile:memstore中的数据达到一定阈值后溢写,溢写成HFile文件 |
| 56 | + |
| 57 | +Regoin的分裂设置: |
| 58 | +在hbase0.96中,默认状态下,分裂策略是IncreasingToupperBoundRegoinSplitPolicy, |
| 59 | +即根据table的regoin个数的平方乘以memstore flush size的大小, |
| 60 | +比如:memstore内存大小是128M,第一次flush就分裂,因为regoin就一个,分裂成两个regoin |
| 61 | +后,下次分裂regoin的size就是2*2*128=512M,达到512M时才进行分裂 |
| 62 | + |
| 63 | +如果想regoin很大程度上不分列,可以设置参数 |
| 64 | +第一,改变策略,设置参数 |
| 65 | +第二,设置regoin内部storefile的最大值,在参数中设置storefile的最大值 |
| 66 | + |
| 67 | +HBase优化: |
| 68 | +1).提前创建regoin,在创建表时默认会创建一个regoin分区,当这个分区中的数据足够大时,才进行分割,切割的时候 |
| 69 | +会造成效率低,所以可以提前创建一写regoin,这样在写入数据的时候,会按照分区情况在集群中做负载均衡 |
| 70 | +2).合理设计rowkey,比如最近写入的数据和可能会被经常访问,那么可以将时间戳作为rowkey的一部分, |
| 71 | +由于是按照字典序进行排序的,所以可以使用Long.MAX-timestamp作为可以(即long的最大值-最近时间), |
| 72 | +这样就能保证读取数据时会被迅速命中 |
| 73 | +3).1-2个列族,因为在flush的时候,临近的列族会被关联而出发flush |
| 74 | +4).创建表的时候可以通过设置参数,将表放到内存中,快速命中、高效读取 |
| 75 | +5).compact和split,在memtore达到一定阈值溢写成storefile时,会出发major compact,将多个storefile合并成一个 |
| 76 | +大的storefile文件,他们是按照rowkey进行合并的,合并是非常影响效率的,可以将storefile调大一点 |
| 77 | +6)auto flush:自动flush,可以将自动关闭,HTable.setAutoFlush(false),不会有一条put就执行一次flush, |
| 78 | +当自动flush关闭时,只有填满缓存时,才会向HBase进行写请求 |
| 79 | +7)关闭WAL LOG,提高效率,安全性降低了 |
| 80 | +8)通过设置参数,进行多并发读,批量读 |
| 81 | +6.Redis中key的设计规则? |
| 82 | +在保证唯一性的情况下,使用表名:列名:的形式 |
| 83 | +比如说:“user:userid:9:username” |
| 84 | +7.Redis架构原理、搭建? |
| 85 | +K-V格式的内存数据库,支持的数据结构有string,list、set、hash、sorted set(有序集合) |
| 86 | +主从架构master-slave,只要是遵循主从复制的机制,当数据写入redis的master主时,slaves会将master中的数据copy一份,这样 |
| 87 | +使得所有slave具有与master相同的数据master节点允许用户的写入数据权限,slaves只允许读数据。 |
| 88 | + |
| 89 | +redis主从使得读写分离,主从架构同步造成高并发的访问 |
| 90 | + |
| 91 | +Redis的持久化: |
| 92 | +RDB快照:支持将当前数据存成一个数据文件的持久化机制,如何生成快照?采用fork命令的copy or write写时复制机制, |
| 93 | +在生成快照是将当前进程fork出一个子进程,在子进程中循环所有数据,将所有数据写成RDB文件,可以通过save命令来 |
| 94 | +配置生成快照的时机,RDB中数据不是全新,没有达到生成快照的时机时,挂机会造成数据丢失。 |
| 95 | +AOF(append only file):追加写日志的文件,aof文件是可识别的纯文本,内容是一个个的redis的标准命令,不是所有 |
| 96 | +的redis命令,只是那些修改的命令才会追加到aof文件中。没一条修改数据的命令都会生成一条记录,存到aof文件中, |
| 97 | +那么这个文件会很大的,这是redis有提供了新的机制,aof rewrite 就是重新生成一个aof文案,新的aof文件中,对对同一条数据的 |
| 98 | +操作又一次,不会像旧的那样,记录同一条记录的多个修改命令。 |
| 99 | + |
| 100 | +8.Kafka为什么数据传输快? |
| 101 | +1)顺序写入, |
| 102 | +2)memory mapped files:内存映射文件,数据时直接从磁盘使用DMA传输到内核空间的paceCache中,这块对这块空间进行共享, |
| 103 | +用户空间不需要将数据进行copy拷贝到应用程序缓冲区。 |
| 104 | + |
| 105 | +流程:1.调用read函数,文件数据copy到内核缓冲区 |
| 106 | + 2.read函数返回,文件数据从内核缓冲区拷贝到用户缓冲区 |
| 107 | + 3.write函数调用,将文件数据从用户缓冲区copy到内核与socket相关的缓冲区 |
| 108 | +9.Spark数据倾斜、GC调优?公司用那种GC策略 |
| 109 | +数据倾斜: |
| 110 | +(1)业务数据本身的数据倾斜 |
| 111 | +(2)数据倾斜 |
| 112 | +10.Spark中checkpoint和persist的区别 |
| 113 | +checkpoint:将数据持久化到磁盘,外部系统 |
| 114 | +persist:可以将RDD持久化到磁盘,也可以将RDD持久化到内存,可以随意设置RDD的持久化级别 |
| 115 | +使用场景:某个步骤计算特别耗时、计算链条特别长 |
| 116 | +cache:放在内存中只有一份副本,只放在内存的heap中,不会保存在什么目录或者HDFS上,有可能在很多机器的内存中,有可能在 很一台机器的内存上 |
| 117 | +cache之后不能立即有其他算子,因为在实际工作的过程中,cache后有算子的话,每次都会触发这个计算过程,cache不能让指定 |
| 118 | +机器做缓存,是框架自动做的, |
| 119 | + |
| 120 | +11.Spark中broadcast的传输过程 |
| 121 | +广播变量只能有Driver端中的SparkContext来执行并且发送到Executor中,Executor中的task会共享者一个变量副本,只能执行读操作 |
| 122 | +不会执行写操作,写操作只能是在Driver端进行执行的。 |
| 123 | +12.公司中Spark用的是哪种shuffle? |
| 124 | +13.如何避免Spark Shuffle? |
| 125 | +Spark shuffle使由shuffle类的算子所产生的,所以说是尽量避免产生shuffle类的算子,比如说reducebykey、Join类的算子,都会触发shuffle操作 |
| 126 | +shuffle性能差的原因: |
| 127 | +shuffle过程中,各个节点上的相同的key会先写入本地文件中,然后通过其他节点需要通过网络传输拉取各个节点上磁盘中相同key的 |
| 128 | +而且将相同的key拉取到同一个节点进行聚合时, 还有一个可能就是相同的key过多,导致节点内存不够,进而溢写到磁盘上去, |
| 129 | +因此在shuffle过程中,会有大量的触发IO的操作,以及数据的网络间传输,磁盘IO和网络数据传输这些就会导致shuffle操作性能低下的原因 |
| 130 | +1)使用广播变量+filter,broadcast+map当两个表进行join的时候,如果一个两个不同大小表进行join的时候,可以小大表广播出去,再进行filter |
| 131 | + |
| 132 | +14.你们公司中Spark任务在哪个资源框架上提交?说一下提交流程 |
| 133 | +Spark on Yarn: |
| 134 | + 1.集群启动,Executor进行汇报资源,反向注册给ResourceManager |
| 135 | + 2.客户端进行提交Spark Applicatioin任务,并向ResourceManager申请一个ApplicationMaster。 |
| 136 | + 3.ResourceManager接收客户端提交请求后,分配一个NodeManager去启动AppMaster |
| 137 | + 4.在NodeManager上启动一个AppMaster(这个AppMaster可以看做是一个Driver) |
| 138 | + 5.开始初始化Driver启动初始化SparkCOntext,由于提交的job是一系列的RDD组成的,这些RDD会形成DAG有向无环图, |
| 139 | + 由DAGScheduler去根据RDD之间的宽窄依赖划分成一个个Stage,这些Stage形成了一个个的Task,形成了TasKSet,发送给 |
| 140 | + TaskScheduler. |
| 141 | + 6.TaskScheduler接收到TaskSet之后,根据所要执行的Task个数计算所有执行的资源,Driver向ResourceManager去申请资源。 |
| 142 | + 7.ResourceManager接收到Driver的资源请求之后,根据请求分配一批NodeManager,去启动Executor。 |
| 143 | + 8.NodeManager启动自己要执行作业的Executor后,向Driver进行反向注册。 |
| 144 | + 9.Driver掌握了所要执行的Executor资源后,TaskScheduler将TaskSet中的Task任务遍历分发到Executor中的, |
| 145 | + 10.Executor中的ThreadPool线程池接收到Task后开始执行,将执行后的结果发送给Driver |
| 146 | + 11.Driver进行结果的回收、Task任务的执行、Task任务的发送 |
| 147 | +15.DataSet、DataFrame、RDD三者的区别 |
| 148 | +相同点:三者都是Spark平台下的分布式弹性数据集,为处理大数据提供提供了遍历 |
| 149 | + 三者都是惰性机制,只有遇到action触发算子的时候,才会执行, |
| 150 | +区别: |
| 151 | + RDD: |
| 152 | + RDD一般和Spark mrlib使用 |
| 153 | + RDD不支持sql操作 |
| 154 | + Spark不了解RDD内部详细的数据结构 |
| 155 | + DataFrame: |
| 156 | + DataFrame每一行都固定为Row,只有通过解析才能获取各个字段的值,支持Spark Sql操作,还能注册临时表、视图等操作 |
| 157 | + 支持一些比较方便的保存方式,比如csv。 |
| 158 | + DataSet: |
| 159 | + DataFrame和DataSet拥有完全相同的成员函数,区别是每一行数据类型是不同的. |
| 160 | + DataSet[Row]就是DataFrame,每一行的类型是ROW,不解析,每一行有那些字段也不知道的,只能利用getAS()的方式获取对应的属性字段 |
| 161 | + |
| 162 | + DataFrame是非常好用的,即DataSet[Row],知道其中的各个字段可以通过sql进行操作。对具体字段进行解析 |
| 163 | + |
| 164 | + 转换: |
| 165 | + DataFrame、DataSet转RDD:直接点RDD,testDF.rdd;testDS.rdd; |
| 166 | + RDD转DataFrame:首先导包:import spark.implicits._ 调用toDF方法, |
| 167 | + RDD转DataSet:首先定义一个case class 样例类,直接toDS |
| 168 | + DataSet转DataFrame:把case class 分装成Row类型,直接调用toDF, |
| 169 | + |
| 170 | + |
| 171 | +16.Spark资源优化 |
| 172 | +Executor的内存主要分为三块: |
| 173 | + 第一块就是task执行代码时所使用的,占比20% |
| 174 | + 第二块就是Spark Shuffle时,下一个stage拉取上一个stage的结果,进行聚合时使用的,占比20% |
| 175 | + 第三块RDD进行持久化时进行使用,默认占比60% |
| 176 | + |
| 177 | + |
| 178 | +触发bypass shuffle机制的算子有: |
| 179 | +repartition、coalase、sortbykey |
0 commit comments