大数据知识

浏览量(PV)、访客数(UV)

大数据(Big Data)4V特征(即Volume、Variety、Value、Velocity)
一是数据体量巨大(Volume)。
二是数据类型繁多(Variety)。
三是价值密度低(Value)。
四是处理速度快(Velocity)

OLAP和OLTP简介(https://blog.csdn.net/weixin_45568892/article/details/105621715)
联机事务处理 OLTP(On-Line Transaction Processing) 【传统的关系型数据库】
联机分析处理 OLAP(On-Line Analytical Processing) 【数据仓库系统】

★★
柯里化是将原先一次性接受的参数,改成了链式接受的形式
def mul(x: Int)(y: Int) = x * y //定义柯里化函数
mul(6)(7) //调用柯里化函数

★★★★★★
不能将RDD广播出去,RDD不存数据,可以将RDD的结果广播出去,rdd.collect()
但是DataFrame和变量可以直接广播,因为DataFrame不一定是分布式的,他提供了islocal方法,它收集数据创建本地对象,然后广播它。
广播变量只能在Driver定义,因为SparkContext没有被序列化不能被发送到Executor端,在Executor端不能修改广播变量的值。
广播变量更新方法:spark 广播变量可以通过unpersist方法删除,然后重新广播

★★★★★★
checkpoint:将DAG中比较重要的中间数据做一个检查点将结果存储到HDFS中,当下游RDD计算出错时,可直接从checkpoint过的rdd那里读取数据继续计算。
checkpoint时会将rdd的血缘关系去掉,persist/cache的时候是将数据做缓存,lineage是保持完好的,如果cache的rdd某些分区丢失,可以按照lineage重新计算
checkpoint是transformation算子,而且checkpoint是在另外的job中单独计算的,所以建议使用checkpoint的时候应该先cache然后做checkpoint,避免重复计算,
先cache()再checkpoint()就会取刚cache到内存中的数据写入hdfs
checkpoint写入流程:setCheckpointDir() 创建hdfs目录
rdd.checkpoint() rdd需要经过 Initialized --> CheckpointingInProgress–> Checkpointed 这几个阶段才能完成checkpoint
runJob()触发checkpoint()
写入数据到CheckpointDir
checkpoint读取流程:task执行失败的时候会触发
executor执行task时,比如ShuffleMapTask,会调用rdd.iterator(partition, context)在每个分区上执行用户自定义的函数序列,RDD.iterator()执行分区上的计算任务时,如果RDD被cache了,就读取cache的分区进行计算,否则就computeOrReadCheckpoint()

★★★★★★★★★★★★★
https://www.cnblogs.com/blair-chen/p/6538741.html
https://www.cnblogs.com/jxhd1/p/6528517.html
spark调优:开发调优,资源调优

开发调优:RDD lineage设计、算子的合理使用、特殊操作的优化
1.避免创建重复的RDD,
2.尽可能复用同一个RDD
3.对多次使用的RDD进行持久化,cache()和persist(),持久化策略选择,memory_only --> memory_only_ser --> memory_and_disk_ser --> disk_only和后缀为_2的级别(不推荐)
4.尽量避免使用shuffle类算子,可用broadcast+map来替换join
5.使用map-side预聚合的shuffle操作,使用reduceByKey或者aggregateByKey算子来替代掉groupByKey
6.使用高性能的算子:使用reduceByKey/aggregateByKey替代groupByKey,使用mapPartitions替代普通map,使用foreachPartitions替代foreach,使用filter之后进行coalesce操作,使用repartitionAndSortWithinPartitions替代repartition与sort类操作
7.广播大变量,保证每个Executor的内存中,只驻留一份变量副本
8.使用Kryo优化序列化性能
9.优化数据结构

资源调优:driver-memory Driver的内存通常来说不设置,或者设置1G左右应该就够了。唯一需要注意的一点是,如果需要使用collect算子将RDD的数据全部拉取到Driver上进行处理,那么必须确保Driver的内存足够大,否则会出现OOM内存溢出的问题。
spark.default.parallelism:task的并行度,建议设置为num-executors * executor-cores的2~3倍较为合适
spark.default.parallelism 任务并行度,spark.executor.memoryOverhead 堆外内存

数据倾斜调优
数据倾斜发生时的现象:个别task特别慢,oom
数据倾斜发生的原理:热点数据,个别key的数据量特别大
如何定位导致数据倾斜的代码:只发生在shuffle过程中,查看spark web ui某个task执行时间长,处理的数据量大;内存溢出报错的直接看日志定位到代码行
查看导致数据倾斜的key的数据分布情况:sql统计表的key分布情况,pairs.sample(false, 0.1).countByKey().foreach(println(_))打印rdd的key分布
数据倾斜的解决方案:(https://www.cnblogs.com/frankdeng/p/9301695.html)
1.使用Hive ETL预处理数据,提前在hive中做一个预聚合,但是治标不治本,在hive阶段还是会发生数据倾斜
2.过滤少数导致倾斜的key,对于计算结果不重要的key可以过滤掉,比如null值
3.提高shuffle操作的并行度,减少每个task执行的数据量,但只是缓解了数据倾斜而已,没有彻底根除某个热点key的问题
需要设置一个参数,即spark.sql.shuffle.partitions,该参数代表了shuffle read task的并行度,该值默认是200,对于很多场景来说都有点过小。
4.两阶段聚合(局部聚合+全局聚合):仅适用于聚合类操作,reducebykey或group by
将原本相同的key通过附加随机前缀的方式,变成多个不同的key,就可以让原本被一个task处理的数据分散到多个task上去做局部聚合,进而解决单个task处理数据量过多的问题。接着去除掉随机前缀,再次进行全局聚合,就可以得到最终的结果
5.将reduce join转为map join:只适用于一个大表一个小表的情况,广播小表,如果是大表内存放不下。广播小RDD全量数据+map算子来实现与join同样的效果
6.采样倾斜key并分拆join操作:适用于一张表有热点key,另一张表分布均匀,且是少量热点key
对于join导致的数据倾斜,如果只是某几个key导致了倾斜,可以将少数几个key分拆成独立RDD,并附加随机前缀打散成n份去进行join,此时这几个key对应的数据就不会集中在少数几个task上,而是分散到多个task进行join了
7.使用随机前缀和扩容RDD进行join:适用于一张表有热点key,另一张表分布均匀,但是这次存在大量热点key,过滤处理的话没有意义
和方案6一样,只不过是全表加n以内的随机前缀,对均匀的表进行相同扩容成n条,然后再join
8.以上多种方案组合使用
shuffle调优:(https://blog.csdn.net/qiuhui19941118/article/details/60608759)

shuffleManager的发展:hashShuffleManager(产生大量的中间磁盘文件) --> sortShuffleManager(会将临时文件合并只生成一个磁盘文件,和索引文件)
sortShuffleManager下数据会先写入一个内存数据结构中,如果是reduceByKey这种聚合类算子就写入Map数据结构,如果是join这种普通算子就写入Array数据结构;如果内存达到某个临界值,就会溢写磁盘,溢写之前会先根据key对内存数据结构中的数据进行排序,排序过后会分批将数据写入磁盘文件。一个task将所有数据写入内存数据结构的过程中,会发生多次磁盘溢写操作,也就会产生多个临时文件。最后会将之前所有的临时磁盘文件都进行合并,这就是merge过程。还会单独写一份索引文件,其中标识了下游各个task的数据在文件中的start offset与end offset。
bypass机制:shuffle read task数量小于spark.shuffle.sort.bypassMergeThreshold参数的值。不是聚合类的shuffle算子(比如reduceByKey)。写机制其实跟未经优化的HashShuffleManager是一模一样的,因为都要创建数量惊人的磁盘文件,只是在最后会做一个磁盘文件的合并而已。不会进行排序,性能开销会小一点。
shuffle相关参数调优:spark.shuffle.file.buffer、spark.reducer.maxSizeInFlight、spark.shuffle.io.maxRetries、spark.shuffle.io.retryWait、spark.shuffle.memoryFraction、spark.shuffle.manager、spark.shuffle.sort.bypassMergeThreshold、spark.shuffle.consolidateFiles。

★★★★
RDD的五大特性
1.a list of partiotioner有很多个partiotioner(这里有3个partiotioner),可以明确的说,一个分区在一台机器上,一个分区其实就是放在一台机器的内存上,一台机器上可以有多个分区。

2.a function for partiotioner一个函数作用在一个分区上。比如说一个分区有1,2,3 在rdd1.map(_*10),把RDD里面的每一个元素取出来乘以10,每个分片都应用这个map的函数

3.RDD之间有一系列的依赖rdd1.map(_*10).flatMap(…).map(…).reduceByKey(…)构建成为DAG,这个DAG会构造成很多个阶段,这些阶段叫做stage,RDDstage之间会有依赖关系,后面根据前面的依赖关系来构建,如果前面的数据丢了,它会记住前面的依赖,从前面进行重新恢复。每一个算子都会产生新的RDD.textFile 与flatMap会产生两个RDD.

4.分区器hash & Integer.Max % partiotioner 决定数据到哪个分区里面,可选,这个RDD是key-value 的时候才能有

5.最佳位置。
数据在哪台机器上,任务就启在哪个机器上,数据在本地上,不用走网络。不过数据进行最后汇总的时候就要走网络。(hdfs file的block块)

★★★★
DataSet\DataFrame\RDD的区别:
(1)相同点:
都是分布式数据集
DataFrame底层是RDD,但是DataSet不是,不过他们最后都是转换成RDD运行
DataSet和DataFrame的相同点都是有数据特征、数据类型的分布式数据集(schema)
(2)不同点:
(a)schema信息:
RDD中的数据是没有数据类型的
DataFrame中的数据是弱数据类型,不会做数据类型检查
虽然有schema规定了数据类型,但是编译时是不会报错的,运行时才会报错
DataSet中的数据类型是强数据类型
(b)序列化机制:
RDD和DataFrame默认的序列化机制是java的序列化,可以修改为Kyro的机制
DataSet使用自定义的数据编码器进行序列化和反序列化

★★★★★★
Spark中shuffle类算子
distinct、reduceByKey、groupByKey、aggregateByKey、combineByKey、sortByKey、coalesce、repartition、join、subtract、subtractByKey

★★★★
Case : wordcount
val textFile = sc.textFile(args(1))
val result = textFile.flatMap(line => line.split("\s+")).map(word => (word, 1)).reduceByKey(_ + _)
println(result.collect().mkString(","))
result.saveAsTextFile(args(2))

★★
spark中涉及到序列化的三个地方:1.算子函数中使用到外部变量,该变量会被序列化后进行网络传输(广播大变量)
2.将自定义的类型作为RDD的泛型类型时,所有自定义类型对象,都会进行序列化。要求自定义的类必须实现Serializable接口
3.使用可序列化的持久化策略时(比如MEMORY_ONLY_SER),Spark会将RDD中的每个partition都序列化成一个大的字节数组。
// 创建SparkConf对象。
val conf = new SparkConf().setMaster(…).setAppName(…)
// 设置序列化器为KryoSerializer。
conf.set(“spark.serializer”, “org.apache.spark.serializer.KryoSerializer”)
// 注册要序列化的自定义类型。
conf.registerKryoClasses(Array(classOf[MyClass1], classOf[MyClass2]))

★★
map和mapPartitions:map 算子可以理解为 mapPartitions 的一个高级封装,源码都是作用在MapPartitionsRDD 的迭代器。
普通场景 mapPartitions 和 map 没什么区别(map每次只读取一个,mapPartitions是每次读取一批数据,当数据量比较大时,可能会造成OOM)
mapPartitions的问题:写代码不方便,容易造成OOM
mapPartitions用法:一对一,一个分区只会被调用一次的特性(写数据库)
完全没必要刻意使用 mapPartitions,一般推荐使用 map 算子
https://www.jianshu.com/p/ffa782798883

★★★★★★
select查询时cluster by相当于distribute by + order by,将字段按照hash分发到不同reducer中,然后保证每个reducer有序
而创建表时的clustered by表示:clustered by语句声明的字段中相同的内容会被分配到同一个reducer处理,并且为分桶提供依据。

★★★★★★
driver端是运行用户编写的application的main()函数的地方,具体负责DAG的构建,任务的划分,task的生成和调度。job,stage,task生成都离不开rdd自身,rdd的相关的操作不能缺少driver端的sparksession/sparkcontext。
executor是真正执行task地方,而task执行离不开具体的数据,这些task运行的结果可以是shuffle中间结果,也可以持久化到外部存储系统。一般都是将结果、状态等汇集到driver。但是,目前executor之间不能通信,相互独立,只能借助第三方来实现数据的共享或者通信。

★★★★★★
client:driver运行在本地机器上,所以client模式的客户端不能kill掉;client模式是本地机器负责调度Application,会与yarn集群产生大量的网络通信,引起网卡流量激增;但是在本地就可以看到所有log,方便调试;用于测试环境
cluster:driver进程是运行在yarn的某个nodeManager上,没有流量激增问题,本地看不到log

★★★★★★
spark on YARN-Cluster
在YARN-Cluster模式中,当用户向YARN中提交一个应用程序后,YARN将分两个阶段运行该应用程序:第一个阶段是把Spark的Driver作为一个ApplicationMaster在YARN集群中先启动;第二个阶段是由ApplicationMaster创建应用程序,然后为它向ResourceManager申请资源,并启动Executor来运行Task,同时监控它的整个运行过程,直到运行完成。

YARN-cluster的工作流程分为以下几个步骤:

  1. Spark Yarn Client向YARN中提交应用程序,包括ApplicationMaster程序、启动ApplicationMaster的命令、需要在Executor中运行的程序等;

  2. ResourceManager收到请求后,在集群中选择一个NodeManager,为该应用程序分配第一个Container,要求它在这个Container中启动应用程序的ApplicationMaster,其中ApplicationMaster进行SparkContext等的初始化;

  3. ApplicationMaster向ResourceManager注册,这样用户可以直接通过ResourceManage查看应用程序的运行状态,然后它将采用轮询的方式通过RPC协议为各个任务申请资源,并监控它们的运行状态直到运行结束;

  4. 一旦ApplicationMaster申请到资源(也就是Container)后,便与对应的NodeManager通信,要求它在获得的Container中启动启动CoarseGrainedExecutorBackend,CoarseGrainedExecutorBackend启动后会向ApplicationMaster中的SparkContext注册并申请Task。这一点和Standalone模式一样,只不过SparkContext在Spark Application中初始化时,使用CoarseGrainedSchedulerBackend配合YarnClusterScheduler进行任务的调度,其中YarnClusterScheduler只是对TaskSchedulerImpl的一个简单包装,增加了对Executor的等待逻辑等;

  5. ApplicationMaster中的SparkContext分配Task给CoarseGrainedExecutorBackend执行,CoarseGrainedExecutorBackend运行Task并向ApplicationMaster汇报运行的状态和进度,以让ApplicationMaster随时掌握各个任务的运行状态,从而可以在任务失败时重新启动任务;

  6. 应用程序运行完成后,ApplicationMaster向ResourceManager申请注销并关闭自己。


carbondata
列存储格式和spark sql和dataframe深度结合
file header:文件头 保存存储格式的版本和模式信息
blocklet:最大容量64m,存储数据
file footer:文件尾 存储数据的索引和摘要
通过支持二级索引,提升查询性能,第一级:文件级索引,过滤hdfs block避免不必要的文件扫描,第二级:blocklet索引,过滤文件内部的blocklet
可以大大减少非必要的任务启动和非必要的磁盘io,但是也导致了压缩率的减少和入库时间的延长
和ORCFile与Parquet相比 在索引层面下了功夫,查询是很快,但也付出了代价

★★★
clickhouse快的原因(https://developer.aliyun.com/article/739804)
1.默认情况下主键跟排序键(由 ORDER BY 子句指定)相同。
因此,大部分情况下不需要再专门指定一个 PRIMARY KEY 子句
2.索引粒度默认是8192条数据进行一次记录 二分查找+遍历可以快速索引到指定的数据
3.数据sharding分片可以充分利用集群的大规模并行计算能力
4.支持分区的过滤和列级别的稀疏索引
存储和执行耦合,避免网络数据传输的开销
5.列式存储数据库
6.向量化的执行引擎:思想是均摊开销,一个批次(多行数据8192)调用一次计算引擎,每次调用的开销是相对恒定的,所以计算框架的总开销就减小了
高吞吐的写入:基于批次batch写入的,直接落盘,采用类似LSM tree的机构(对数据排序及拆分,能有效提升写吞吐),数据写入时是顺序append写,写入后会定期compaction压缩合并,小文件合并成大文件,压缩时也是多个段merge sort后顺序写回磁盘。顺序写充分利用了磁盘的吞吐能力。
通过主备复制提供了高可用能力,多个副本都是处于active模式,查询的时候根据query下发策略进行查询
动态代码生成,消除开销

★★★
hbase(https://blog.csdn.net/cqacry2798/article/details/87914415)
图解脉络https://download.csdn.net/download/qq_25073261/13012173

HBase 数据的内部结构大体如下:
一个 RegionServer 包含多个 Region,划分规则是:一个表的一段键值在一个 RegionServer 上会产生一个 Region。不过当某一行的数据量太大了(要非常大),HBase 也会把这个 Region 根据列族切分到不同的机器上去;
一个 Region 包含多个 Store,划分规则是:一个列族分为一个 Store,如果一个表只有一个列族,那么这个表在这个机器上的每一个 Region 里面都只有一个 Store;
一个 Store 里面只有一个 Memstore;
一个 Store 里面有多个 HFile,每次 Memstore 的刷写(flush)就产生一个新的 HFile 出来。(Memstore 存在的意义是维持数据按照 rowkey 顺序排列,而不是做一个缓存。)

kudu(https://blog.csdn.net/lingbo229/article/details/80359987)
图解脉络https://download.csdn.net/download/qq_25073261/13012173

架构
1个Table包含多个Tablet,其中Tablet的数量是根据hash或者是range进行设置的
1个Tablet中包含MetaData信息和多个RowSet信息,其中MetaData信息是block和block在data中的位置。
1个RowSet包含一个MemRowSet和多个DiskRowSet,其中MemRowSet用于存储insert数据和update后的数据,写满后会刷新到磁盘中也就是多个DiskRowSet中,默认是1G刷新一次或者是2分钟。
DiskRowSet用于老数据的mutation,比如说数据的更新操作,后台定期对DiskRowSet进行合并操作,删除历史数据和没有的数据,减少查询过程中的IO开销。
1个DiskRowSet包含1个BloomFilter,1个Ad_hoc Index,多个UndoFile、RedoFile、BaseData、DeltaMem
BloomFile:根据DiskRowSet中key生成一个bloom filter,用于快速模糊的定位某一个key是否在DiskRowSet中
Ad_hoc Index:是主键的索引,用于定位key在DiskRowSet中具体哪个偏移位置
BaseData:是MemRowSet flush下来的数据,按照列存储,按照主键有序
UndoFile:是BaseData之前的数据历史数据
RedoFile:是BaseData之后的mutation记录,可以获得较新的数据
DeltaMem:用于在内存中存储mutation记录,先写到内存中,然后写满后flush到磁盘,形成deltafile

★★★★★★★★★
重点看sqoop(集群分布式),次看datax(单机多线程)
sqoop是集成在hadoop平台的,sqoop任务底层是执行MapReduce作业(我们服务器性能不是很好,当执行同步任务时,会与spark离线处理抢占资源)

★★★(https://www.cnblogs.com/zwgblog/p/7096875.html)
hdfs机架感应原理

★★★★★★

Presto的优缺点
优点
1.Presto基于内存计算,减少了硬盘IO,计算更快。
2.能够连接多个数据源,跨数据源连表查,如从Hive查询大量网络访问计算,然后从MySQL中匹配出设备信息。
3.Presto对ORC格式做了内部优化

缺点
1.Presto能够处理PB级别的海量数据分析,但Presto并不是把PB级数据都放在内存中计算的。而是根据场景,如Count,AVG等聚合运算,是边读数据边计算,在清内存,再读数据再计算,这种消耗的内存并不会很高。但是连表查,就可能产生大量的临时数据,因此速速就会变得很慢。


1.mapreduce如何实现全局排序
https://www.cnblogs.com/CoXieLearnPython/p/9463549.html
a.用一个reduce排序
b.利用分区取模进行分区局部数据排序

★★
2.小文件了解吗,项目中怎么产生?如何解决?
https://blog.csdn.net/pengzonglu7292/article/details/90230986
影响:
1、文件的元数据存储在namenode中,每个文件的元数据都差不多大,小文件过多会极大的占用namonode
的内存,制约集群的扩展。(主要影响)
2、在对小文件进行处理的时候,一个小文件对应一个maptask,一个maptask会起一个jvm进程,进程的
开启销毁会严重性能。(jvm复用)

产生场景:
1、实时处理:比如我们使用 Spark Streaming 从外部数据源接收数据,然后经过 ETL 处理之后存储
到 HDFS 中。这种情况下在每个 Job 中会产生大量的小文件。
2、hive中对表执行insert操作,每次插入都在表目录下形成一个小文件。
创建表结构相同的表,create table t_new as select * from t_old;
老表根据实际情况可以删除就删除。
3、hive中执行简单过滤操作,符合过滤条件的数据存在很多block块中,只走map,map输出有很多小文
件。
开启map端的聚合。
4、mapreduce正常执行产生小文件。
将mapreduce输出不直接写hdfs,而是写入到hbase中。
设置map端文件合并及reduce端文件合并。
5、输入数据文件为小文件。
小文件合并后再计算。
CombineFileInputFormat: 它是一种新的inputformat,用于将多个文件合并成一个单独的
split,另外,它会考虑数据的存储位置。

通用处理方案:
1、Hadoop Archive
Hadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件
打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。

2、Sequence file
sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将
大批小文件合并成一个大文件。

底层处理方案:
HDFS-8998:
DataNode划分小文件区,专门存储小文件。一个block块满了开始使用下一个block。
HDFS-8286:
将元数据从namenode从内存移到第三方k-v存储系统中。
HDFS-7240:
Apache Hadoop Ozone,hadoop子项目,为扩展hdfs而生。

★★
3.task的个数是由什么决定的?(https://blog.csdn.net/xuehuagongzi000/article/details/103081319) (https://blog.csdn.net/ifenggege/article/details/104581273)

Task是真正干活的,所以说是它间接决定了Spark程序的快慢也不过分。

再看看Spark任务提交时的几个相关配置:
num-executors:配置执行任务的Executor的数量。
executor-cores:每个Executor的核的数量。此核非彼核,它不是机器的CPU核,可以理解为Executor的一个线程。
每个核同时只可以执行一个Task。
也就是说一个Spark应用同时执行的任务数 = 用于执行任务的Executor数 * 每个Executor的核数。
spark.executor.memory:每个Executor的内存大小。

spark.default.parallelism:RDD的默认分区数。(默认是没有值的,如果设置了值比如说10,是在shuffle的过程才会起作用)
在我们没有指定这个参数的前提下,如果是shuffle操作,这个值默认是父RDD中分区数较大的那个值;如果是普通操作,这个值的默认大小取决于集群管理器(YARN, Local这些)。
以YARN为例,如果我们没有指定,它的大小就是所有用于执行任务的Executor核的总数。
spark.sql.shuffle.partitions:这个配置是针对于Spark SQL在shuffle时的默认分区数。默认值是200。只对Spark SQL起作用。

RDD计算时Task的数量
在基于RDD计算时,Task的数量 = RDD的分区数。
所以调整RDD分区的数量就可以变相的调整Task的数量。
所以当RDD计算跑的很慢时,可以通过适当的调整RDD分区数来实现提速。


4.spark报错不能超过2G的问题有没有遇到过?
spark中块分区的大小有2G的限制,2GB limit in spark for blocks,“Size exceeds Integer.MAX_VALUE” https://issues.apache.org/jira/browse/SPARK-1476
spark中块的底层抽象是bytebuffer,它将块的大小限制为2G. BlockManager cannot transfer blocks larger than 2G in size
可以通过repartition增加分区数来解决
2.4版本的时候已经通过将数据复制为流来解决这个2G的限制 https://issues.apache.org/jira/browse/SPARK-24296


5.Scala yeild for循环的跳出
a.针对每一次 for 循环的迭代, yield 会产生一个值,被循环记录下来 (内部实现上,像是一个缓冲区).
b.当循环结束后, 会返回所有 yield 的值组成的集合.
c.返回集合的类型与被遍历的集合类型是一致的

★★
6.项目中配置文件的加载方式?
ConfigFactory.load()

★★★★★★
7.kafka数据消费如何保证顺序性
a.一个 topic,一个 partition,一个 consumer,内部单线程消费,单线程吞吐量太低,一般不会用这个。
b.写 N 个内存 queue,具有相同 key 的数据都到同一个内存 queue;然后对于 N 个线程,每个线程分别消费一个内存 queue 即可,这样就能保证顺序性。

★★★★
8.kafka原理
架构
Producer:Producer即生产者,消息的产生者,是消息的入口。
  kafka cluster:
    Broker:Broker是kafka实例,每个服务器上有一个或多个kafka的实例,我们姑且认为每个broker对应一台服务器。每个kafka集群内的broker都有一个不重复的编号,如图中的broker-0、broker-1等……
    Topic:消息的主题,可以理解为消息的分类,kafka的数据就保存在topic。在每个broker上都可以创建多个topic。
    Partition:Topic的分区,每个topic可以有多个分区,分区的作用是做负载,提高kafka的吞吐量。同一个topic在不同的分区的数据是不重复的,partition的表现形式就是一个一个的文件夹!
    Replication:每一个分区都有多个副本,副本的作用是做备胎。当主分区(Leader)故障的时候会选择一个备胎(Follower)上位,成为Leader。在kafka中默认副本的最大数量是10个,且副本的数量不能大于Broker的数量,follower和leader绝对是在不同的机器,同一机器对同一个分区也只可能存放一个副本(包括自己)。
    Message:每一条发送的消息主体。
  Consumer:消费者,即消息的消费方,是消息的出口。
  Consumer Group:我们可以将多个消费组组成一个消费者组,在kafka的设计中同一个分区的数据只能被消费者组中的某一个消费者消费。同一个消费者组的消费者可以消费同一个topic的不同分区的数据,这也是为了提高kafka的吞吐量!
  Zookeeper:kafka集群依赖zookeeper来保存集群的的元信息,来保证系统的可用性。

原理
1.Producer先从kafka集群获取分区的leader
2.Producer将消息发送给leader
3.leader将消息写入本地文件
4.followers从leader pull消息
5.followers将消息写入本地后向leader发送ack
6.leader收到所有副本的ack后向producer发送ack

★★★★★★
9.kafka分区写入策略(https://www.cnblogs.com/listenfwind/p/12465409.html)
轮询策略,随机策略,和按键保存策略(目前版本默认为轮询策略)
kafka将数据保存在磁盘,Kafka初始会单独开辟一块磁盘空间,顺序写入数据(效率比随机写入高)

★★★★★★
10.kafka保证消息不丢失是一个消息队列中间件的基本保证,那producer在向kafka写入消息的时候,怎么保证消息不丢失呢?(https://www.cnblogs.com/sujing/p/10960832.html)
通过ACK应答机制!在生产者向队列写入数据的时候可以设置参数来确定是否确认kafka接收到数据,这个参数可设置的值为0、1、-1/all。
  0代表producer往集群发送数据不需要等到集群的返回,不确保消息发送成功。安全性最低但是效率最高。
  1代表producer往集群发送数据只要leader应答就可以发送下一条,只确保leader发送成功。
  -1/all代表producer往集群发送数据需要所有的follower都完成从leader的同步才会发送下一条,确保leader发送成功和所有的副本都完成备份。安全性最高,但是效率最低。

最后要注意的是,如果往不存在的topic写数据,能不能写入成功呢?kafka会自动创建topic,分区和副本的数量根据默认配置都是1。

★★
11.earliest 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
latest 当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
none topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常

★★★★★★
12.kafka是如何保证消息不被重复消费的(https://www.cnblogs.com/756623607-zhang/p/10506909.html)
一、kafka自带的消费机制offset
二、通过保证消息队列消费的幂等性来保证
1.比如某个数据要写库,你先根据主键查一下,如果数据有了,就别插入了,update一下好吧
2.比如计算某一天的某个公园的收入,可以用公园id+当前日期(年月日)作MD5,作upset操作,无论某个公园某天算多少次都只会产生一条对应的数据
三、exactly once
流式系统中最重要的保证:Exactly Once,即消息不会丢失,也不会被重复发送

在 Kafka 0.11 之前,开启重试机制只能保证数据不丢失,但是数据有可能有重复
在 Kafka 0.11 之后,可以实现数据的精准一次,它能保证多条消息原子性地写入到目标分区,即要不一起成功,要不都失败

主要靠两点:

事务型 Producer
Consumer 只会成功提交的事务消息
1.事务型 Producer
开启事务型 Producer 需要做以下 3 点:

设置 enable.idempotence = true
设置 transactional.id
发信息格式如下:

producer.initTransactions();
try {
    producer.beginTransaction();
    producer.send(record1);
    producer.send(record2);
    producer.commitTransaction();
} catch (KafkaException e) {
    producer.abortTransaction();
}

2.Consumer 只会成功提交的事务消息
设置 isolation.level = read_committed,表明 Consumer 只会读取事务型 Producer 成功提交事务写入的消息

13.spark3.0新特性(https://blog.csdn.net/qq_16038125/article/details/106987136)

★★★★★
https://www.cnblogs.com/sddai/p/11340870.html
如何保证消费者不重复消费:幂等,在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。
强校验:和钱相关的,比如一条消息是要调加钱的接口,这时候调完加钱接口后再调一个流水接口,将两个接口放到一个事务里,成功一起成功失败一起失败。每次消息过来先去查流水表,如果存在就return,
不存在就调取加钱接口和流水接口。之所以用流水表,是因为涉及到金钱这样的活动,有啥问题后面也可以去流水表对账
弱校验:把消息的id+场景唯一标识 作为redis的key,设置失效时间,一定时间内的这个消息就去redis判断。
如何保证消费有序性:kafka同一个partition用一个write ahead log组织,所以可以保证FIFO的顺序。不同partition之间不能保证顺序。
局部顺序:我们可使用Hash取模法,让同一个订单发送到同一个队列中,再使用同步发送,只有同个订单的创建消息发送成功,再发送支付消息。这样,我们保证了发送有序。
一个topic的多个分区,可以对应多个内存队列,多个内存队列再采用多线程消费,这样就可以保证有序性了。
全局顺序:binlog日志传输,全局使用一个生产者,一个分区,一个消费者单线程。

什么时候发生数据倾斜,如何解决
hbase的rowkey了解吗
Linux文本编辑命令,如何选出文本的第10-15行数据
spark的运行架构讲一下,常用的算子
spark如何往数据库写入数据(foreachpartition or foreachrdd 批量写)
十大基本算法介绍、常见数据结构、分布式算法

sparksql selectExpr:可以对指定字段进行特殊处理,可以直接对指定字段调用UDF函数,或者指定别名等


1.scala的伴生类和伴生对象(https://www.cnblogs.com/rabbit624/p/10528575.html)
在同一个scala文件中定义一个类,同时定义一个同名的object,那么它们就是伴生类和伴生对象的关系,可以互相直接访问私有的field。
伴生对象通常会使用apply函数定义伴生类的构造方法。 这样在创建伴生类的对象时就可以省略 new 关键字。

★★
2.Spark Broadcast
Spark中因为算子中的真正逻辑是发送到Executor中去运行的,所以当Executor中需要引用外部变量时,需要使用广播变量。
进一步解释:
如果executor端用到了Driver的变量,如果不使用广播变量在Executor有多少task就有多少Driver端的变量副本;如果Executor端用到了Driver的变量,如果使用广播变量在每个Executor中只有一份Driver端的变量副本。
a)broadcast的定义必须在Driver端,不能再executor端定义;
b)调用unpersist(),unpersist(boolean blocking),destroy(),distroy(boolean blocking)方法这些方法必须在driver端调用。
c)在Driver端可以修改广播变量的值,在Executor端无法修改广播变量的值。

★★★★
3.如何从根源上解决 HDFS 小文件问题
https://blog.csdn.net/pengzonglu7292/article/details/90230986
https://blog.csdn.net/b6ecl1k7BS8O/article/details/83005862

影响:
1、文件的元数据存储在namenode中,每个文件的元数据都差不多大,小文件过多会极大的占用namonode
的内存,制约集群的扩展。(主要影响)
2、在对小文件进行处理的时候,一个小文件对应一个maptask,一个maptask会起一个jvm进程,进程的
开启销毁会严重性能。(jvm复用)

产生场景:
1、实时处理:比如我们使用 Spark Streaming 从外部数据源接收数据,然后经过 ETL 处理之后存储
到 HDFS 中。这种情况下在每个 Job 中会产生大量的小文件。
2、hive中对表执行insert操作,每次插入都在表目录下形成一个小文件。
创建表结构相同的表,create table t_new as select * from t_old;
老表根据实际情况可以删除就删除。
3、hive中执行简单过滤操作,符合过滤条件的数据存在很多block块中,只走map,map输出有很多小文
件。
开启map端的聚合。
4、mapreduce正常执行产生小文件。
将mapreduce输出不直接写hdfs,而是写入到hbase中。
设置map端文件合并及reduce端文件合并。
5、输入数据文件为小文件。
小文件合并后再计算。
CombineFileInputFormat: 它是一种新的inputformat,用于将多个文件合并成一个单独的
split,另外,它会考虑数据的存储位置。

通用处理方案:
a、Hadoop Archive
Hadoop Archive或者HAR,是一个高效地将小文件放入HDFS块中的文件存档工具,它能够将多个小文件
打包成一个HAR文件,这样在减少namenode内存使用的同时,仍然允许对文件进行透明的访问。

b、Sequence file
sequence file由一系列的二进制key/value组成,如果为key小文件名,value为文件内容,则可以将
大批小文件合并成一个大文件。

底层处理方案:
HDFS-8998:
DataNode划分小文件区,专门存储小文件。一个block块满了开始使用下一个block。
HDFS-8286:
将元数据从namenode从内存移到第三方k-v存储系统中。
HDFS-7240:
Apache Hadoop Ozone,hadoop子项目,为扩展hdfs而生。

★★★
4.Spark内存分配详解(https://www.jianshu.com/p/b68a3a2df7a3) (https://www.cnblogs.com/ulysses-you/p/9660400.html#_labelTop)
在Spark 1.5版本及以前,Spark采用静态内存管理模型。
spark.storage.memoryFraction=0.6
spark.shuffle.memoryFraction=0.2

Spark 1.6版本推出以后,Spark采用了统一内存管理模型。
spark.memory.fraction=0.6 spark可以直接使用的内存大小系数
spark.memory.storageFraction=0.5 spark存储可以直接使用的内存大小系数

★★★★★★★
5.Spark任务提交方式和执行流程(https://www.cnblogs.com/frankdeng/p/9301485.html)

★★★★★
6.深入理解Hive分区与分桶
(https://blog.csdn.net/xm_QUQ/article/details/96043989)
(https://www.jianshu.com/p/3e8dbcbaf2b4 、 https://www.cnblogs.com/cssdongl/p/6831884.html)
分区:我们可以按照日期对数据表进行分区,不同日期的数据存放在不同的分区,在查询时只要指定分区字段的值就可以直接从该分区查找。

静态分区:
CREATE TABLE p_table2(id int, name string) PARTITIONED BY(date_day string,emp_no string) stored as orc;

动态分区:
动态分区与静态分区建表语句一样,不同在:动态分区插入数据时需要开启动态数据支持:
set hive.exec.dynamic.partition=true;
set hive.exec.dynamic.partition.mode=nostrict;
插入数据(覆盖)insert overwrite table p_table2 partition(date_day,emp_no) select 2 as id,‘lily’ as name,‘2019-07-14’ as date_day, ‘a’ as emp_no;
分区并没有写死,而是根据查询到的值动态创建的两级分区。

分桶:它指定分桶表的某一列,让该列数据按照哈希取模的方式随机、均匀地分发到各个桶文件中。因为分桶操作需要根据某一列具体数据来进行哈希取模操作,故指定的分桶列必须基于表中的某一列(字段)
create table b_table1(id int,name string) clustered by (id) sorted by(id) into 4 buckets stored as textfile;
使用CLUSTERED BY 子句来指定划分桶所用的列和要划分的桶的个数,当表分区时,每个分区下都会有4个桶。

区别:
1、分区使用的是表外字段,需要指定字段类型;分桶使用的是表内字段,已经知道字段类型,不需要再指定。
2、分区通过关键字partitioned by(partition_name string)声明,分桶表通过关键字clustered by(column_name) into 3 buckets声明。
3、分区划分粒度较粗,分桶是更细粒度的划分、管理数据,可以对表进行先分区再分桶的划分策略。
4、分区是个伪列,只对应着文件存储路径上的一个层级。

★★★
hive中Sort By,Order By,Cluster By,Distribute By,Group By的区别 。
order by:
hive中的order by 和传统sql中的order by 一样,对数据做全局排序,加上排序,会新启动一个job进行排序,会把所有数据放到同一个reduce中进行处理,不管数据多少,不管文件多少,都启用一个reduce进行处理。如果指定了hive.mapred.mode=strict(默认值是nonstrict),这时就必须指定limit来限制输出条数,原因是:所有的数据都会在同一个reducer端进行,数据量大的情况下可能不能出结果,那么在这样的严格模式下,必须指定输出的条数。

sort by:sort by 是局部排序,会在每个reduce端做排序,每个reduce端是排序的,也就是每个reduce出来的数据是有序的,但是全部不一定有序,除非一个reduce,一般情况下可以先进行局部排序完成后,再进行全局排序,会提高不少效率。

distribute by:distribute by 是控制map端在reduce上是如何区分的,distribute by 会把指定的值发到同一个reduce中,比如 用上面数据distribute by id 它就会把id相同的值放到一个reduce中执行,不是一个值一个reduce,而是相同的值进入到一个reduce,例如用上面数据可以进入到2个reduce,一般情况下可以sort by 结合使用,先进行分组reduce,再进行排序(相当于mapreduce中的分区函数)。

PS:Order by 能够预期产生完全排序的结果,但是它是通过只用一个reduce来做到这点的。所以对于大规模的数据集它的效率非常低。在很多情况下,并不需要全局排序,此时可以换成Hive的非标准扩展sort by。
Sort by为每个reducer产生一个排序文件。在有些情况下,你需要控制某个特定行应该到哪个reducer,通常是为了进行后续的聚集操作。
Hive的distribute by 子句可以做这件事

cluster by(只能是使用默认的升序排序,不能使用ACS和DESC):
这个其实就是distribute by 和sort by 结合使用的结果(前提是同一个字段)。  
例如:select id,money,name from t cluster by id;等价于:select id,money,name from t distribute by id sort by id

distribute by和group by的区别:都是按key值划分数据 都使用reduce操作 **唯一不同的是,distribute by只是单纯的分散数据,distribute by col – 按照col列把数据分散到不同的reduce。而group by把相同key的数据聚集到一起,后续必须是聚合操作。

order by和sort by的区别:order by是全局排序 sort by只是确保每个reduce上面输出的数据有序。如果只有一个reduce时,和order by作用一样。

★★
7.Phoenix索引(https://blog.csdn.net/weixin_42072754/article/details/103918369)
Phoenix支持的索引有三个类型,分别是覆盖索引、全局索引、本地索引。

覆盖索引Covered Index
覆盖索引要求查询语句中的条件字段、查询字段都必须创建过索引,否则就会触发“全局扫描”(full table scan)
创建语法:create index coverindex user_index on user (name) include (age);
因此它的特点是:只需要通过索引就能返回所要查询的数据 。

全局索引Global indexes
global是默认的索引格式。
全局索引适用于多读少写的场景,在写操作上会给性能带来极大的开销,因为所有的更新和写操作(DELETE,UPSERT VALUES和UPSERT SELECT)都会引起索引的更新,在读数据时,Phoenix将通过索引表来达到快速查询的目的。如;
create index userid_index on user (userid);

它有一个缺陷,如果查询语句中的条件字段或查询字段不是索引字段,就会触发全表扫描。例如:
select userid,name from user where userid='8960321’

解决办法
和覆盖索引一样,创建索引时把查询的相关字放入段include来。
create index userid_index on user (userid) include (name );

本地索引Local Indexing
与Global Indexing不同,本地索引适用于写多读少的场景,当使用Local Indexing的时候即使查询的所有字段都不在索引字段中时也会用到索引进行查询,Phoneix在查询时会自动选择是否使用本地索引(这是由Local Indexing自动完成的)。
create local index user_Index on user (userid,name);

★★
8.hbase的RowKey设计原则
长度原则
RowKey是一个二进制码流,可以是任意字符串,最大长度为64kb,实际应用中一般为10-100byte,以byte[]形式保存,一般设计成定长。建议越短越好,不要超过16个字节,原因如下:
数据的持久化文件HFile中时按照Key-Value存储的,如果RowKey过长,例如超过100byte,那么1000w行的记录,仅RowKey就需占用近1GB的空间。这样会极大影响HFile的存储效率。
MemStore会缓存部分数据到内存中,若RowKey字段过长,内存的有效利用率就会降低,就不能缓存更多的数据,从而降低检索效率。
目前操作系统都是64位系统,内存8字节对齐,控制在16字节,8字节的整数倍利用了操作系统的最佳特性。

唯一原则
必须在设计上保证RowKey的唯一性。由于在HBase中数据存储是Key-Value形式,若向HBase中同一张表插入相同RowKey的数据,则原先存在的数据会被新的数据覆盖。

排序原则
HBase的RowKey是按照ASCII有序排序的,因此我们在设计RowKey的时候要充分利用这点。

散列原则
设计的RowKey应均匀的分布在各个HBase节点上。(使用散列函数hash,md5)

★★★★★★
9.hive优化(https://www.cnblogs.com/swordfall/p/11037539.html)
1 慎用api 数据量较大的情况下,慎用count(distinct),count(distinct)容易产生倾斜问题。

2 自定义UDAF函数优化 sum,count,max,min等UDAF,不怕数据倾斜问题

3 设置合理的map reduce的task数量
a.map阶段 减少map数和增加map数
b.reduce阶段 最准确的数根据Map的输出估算Reduce的个数

4 小文件合并优化
用于设置合并的参数有:
a.是否合并Map输出文件:hive.merge.mapfiles=true(默认值为true)
b.是否合并Reduce端输出文件:hive.merge.mapredfiles=false(默认值为false)
c.合并文件的大小:hive.merge.size.per.task=25610001000(默认值为256000000)
从小文件产生的途径就可以从源头上控制小文件数量,方法如下:
a.使用Sequencefile作为表存储格式,不要用textfile,在一定程度上可以减少小文件;
b.减少reduce的数量(可以使用参数进行控制);
c.少用动态分区,用时记得按distribute by分区;
    对于已有的小文件,我们可以通过以下几种方案解决:
a.使用hadoop archive命令把小文件进行归档;
b.重建表,建表时减少reduce数量;
c.通过参数进行调节,设置map/reduce端的相关参数

5 SQL优化
列裁剪
Hive在读数据的时候,可以只读取查询中所需要用到的列,而忽略其他列: SELECT a,b FROM q WHERE e<10;
分区裁剪
在查询的过程中减少不必要的分区: SELECT * FROM T1 JOIN (SELECT * FROM T2) subq ON (T1.a1=subq.a2) WHERE subq.prtn=100; 查询语句若将"subq.prtn=100"条件放入子查询中更为高效,可以减少读入的分区数目。Hive自动执行这种裁剪优化。
不同数据类型关联产生的倾斜问题
不同数据类型id的关联会产生数据倾斜问题, 解决方法:把数据类型转换成字符串类型 : SELECT * FROM s8_log a LEFT OUTER JOIN r_auction_auctions b ON a.auction_id=CAST(b.auction_id AS STRING)
利用Hive对UNION ALL优化的特性
解决Hive对UNION ALL优化的短板: 消灭子查询内的group by,COUNT(DISTINCT),MAX,MIN,JOIN
使用先GROUP BY再COUNT的方式替换:COUNT(DISTINCT)
JOIN操作
小表join大表,小表放在前面,原因是在Join操作的Reduce阶段,位于Join操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生OOM错误的几率
关联字段空Key过滤
GROUP BY操作
开启Map端部分聚合set hive.map.aggr=true 或者开启有数据倾斜的时候进行负载均衡set hive.groupby.skewindata = true
使用left semi join替代优化in/exists语句

6 存储格式(textfile,Sequence Files,RCFile,ORCFile)
ORC是列式存储,有多种文件压缩方式,并且有着很高的压缩比(默认采用Zstd压缩算法)
加速Hive查询速度

7 压缩格式
8 引擎的选择
9 使用向量化查询
10 设置cost based query optimization
11 模式选择
12 JVM重用
13 推测执行

★★
10.hive常用函数
concat字符串连接函数
select concat(‘江苏省’,’-’,‘南京市’,’-’,‘玄武区’,’-’,‘徐庄软件园’);

concat_ws
select concat_ws(’-’,‘江苏省’,‘南京市’,‘玄武区’,‘徐庄软件园’);

unix_timestamp()当前系统时间
select unix_timestamp();

from_unixtime 将数字型按照 格式进行时间转换
select from_unixtime(unix_timestamp(),‘yyyy-MM-dd HH:mm:ss’);

regexp_replace(string A, string B, string C) 字符串替换函数,将字符串A 中的B 用 C 替换。
select regexp_replace(‘www.tuniu.com’,‘tuniu’,‘jd’);

trim(string A) 删除字符串两边的空格,中间的会保留。相应的 ltrim(string A) ,rtrim(string A)

to_date(string timestamp) 将时间戳转换成日期型字符串
select to_date(‘2017-01-16 09:55:54’);

datediff(string enddate, string startdate) 返回int 的两个日期差
select datediff(‘2017-01-16’, ‘2017-01-10’);

date_add(string startdate, int days) 日期加减
select date_add(‘2017-01-10’, 7);

date_format(date/timestamp/string ts, string fmt) 按照格式返回字符串
select date_format(‘2017-01-16 09:55:54’, ‘yyyy-MM-dd’);

if(boolean testCondition, T valueTrue, T valueFalseOrNull) ,根据条件返回不同的值

nvl(T value, T default_value) 如果T is null ,返回默认值

length(string A) 返回字符串A的长度

rand(), 返回0-1的随机值。rand(INT seed) 返回固定的随机值。

md5(string/binary)hive 1.3以上版本,返回md5码

split(str, regex) ,安装规则截取字符串,返回数组

substring 截取字符串

★★★★
11.hive与hbase的区别
Hive:Hive是基于Hadoop的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的sql查询功能。
Hive本身不存储和计算数据,它完全依赖于HDFS和MapReduce,Hive中的表纯逻辑。hive需要用到hdfs存储文件,需要用到MapReduce计算框架。
hive可以认为是map-reduce的一个包装。hive的意义就是把好写的hive的sql转换为复杂难写的map-reduce程序。
HBase:HBase是Hadoop的数据库,一个分布式、可扩展、大数据的存储。
hbase是物理表,不是逻辑表,提供一个超大的内存hash表,搜索引擎通过它来存储索引,方便查询操作
hbase可以认为是hdfs的一个包装。他的本质是数据存储,是个NoSql数据库;hbase部署于hdfs之上,并且克服了hdfs在随机读写方面的缺点。
Hbase和Hive在大数据架构中处在不同位置,Hbase主要解决实时数据查询问题,Hive主要解决数据处理和计算问题,一般是配合使用。

★★★
12.Spark Streaming感知kafka动态分区的问题(https://blog.csdn.net/rlnLo2pNEfx9c/article/details/81117367)
kafka 0.10版本
相似的我们也可以直接去看kafka 0.10这块的源码去检查,他是否会动态生成kafka分区。
进入DirectKafkaInputDStream的compute,看到的第一行代码也是:
val untilOffsets = clamp(latestOffsets())
在latestOffsets里面,有了新的大陆:先获取所有的partition信息,然后得到新的partition,并且将新的partition加入到了currentOffsets这个变量里,这就实现了动态kafka分区检测。

★★★★
13.Hive内部表和外部表的区别,以及各自使用的环境?(https://my.oschina.net/u/3484567/blog/3109827)
未被external修饰的是内部表(managed table), 被external修饰的为外部表(external table);
区别:
a.内部表数据由Hive自身管理,外部表数据由HDFS管理;
b.内部表数据存储的位置是hive.metastore.warehouse.dir(默认:/user/hive/warehouse),外部表数据的存储位置由自己制定;
c.删除内部表会直接删除元数据(metadata)及存储数据;删除外部表仅仅会删除元数据,HDFS上的文件并不会被删除,数据还在HDFS里面;
d.对内部表的修改会将修改直接同步给元数据,而对外部表的表结构和分区进行修改,则需要 修复(MSCK REPAIR TABLE table_name;)主要体现在load与drop(是否同时删除元数据与数据)的操作上
e.Hive创建内部表时,会将数据移动到数据仓库指向的路径,hive管理数据的生命周期。创建外部表时,仅仅记录数据所在的路径,并不会对数据做任何处理。
选择:
内部表与外部表没有太大区别,如果所有的 数据都用Hive处理,则创建内部表;如果数据的处理需要 hive和其他工具一起处理,则创建外部表。

★★
14.Hive 建外链表到 Hbase(分内部表、外部表两种方式)(https://www.bbsmax.com/A/nAJvRKA3Jr/)
一、Hive 建内部表,链到hbase ;特点:Hive drop表后,Hbase 表同步删除
二、Hive上建外部表,链到Hbase ;特点:Hive drop表后,Hbase表不变

★★
15.HBase 列族属性配置(https://blog.csdn.net/wwd0501/article/details/107472676)
a. 创建表
create ‘user’,‘base_info’ (多个列族,直接在base_info后以逗号分隔添加base_info2,eg:create ‘user’,‘base_info’,“base_info2”,“base_info3”)

b. 向表中添加数据
put ‘user’, ‘rowkey_10’, ‘base_info:username’, ‘张三’
put ‘user’, ‘rowkey_10’, ‘base_info:birthday’, ‘2014-07-10’
put ‘user’, ‘rowkey_10’, ‘base_info:sex’, ‘1’
put ‘user’, ‘rowkey_10’, ‘base_info:address’, ‘北京市’

put ‘user’, ‘rowkey_16’, ‘base_info:username’, ‘张小明’
put ‘user’, ‘rowkey_16’, ‘base_info:birthday’, ‘2014-07-10’
put ‘user’, ‘rowkey_16’, ‘base_info:sex’, ‘1’
put ‘user’, ‘rowkey_16’, ‘base_info:address’, ‘北京’

16.增删查改的真正面目
HBase 是一个可以随机读写的数据库,而它所基于的持久化层 HDFS 却是要么新增,要么整个删除,不能修改的系统。那 HBase 怎么实现我们的增删查改的?真实的情况是这样的:HBase 几乎总是在做新增操作。
当你新增一个单元格的时候,HBase 在 HDFS 上新增一条数据;
当你修改一个单元格的时候,HBase 在 HDFS 又新增一条数据,只是版本号比之前那个大(或者你自己定义);
当你删除一个单元格的时候,HBase 还是新增一条数据!只是这条数据没有 value,类型为 DELETE,这条数据叫墓碑标记(Tombstone)。

★★★★
storm
1.消息的可靠性保证(https://www.cnblogs.com/hd3013779515/p/6962934.html)
在Spout中由message 1绑定的tuple1和tuple2分别经过bolt1和bolt2的处理,然后生成了两个新的Tuple,并最终流向了bolt3。当bolt3处理完之后,称message 1被完全处理了。
Storm中的每一个Topology中都包含有一个Acker组件。Acker组件的任务就是跟踪从Spout中流出的每一个messageId所绑定的Tuple树中的所有Tuple的处理情况。如果在用户设置的最大超时时间内这些Tuple没有被完全处理,那么Acker会告诉Spout该消息处理失败,相反则会告知Spout该消息处理成功。
那么Acker是如何记录Tuple的处理结果呢??
A xor A = 0.
A xor B…xor B xor A = 0,其中每一个操作数出现且仅出现两次。
在Spout中,Storm系统会为用户指定的MessageId生成一个对应的64位的整数,作为整个Tuple Tree的RootId。RootId会被传递给Acker以及后续的Bolt来作为该消息单元的唯一标识。同时,无论Spout还是Bolt每次新生成一个Tuple时,都会赋予该Tuple一个唯一的64位整数的Id。
当Spout发射完某个MessageId对应的源Tuple之后,它会告诉Acker自己发射的RootId以及生成的那些源Tuple的Id。而当Bolt处理完一个输入Tuple并产生出新的Tuple时,也会告知Acker自己处理的输入Tuple的Id以及新生成的那些Tuple的Id。Acker只需要对这些Id进行异或运算,就能判断出该RootId对应的消息单元是否成功处理完成了。

★★
1.IOC和AOP
Spring是一套为了解决企业应用开发的复杂性而创建的框架,特点是分层的架构,允许用户在不同层面使用不同的组件进行组合。同时通过IOC容器来降低耦合,简化开发。利用AOP来进行切面编程统一管理通用模块。
我在工作中用到过Spring的IOC容器和AOP面向切面编程,在项目中使用IOC容器帮我很好的理清各个业务对象的关系,同时方便不同组件的更替。在做接口权限验证时,使用AOP切面编程帮助我能很快的对需要进行验证的接口完成验证功能的实现。并且统一进行管理,提高开发效率。
IOC:
    @Component:实现Bean组件的定义
    @Repository:用于标注DAO类,功能与@Component作用相当
    @Service:用于标注业务类
    @Controller:用于标注控制器

DI:
    @Resource(name=“userService”)默认ByName方式,如果name确实默认按照ByType方式注入
    @Autowired,默认ByType方式,如果出现同名类,则不能按照Type进行注入,需要使用
    @Qualifier 指明ID

2.接口和抽象类的区别之处:(https://www.cnblogs.com/3020815dzq/p/8509137.html)
1. 接口中所有的方法隐含都是抽象的,而抽象类则可以同时包含抽象和非抽象的方法
2. 类可以实现很多个接口,但是只能继承一个抽象类
3. 类可以不实现抽象类和接口声明的所有方法,在这种情况下,类也必须得声明成是抽象的
4. 抽象类可以在不提供接口方法实现的情况下实现接口
5. java接口中声明的变量默认都是final的,抽象类可以包含非final变量
6. java接口中的成员函数默认都是public的,抽象类中的成员函数可以是private,protected或者是public的
7. 接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是如果它包含main方法的话是可以被调用的
8:抽象类中可以有普通方法,接口中不能。
9:抽象类可以有构造,接口不能
10:抽象类中可以有普通字段,而接口中不行
11:抽象类不能实现多继承,接口可以
12:符合isa关系的选用抽象类,符合hasa关系的选用接口比抽象类抽象程度更高

3.java sleep wait区别?(https://www.cnblogs.com/nongzihong/p/10509673.html)
a.每个对象都有一个锁来控制同步访问,Synchronized关键字可以和对象的锁交互,来实现同步方法或同步块。sleep()方法正在执行的线程主动让出CPU(然后CPU就可以去执行其他任务),在sleep指定时间后CPU再回到该线程继续往下执行(注意:sleep方法只让出了CPU,而并不会释放同步资源锁!!!);wait()方法则是指当前线程让自己暂时退让出同步资源锁,以便其他正在等待该资源的线程得到该资源进而运行,只有调用了notify()方法,之前调用wait()的线程才会解除wait状态,可以去参与竞争同步资源锁,进而得到执行。(注意:notify的作用相当于叫醒睡着的人,而并不会给他分配任务,就是说notify只是让之前调用wait的线程有权利重新参与线程的调度);
b.sleep()方法可以在任何地方使用;wait()方法则只能在同步方法或同步块中使用;
c.sleep()是线程线程类(Thread)的方法,调用会暂停此线程指定的时间,但监控依然保持,不会释放对象锁,到时间自动恢复;wait()是Object的方法,调用会放弃对象锁,进入等待队列,待调用notify()/notifyAll()唤醒指定的线程或者所有线程,才会进入锁池,不再次获得对象锁才会进入运行状态;

4.hashmap的扩容机制?(https://blog.csdn.net/u010890358/article/details/80496144)
第一种:使用默认构造方法初始化HashMap。从前文可以知道HashMap在一开始初始化的时候会返回一个空的table,并且thershold为0。因此第一次扩容的容量为默认值DEFAULT_INITIAL_CAPACITY也就是16。同时threshold = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR = 12。
第二种:指定初始容量的构造方法初始化HashMap。那么从下面源码可以看到初始容量会等于threshold,接着threshold = 当前的容量(threshold) * DEFAULT_LOAD_FACTOR。
第三种:HashMap不是第一次扩容。如果HashMap已经扩容过的话,那么每次table的容量以及threshold(阈值)量为原有的两倍。
HashMap默认使用的容量为16、默认使用的负载因子值为0.75f,在使用HashMap的时候如果可以预知数据量大小的话最好指定初始容量,可以减少运行过程中扩容的次数,以达到一定的性能提升。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值