知识点整理

1.spark 批流一体计算引擎

1.1sparkcore

1.1.1rdd 弹性分布式数据集

弹性?容错 =》 计算的时候 可以重试
分布式?
分布式存储:rdd数据存储是分布式的 ,是跨节点进行存储的
分布式计算:对rdd进行操作实际上是操作 rdd分区里面的数据
数据集?就是构建rdd本身的数据
rdd五大特性:
1.rdd底层存储一系列partition
2.针对rdd做计算/操作其实就是对rdd底层的partition进行计算/操作
3.rdd之间的依赖关系 (血缘关系)
rdd 不可变 rdda => rddb => rddc
4.Partitioner => kv类型的rdd
5.数据本地性 =》 减少数据传输的网络io
优先把作业调度在数据所在节点 =》 【理想状况】
作业调度在别的节点上 ,数据在另外一台节点上
只能把数据通过网络把数据传输到 作业所在节点上去进行计算

1.1.2SparkContext sparkcore 程序入口

转换成rdd :parallelize、textFile
collect() 将rdd变成数组输出
saveAsTextFile输出到本地或hdfs上
transformations算子 懒加载 不会立即触发job的执行
转换算子rdda => rddb 血缘关系
map filter flatMap 底层是MapPartitionsRDD
groupByKey不要使用效率低,没有开启预聚合
sortby分区排序 默认升序
想要全局排序的前提是rdd的分区只有一个
join vs cogroup
1.操作对象都是kv类型的
2.都是根据key进行关联
3.join返回值类型是RDD[(k,(option[v],option[w]))],cogroup的返回值类型是RDD[(k,(Iterable[v],Iterable[w]))],一个直接返回值,一个返回集合
4.join底层调用cogroup算子
distinct 去重 默认采用分区器: hash
底层调用map+reduceByKey+map完成对数据的key去重
case _ => map(x => (x, null)).reduceByKey((x, ) => x, numPartitions).map(._1)
foreachPartition、foreach
first底层调用的是take(n)算子
top是降序取前n个数据集, takeOrdered 是升序取前n个数据集
top底层是takeOrdered实现的
大部分 xxxBykey算子 =》 transformation算子 ,除了countByKey() =》 aciton算子
源码里面 :sparkcount.runjob => 触发作业的执行 =》 action算子
case class 推荐!!!
1.默认实现了 序列化
2.重写了 tostring方法
3.不用new可以直接用
Ordering =》 compareable
Ordered =》 comparetor
输出rdd:collect()、foreach()、foreachPartition

spark核心概念

cluster: driver inside of the cluster driver跑在yarn所在的机器里面
client driver 运行在集群cluster之外,在哪提交作业的地方
Worker node相当于yarn里面的nodemanager
Executor: 相当于yarn里面的container
Task: 任务等于rdd: partitions个数
总结:
一个application :包含 1 到n 个job
一个job: 包含 1到n个stage
rdda => rddb => rddc action => 一个job
01stage 02stage
一个stage:包含 1个到n个task
task 和 partition 一一对应

spark执行流程

1.spark作业运行在集群上 有一系列进程
2.SparkContext 去协调这些进程
进程 :
driver 1
executors
3.运行spark作业:
1.sc 去连接 集群cluster manager
2.只要连接到集群,cluster manager 给spark作业分配资源
3.spark一旦连接上cluster
1.启动executor
2.executor =》 计算和存储数据
4.
sparkcontext 发送代码 给executor
sparkcontext 发送task 去executor 运行
补充: mem、CPU
1.worknode =》 nodemanager 所在的节点
executor=》 container:
task、store data
4.spark执行架构补充:
1.每个spark作业有自己的executor进程
app1: executors 1
app2: executors 1
好处:
1.资源隔离,这个作业申请的executor,别的作业不能用
2.调度的隔离,每个driver调度自己的任务
不同作业之间数据是不能进行共享的,除非把数据存储在外部存储系统上

rdd持久化

1.persist() or cache()
2.触发action之后 rdd数据持久化生效
cache() 是lazy 是懒加载的 不是action算子
rdd.cache 之后 rdd之后的数据就不用从头开机计算,而是从 rdd持久化的地方加载数据 ,好处:提升计算效率、复用
对rdd做持久化 就是对rdd里面的分区做持久化
cache vs persist(更好) 区别:【面试】
1.cache底层就是调用 persist算子
2.spark-core 持久化 默认存储级别:StorageLevel.MEMORY_ONLY
StorageLevel:
private var _useDisk: Boolean,
private var _useMemory: Boolean,
private var _useOffHeap: Boolean,
private var _deserialized: Boolean,
private var _replication: Int = 1
val NONE = new StorageLevel(false, false, false, false)
val DISK_ONLY = new StorageLevel(true, false, false, false)
val DISK_ONLY_2 = new StorageLevel(true, false, false, false, 2)
val DISK_ONLY_3 = new StorageLevel(true, false, false, false, 3)
val MEMORY_ONLY = new StorageLevel(false, true, false, true)
val MEMORY_ONLY_2 = new StorageLevel(false, true, false, true, 2)
val MEMORY_ONLY_SER = new StorageLevel(false, true, false, false)
val MEMORY_ONLY_SER_2 = new StorageLevel(false, true, false, false, 2)
val MEMORY_AND_DISK = new StorageLevel(true, true, false, true)
val MEMORY_AND_DISK_2 = new StorageLevel(true, true, false, true, 2)
val MEMORY_AND_DISK_SER = new StorageLevel(true, true, false, false)
val MEMORY_AND_DISK_SER_2 = new StorageLevel(true, true, false, false, 2)
val OFF_HEAP = new StorageLevel(true, true, true, false, 1)
存储级别选择:
1.MEMORY_ONLY 首选
2.MEMORY_ONLY_SER 次选 (cpu充足时)
1.Java serialization: By default,
2.Kryo: 注册 class 比java快
3.不建议选择磁盘
4.不要选择副本 太占内存
data.persist()// 10.3M
data.persist(StorageLevel.MEMORY_ONLY_SER)// 7.6M 默认是java 类需要序列化 样例类默认是实现序列化
// Kryo 8.6M 性能比java高
移除rdd持久化 :
1.lru 会自动移除不常用的持久化数据
2.手动 :【生产】
RDD.unpersist(true) 立即执行的 eager

血缘关系和依赖关系

lineage: rdda => rddb => rddc
rdda和rddb分区数是一一对应的,rddb某个分区挂了时,直接从rdda对应的分区进行重新计算即可
rdda => rddb
不同的依赖 会导致 生成rdd分区数发生变化的
分类:【面试】
1.宽依赖:
1.一个父rdd的parition会被子rdd的parition使用多次
2.会产生shuffle(数据重新洗牌) 会有新的stage产生
2.窄依赖:
1.一个父rdd的parition至多被子rdd的partition使用一次
2.不会产生shuffle,都是在一个stage里面完成的
宽依赖:
xxxbykey shuffle
其他: 普通/reducejoin
窄依赖:
mapjoin、map filter flatmap union
spark: stage是如何划分? ****
spark-core 产生 宽依赖 就会划分stage
算子:引起shuffle 就会划分stage
一个shuffle算子 会划分2个stage,两个shuffle算子 会产生3个stage

shuffle 算子

引起shuffle的算子:
1.xxxbykey =》
2. repartition and coalesce
coalesce: 一般用于 减少rdd的分区数 =》 窄依赖 =》 不会引起shuffle 减少并行度task少了,data.coalesce(1)
repartition:增加rdd的分区数 会引起shuffle data.repartition(3)
coalesce(num,shuffle=true)
4. join:
map join 不会引发shuffle
reduce join /common join =》 引起shuffle
可不可以使用coalesce 增加rdd分区数 ? 可以的 data.coalesce(4,true)
repartition 减少rdd的分区数? 不能
coalesce 增加rdd分区数 ? 走不走shuffle? 必然走shuffle
rdd =》 hdfs 200个小文件 变成10个文件 rdd.coalesce(10)

区分代码里的driver和executor(idea)

主要看操作对象
操作对象是rdd的就是executor
操作对象不是rdd的就是driver

sparksql sql+dataframe->rdd+schema

sparksql 主要处理结构化数据—带有schema信息的数据
SparkSQL 是能够处理多种不同的数据源的数据:
Hive, Avro, Parquet, ORC, JSON, and JDBC text HDFS/s3(亚马逊)/oss(阿里)/cos(腾讯)
SparkSQL访问hive的元数据库即 可利用sparksql查询hive里面的数据
概述:
1.sparksql 处理数据的性能比 spark rdd 方式的处理性能高
1.more information about the structure of both the data 【schema】
2.sparksql架构有关
sparksql底层跑的还是 Sparkcore rdd ,只是spark框架底层给我们做了优化
sparkcore:编程模型 rdd
sparksql: rdd[数据集] +schema[字段 字段的类型] =》 table
2.Spark SQL including SQL and the Dataset API
3.Datasets and DataFrames:
Dataset
1.Dataset 也是一个分布式数据集
2.比rdd多出的优势:
1.强类型
2.Dataset 也可以使用算子
3.optimized execution engine. 执行性能 高 【sparksql架构 catelyst 做了很多优化】
4.Dataset 是Spark 1.6 之后诞生的
3.Dataset API :scala java进行开发
DataFrame:
1.DataFrame 也是一个dataset
2.DataFrame四种创建方式:
structured data files, tables in Hive, external databases, or existing RDDs
3. DataFrame is represented by a Dataset of Rows:
DataFrame = Dataset[Row]
Row => 一行数据 仅仅包含 named columns
DataFrame =》 table
sparkcore=> rdd 数据集
sparksql=》 DataFrame /df 数据集 【数据集 + 额外的信息【schema】】
rdd + schema => table
Sparksql:
1.0: schemaRDD : rdd(存数据)+ schema(数据的(额外信息:元数据):字段、字段类型) =》 table
=》1.2/3
=> DataFrame =>schemaRDD 变过来的
=》1.6
=》 DataSet =》 DataFrame 变过来的
DataFrame /df vs rdd:
DataFrame和rdd区别:
1.rdd : 不同的语言开发的 rdd ,执行性能是不一样
java和scala(会被语言转换为jvm去运行)、python(pathon会转化成自己的运行时数据区去运行,pathon开发rdd性能没有java和scala高)
2.DataFrame/df:使用不同的开发语言 执行性能是一样的 (spark底层逻辑优化=》物理执行计划=》rdd执行,此时执行性能和语言就没有关系了),df比rdd开发简单
SparkSQL程序开发入口 :SparkSession
获取df后会立即触发job,不是懒加载
df.show(2,false) 显示2条数据,显示所有字符串长度,默认截至字符串20字节
df.printSchema()
df.createOrReplaceTempView(“tmp”)
spark.sql(
“”"
|select count(1) as cnt from tmp
|“”".stripMargin).show()
构建dataframe
三种方式:
existing RDD, from a Hive table, or from Spark data sources
schema: table 元数据【字段名字、字段的类型】 =》 StructType
fileds: 一个字段的元数据 =》 StructField

val schema: StructType = StructType(Array(StructField("uid", StringType), StructField("name", StringType), StructField("age", IntegerType)))
    val inputDF: DataFrame = spark.createDataFrame(rowRDD, schema)

如何把rdd转变成df、ds?

rdd =》 toDF / => toDS
如何把 df/ds => rdd ?
df/ds.rdd
df 如何转变成ds ?
df.as[数据类型] =》 ds

text文件

本身是不带有schema信息 【字段 value string 】
text 比 json csv 带有的schema信息偏少,只有一个value字段
1.text文件加载进来之后 需要解析数据 需要引入隐式转换
2.文本类型不支持Int类型
3.写数据时
Text data source supports only a single column, and you have 3 columns.
Text仅仅支持一列(一个字段)输出 不支持多列输出
使用sparksql 支持text多列输出?
1.自定义外部数据源 =》 难度
2.df 转变成rdd方式进行输出 =》 常用的手段

json

1.普通json
2.嵌套json:
1.api:
struct:打点
array:expolde + struct:打点
2.sql:
hive
struct:打点
array:expolde + struct:打点
3.不规范json =》udf函数来解决
数据输出:
数据写出方式:
1.覆盖 overwrite
2.追加 append

csv

csv文件 excel=> spark-excel
1.可以使用excel打开
2.默认字段之间的分割符 , [可以进行更改]
常用参数:
read:
1.sep 分割符 ,
2.header 第一行作为table中的字段
3.inferSchema 类型推断功能
4.encoding 指定读取的csv文件的字符集 默认utf-8
write:
compression
sep
encoding

jdbc

  val data: DataFrame = spark.read.format("jdbc")
      .option("url", "jdbc:mysql://bigdata12:3306/bigdata")
      .option("dbtable", s"($inputsql) as tmp")
      .option("user", "root")
      .option("password", "123456")
      .load()
      
    data.show(false)
    data.printSchema()
    
    val url = "jdbc:mysql://bigdata12:3306/bigdata"
    val table = "dept01"
    val properties: Properties = new Properties()
    properties.setProperty("user","root")
    properties.setProperty("password","123456")
    data.write.mode(SaveMode.Append).jdbc(url,table,properties)

spark-sql -e/-f xxx.sql => sparksql => 推荐的方式 离线数仓 好维护 简单
drop table if exists bigdata.dws_user_log

以yarn方式进行部署【面试】

  1.  client : driver   =》 提交机器
     cluster: driver  =》 集群内部的 
    

2.提交作业有关
cluster :
提交作业 client作业提交 client就可以关闭了 对spark作业是没有影响的
client:
提交作业 client作业提交 如果client关闭了 driver process 挂了 对spark作业有影响的
3.输出日志
client =》 可以直接查看日志
cluster =》 yarn上去看运行日志

数据写入hive

insert overwrite table bigdata.result01
select *
from result

insert overwrite table bigdata.result02 partition(month=‘2017-01’)
select
uid,
cnt,
total_cnt
from result
where month='2017-01

spark.conf.set(“hive.exec.dynamic.partition”,“true”)
spark.conf.set(“hive.exec.dynamic.partition.mode”,“nonstrict”)
spark.sql(
“”"
|–1.动态分区
|insert overwrite table bigdata.result02 partition(month)
|select
|uid,
|cnt,
|month,
|total_cnt
|from result
|“”".stripMargin)
saveAsTable(不能用!!!):建分区表时,会自动建表默认是动态分区,没办法建静态分区
insertInto.overwrite时操作的是table,不是具体的partition
解决方法:用SaveMode.Append,修改分区dt的过滤条件 select * from tmp where month=‘2017-01’
但是SaveMode.Append相同分区再次修改会出现数据重复,要解决幂等性的问题
解决方法:
1.删除对应分区hdfs上数据 =》hdfs api
2.删除对应分区 元数据 =》 alter table xxx drop partition
3.api 写入对应分区 hdfs 上数据 =》sparksql api
4.api 加上对应分区 元数据 =》alter table xxx add partition或者msck repair table xxx
insertInto不能和partitionBy连用 不能用于写入分区表!!!partitionBy用来指定分区

catalog

hive元数据 mysql里面:
spark2.0之前 spark 想要访问hive元数据 要通过jdbc 连接,取数据
spark2.0之后 调用catalog 就可以拿到 hive元数据的内容
拿到hive元数据=》 做什么事情?
大数据平台: 哪些表是热表哪些表是冷表,哪些表什么时间段进来数据什么时间段出去数据,数据分析平台都可以利用元数据去取数据

spark-shell 以yarn方式运行 client/cluster都能启动嘛

client可以,cluster不可以
因为spark-shell是交互式脚本,它的driver就在提交机器上,client的driver也在提交机器上,而cluster的driver在集群内部

udf

hive udf 可以在sparksql里面直接使用:
使用场景 : xxx.sql
hive jar: add jar xx.jar
create function 方法名字 as copy reference

/**
     * udf:f(x)
     * 添加一个随机数前缀
     * u01 => 9_u01
     */
    spark.udf.register("addRandom",(input:String) => {
      Random.nextInt(10)+"_"+input
    })

udaf:一进一出
udtf:一进多出

sparkstreamig+kafka DStream

批处理/离线计算
一次性处理某一个批次的数据 数据是有始有终的
流处理:
水龙头 数据是远远不断的来 数据没有始终 event基于事件的方式进行计算真正的实时计算 mini-batch近实时
数据积压:kafka数据多,spark消费能力不足,导致kafka数据大量积压
解决方法:减少spark批处理时间,提高spark消费能力
增加kafka分区数,提高吞吐量
修改kafka参数
sparkstreaming编程模型:DStream
sparkcore:rdd
sparksql :ds、df
Stream data 按照时间把数据拆分一个一个的 batch(batch就是一个一个的rdd )
流式处理:
对 DStream进行转换操作
实际上就是对 DStream里面的rdd进行操作
对rdd进行操作就是对 rdd里面分区的元素进行操作
总结: 程序入口
sparkstreaming :StreamingContext
sparkcore: sparkcontext
sparksql: sparksession
实时计算处理数据的qps是多少?
qps指的是计算程序每秒钟处理的数据是多少条
spark处理 当前批次的数据的结果 不能处理 累计批次的数据
累计批次:多个批次之间又联系的

如何构建DStream?

1.外部数据源【kafka】
2.Receivers 【接收流 测试使用 生产上不用】: 为面试准备
并不是所有的接收数据都需要接收器
底层DStream前面带Receiver的就是接收流
Receiver:master =》 local[2] => local[1] code能否处理数据?【面试】
sparkstreaming: 1 cpu =》 1 core
1.接收流式数据 ok 需要1core去接收数据
2.流式数据 切分成 batch进行处理 no ok cpu不够 你的数据没有资源进行处理
要求:master cpu 个数 一定要大于Receiver 数量
什么是Receiver? 指的就是 接收数据形成的流 看底层返回值 底层DStream前面带Receiver的就是接收流 接收器

updateStateByKey 用于解决 有状态问题

1.有状态 前后批次有联系的
2.无状态 前后批次是没有联系的
updateStateByKey 算子解决
1.Define the state
2.Define the state update function
注意: 得指定 The checkpoint directory has not been set

ssc.checkpoint("file:///F:\\bigdata\\ideaProject\\spark-2262\\data\\checkpoint")
    val lines = ssc.socketTextStream("bigdata12", 9999)
    val words = lines.flatMap(_.split(" "))
    val pairs = words.map(word => (word, 1))
    val wordCounts = pairs.updateStateByKey(updateFunction)
    wordCounts.print()
    ssc.start()
    ssc.awaitTermination()
  }
  /**
   * Option some none
   * @param newValues 最新批次的数据 (a,<1,1,1>)
   * @param preValues 以前批次的一个累加值 (a,3)
   * @return
   */
  def updateFunction(newValues: Seq[Int], preValues: Option[Int]): Option[Int] = {
    val curr_sum: Int = newValues.sum
    val pre_sum: Int = preValues.getOrElse(0)// 取到了就取到了,取不到就给个0
    Some(curr_sum+pre_sum)
  }
}

总结:
1.为什么要指定checkpoint?
1.维护 当前批次和以前的累计批次数据的state
2.checkpoint 目录 生产上 得指定到 hdfs上进行存储?
存在问题:
1.checkpoint 每个批次都会产生 文件 =》 hdfs 扛不住 挂掉的风险
checkpoint 的作用 针对sparkstreaming来说
【checkpoint这个东西 生产上用不了 了解它 即可 面试准备】
1.作用:
1.为了容错
2.恢复作业【实时计算作业 挂掉之后 可以恢复起来】
2.checkpoint存储的东西:
1.Metadata 元数据
Configuration 作业里面配置信息
DStream operations 作业code里面的算子操作
Incomplete batches 未完成的批次
2.Data
每个批次里面真正传过来的数据 +stateful转换
3.使用场景
1.Usage of stateful transformations
2.Recovering from failures of the driver running the application
恢复作业
4.如何正确使用checkpint?
如果你想要 恢复application 需要 正确编写 checkpoint设置代码
注意:
checkpoint缺点:
1.小文件多
2.修改代码程序就用不了【修改业务逻辑代码】
checkpoint 用不了生产上 =》 累计批次指标统计问题 updateStateByKey这个算子 也用不了!!!
那么如何实现 累计批次统计需求?
1.把每个批次数据 写到外部存储
2.然后利用外部存储系统再统计即可
1.某个东西没有进行序列化?
1.MySQL连接驱动没有进行序列化 【做不了】
2.ClosureCleaner
Closure 闭包的 意思
闭包的: 方法内使用了方法外的变量
2.正确写法:
rdd.foreachPartition{
mysql 连接次数 会减少 rdd有多少个分区 就有多少个连接
}

//data output => mysql
    wordCounts.foreachRDD(rdd => {
      // mysql clickhouse drios phoenix
      // 只有mysql连接不支持序列化,其他三个都支持
//      rdd.foreach(pair => {// executor
//        val conn: Connection = MySQLUtil.getConnection()
//        val sql = s"insert into wc(word,cnt) values('${pair._1}','${pair._2}')"
//        conn.createStatement().execute(sql)
//        conn.close()
//      })
      //rdd.coalesce(10).foreachPartition()
      // 如果连接有序列化可以把连接放在这
      rdd.foreachPartition(partition => {
        val conn: Connection = MySQLUtil.getConnection()
        partition.foreach(pair => {
          val sql = s"insert into wc(word,cnt) values('${pair._1}','${pair._2}')"
          conn.createStatement().execute(sql)
        })
        conn.close()
         // sparksql的方式写出 推荐
      val spark = SparkSession.builder.config(rdd.sparkContext.getConf).getOrCreate()
      import spark.implicits._
      val df: DataFrame = rdd.toDF("word", "cnt")
      df.printSchema()
      df.show()
      val url = "jdbc:mysql://bigdata12:3306/bigdata"
      val table = "rpt_cnt_top3"
      val properties: Properties = new Properties()
      properties.setProperty("user","root")
      properties.setProperty("password","123456")
      df.write.mode(SaveMode.Append).jdbc(url,table,properties)
      })
      })

如果 rdd.foreachPartition 写数据 存在存储性能问题: 【一般不用,可以使用!!!】
1.可以使用连接池
2.rdd.coalse =》 减少rdd分区数
lsof -i:3000 查看端口占没占用

转换算子transform

transform =》 DStream 和 rdd之间数据进行交互的算子

 val log_kv: DStream[(String, Int)] = logs.map(word => (word, 1))
    val black_kv: RDD[(String, Boolean)] = black.map(line => (line, true))
    val result: DStream[String] = log_kv.transform(rdd => {
      rdd.leftOuterJoin(black_kv)
        .filter(_._2._2.getOrElse(false) != true)
        .map(_._1)
    })

sparkstreaming + kafka 整合

kafka 数据源=》 sparkstreaming 消费
spark 去kafka读取数据的方式:
1.kafka 0.8 reciver方式读取kafka数据 【效率低 、代码开发复杂】
2.kafka 0.10.0版本之后 direct stream的方式加载kafka数据 【效率高、代码开发简单】
kafka:
版本也有要求:
0.11.0 版本之后
交付语义: consumer producer
producer 默认就是精准一次
consumer 交付语义取决于 consumer 框架本身
交付语义: consumer
至多一次 数据丢失问题
至少一次 数据不会丢失,数据重复消费
精准一次 数据不会丢失 数据也不会重复消费
spark 整合kafka 版本 0.10.0版本之后:
1.kafka 0.11.0之后 reciver => direct stream
2.sparkstreaming 默认消费kafka数据 交付语义: 至少一次
spark消费kafka, DStream 【rdd 分区数】 =》 kafka topic 分区数 是一一对应的

offset

spark作业挂掉 =》 重启
“消费完kafka的数据 程序重启之后接着从上次消费的位置接着消费 ”
目前代码 这两个参数 不能动
“auto.offset.reset” -> “earliest”
“enable.auto.commit” -> (false: java.lang.Boolean)
1.获取kafka 流数据
2. 流 Dstream =》 调用foreachRDD算子 进行输出:
0.获取offset 信息
1.做业务逻辑
2.结果数据输出
3.提交offset信息
rdd的分区数:3
topic partition fromOffset untilOffset
spark-kafka01 0 1 1
spark-kafka01 1 1 1
spark-kafka01 2 0 0
此时 kafka 里面数据已经消费完了 fromOffset=untilOffset
精准一次:output + 提交offset 一起发生 =》 事务来实现
事务: 一次操作要么都成功 要么都失败 ,失败时会发生回滚操作
存储offset:
kafka 本身:
offset 信息存储在哪?
kafka 某个topic下:
__consumer_offsets =》 spark作业 消费kafka topic offset 信息存储的地方

kafka 消息中间件

1.distributed event streaming platform kafka是一个流式 分布式平台
2.构建 实时的数据通道 、流式数据分析、流式的app
版本选择:
1.稳定版本即可 可以选择最新版本【bug就是多】
2.根据 Sparkstreaming 来选择kafka的版本 !!!!
1.spark对接kafka 的最低版本 0.10版本 【spark 3.x版本】
2.【spark 2.x版本】
kafka:
0.10
0.11
0.11之后的版本
版本选择
建议 kafka 2.2.1 或者 最新版
kafka的特性:
1.HIGH THROUGHPUT 高吞吐量
2.SCALABLE 高扩展性
3.PERMANENT STORAGE 数据过期时间
4.HIGH AVAILABILITY 高可用
kafka特点
1.发布&订阅
2. store 存储
3. process 处理 :
kafka后面接一个 实时计算的框架 : spark/flink 正确使用
kafka的架构
生产者(producer):消息发送端
event:表示 produce 发送的一条数据
broker:kafka集群里面某一个节点
消费者(consumer):消息消费端
1.topic 主题
1.负责存储events
2.消息订阅和发送基于topic
消息订阅 :
消费者 订阅topic:即可以消费topic里面存储的数据
消息发送:
生产者 往指定topic发送数据
3.kafka中可以有多个topic
topic里面有:
partition:分区
1.一个topic可以有多个partition
2.每个partition是一个有序的队列 =》单分区有序
3.partition linux上的文件夹
创建topic时partition的随便指定
replication-factor topic的副本数 小于等于 broker数量
副本 =》 容错
查看详细的topic时第一行: topic总体情况:topic名字、分区数量、副本数量
Partition:分区号
Leader、Replicas、Isr:kafka 机器broker 对应的编号
Leader 1:该分区 负责对外读写的节点编号
Replicas:当前分区副本都在哪些机器上
Isr:负责对外提供读写请求的 leader顺序
生产上不要删除或修改 topic
kafka 里topic的元数据 zookeeper里面的

生产者

Properties props = new Properties();
        props.put("bootstrap.servers", "bigdata12:9092");// kafka地址
        props.put("acks", "all");
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        // 发送数据到kafka topic:dl2262
        Producer<String, String> producer = new KafkaProducer<>(props);
        for (int i = 0; i < 9; i++) {
            logger.warn("mes:{}",i);
            // key是分区号 value是真正要发送的数据
            int partition = new Random().nextInt(3);
            producer.send(new ProducerRecord<>("dl2262",partition+"" ,i+""));
        }
        producer.close();

消费者

Properties props = new Properties();
        props.setProperty("bootstrap.servers", "bigdata12:9092");
        props.setProperty(ConsumerConfig.GROUP_ID_CONFIG, "test");
        props.setProperty("enable.auto.commit", "true");
        props.setProperty("auto.commit.interval.ms", "1000");
        props.setProperty("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.setProperty("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        props.setProperty(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
        props.setProperty(ConsumerConfig.SESSION_TIMEOUT_MS_CONFIG,"30000");
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
        // 订阅topic
        // consumer.subscribe(Arrays.asList("d1","d2"));
        consumer.subscribe(Collections.singletonList("dl2262"));
        // 消费数据
        while (true){
            ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
            Iterator<ConsumerRecord<String, String>> iterator = records.iterator();
            while (iterator.hasNext()){
                ConsumerRecord<String, String> record = iterator.next();
                Thread.sleep(1000);
                System.out.println("partition"+record.partition()+", "+"offset"+record.offset()+", "+"value"+record.value());

消费者与消费者组

消费者消费kafka里面的数据 是以 消费者组的方式进行消费
consumer group: 消费者组
1.一个组内 共享一个消费者组的id 【group id】
2.组内的所有消费者协调在一起去消费指定的topic的所有分区数据:
“每个分区只能由一个消费者组的一个消费者来消费”
绝对不会出现一个分区被一个消费者组的多个消费者进行重复消费

kafka数据存储

一个partition:下面存储就是数据,一段一段相同大小的segment文件
segment:逻辑概念 log.segment.bytes------segment默认大小,segment包括:
log文件 【kafka topic里面的数据+event 元数据】 默认大小
:log.segment.bytes=1073741824 1G
index文件 【索引文件,维护是log文件内 大部分数据的位置信息】
segment命名规则:
1.parititon的全局的第一个segment 编号从0开始的
2.后续的segment名称 是上一个segment文件的最后一条消息的【offset值+1】 来表示
offset:偏移量 =》 event 编号 存储在topic下的编号
指 该条数据在partition的位置 从0开始
index:
offset: 47 position: 4174
offset: 94 position: 8357
offset: 140 position: 12492
offset: 186 position: 16632
offset: 232 position: 20772
1.维护partition的消息对应offset信息和物理地址
2.稀疏表的方式维护的,并不是每一个消息的offset和物理地址都维护

如何查找 offset 为 11865的数据 ,简述过程?

1.【二分查找】 <= offset 为 11865 的最大segment文件组 =》11518组
2.去11518.index 文件 【二分查找】<= offset 为 11865 最大的offset
=》offset: 11842 =>position: 166515 物理地址
3.根据166515 物理地址 去信息定位 这个位置,按顺序查找 一直找到 offset为11865的数据

交付语义 : 生产者/消费者

至多一次:消息会丢失,不会重复发送/消费
至少一次:消息不会丢失 重复发送/消费
精准一次:消息不会丢失 不会重复发送/消费
produder:
1.kafka 0.11.0之前版本 采用至少一次 会导致重复数据
2.kafka 0.11.0之后包括 采用精准一次 发送数据
消费 交付语义选择:
1.至少一次 =》 可能有数据消费重复问题 [90%] code 简单
2.精准一次 =》 完美的 【开发起来太麻烦了 】

sparkstreaming

sparkstreaming:【了解】
offset信息如何维护?
1.Checkpoints 【生产上,不能用 问题】
1.offset 信息 =》 hdfs 会有小文件问题
2.代码发生变更 spark项目就不能用了 之前记录的Checkpoints 信息就失效了
2.Kafka itself 【推荐】
【至少一次】 代码简单 不需要用户自己开发 维护offset信息的代码
3.Your own data store 【外部数据源存储 offset】
redis、mysql、hbase 事务的 精准一次

副本与数据同步

leader 与 follower:
leader: 该分区负责对外读写的节点
follower:负责拉取leader分区数据 进行数据备份
机制:
ack 消息发送确认机制 【producer】
all, -1, 0, 1
1.ack =1 producer 发送数据 只要一个分区副本成功写入的通知 就认为推送消息成功
2.ack =-1 producer 发送数据 producer收到所有分区副本写入成功的通知才任务推送消息成功
3.ack=0 producer 发送一次数据即可 不管是否发送成功
all => -1

kafka监控

1.kafka manager [首选 ]: 二开 【了解】
https://github.com/yahoo/CMAK
按量计费
2.kafka eagle =》 也好用 【low 一点点 】 用起来简单
部署简单 简单好用
http://www.kafka-eagle.org/
https://github.com/smartloli/EFAK

flume 采集日志数据

组件: source 采集数据
channel 存储采集过来的数据
sink 把采集来的数据发送出去
agent:
source:
avro 序列化框架 source ****
exec 日志文件 **
spooling dir 日志文件 **
taildir Source 日志文件 ****
Kafka Source **
NetCat TCP port采集数据 **
Custom 用户自己开发 *
channel :
Memory ****
File ****
JDBC *
Kafka *
Custom 用户自己开发 *
sink:
HDFS Sink ****
Hive Sink ****
Logger Sink 打印控制台 **
Avro Sink ****
HBaseSinks *
Kafka Sink ***
Custom Sink 用户自己开发
event:一条数据
headers:描述信息
body:存的是实实在在的数据

采集日志文件

1.exec
exec :linux 命令进行采集数据,只能使用tail -F
tail -F:
在第二个会话加echo “11111111” >> 2.log 时,第一个会话会显示上第二个会话加上的东西,当第二个会话删除2.log时,会显示已被删除,第二个会话再次建立vim 2.log时,第一个会话会显示已连接,第二个会话再次加东西时,第一个会话还会显示
tail -f:
在第二个会话加echo “00000000” >> 2.log 时,第一个会话会显示上第二个会话加上的东西,但是当第二个会话删除2.log时,不会显示已被删除,第二个会话再次建立vim 2.log时第一个会话也不会显示
exec存在的问题:采集过的日志内容 flume挂掉了 重启 会导致 数据重复采集
2.spooldir :采集某个文件夹下面的文件(生产上 不能用)
spool 采集某个目录下,文件名 不能重复,如果文件名重复,不会继续采集日志,flume 挂掉
3.tairdir 采集指定文件以及文件夹的内容
采集某个文件夹下面的文件 采集某一个文件
支持”断点续传“ 挂了之后重启不会重复采集数据

为什么flume 采集数据 到hdfs ? 文件查看不了?

flume配置有关:hdfs=》文件存储格式 不是text
需要修改:1.hdfs.fileType =》 DataStream
2.hdfs.writeFormat =》 Text

解决输出到hdfs上小文件问题

a1.sinks.k1.hdfs.rollInterval=60
a1.sinks.k1.hdfs.rollSize=134217728
a1.sinks.k1.hdfs.rollCount=1000

修改文件前后缀

a1.sinks.k1.hdfs.filePrefix=events
a1.sinks.k1.hdfs.fileSuffix=.log
a1.sinks.k1.hdfs.useLocalTimeStamp=true

数据延迟问题

数据落盘依照的时间是本地机器的时间,而不是 数据本身的时间从而导致数据延迟问题
解决延迟数据问题:
1.udf函数 hive
正确的数据重新落盘到正确的分区
2.header 添加数据本身的时间 => 保证 正确数据落到正确分区二次开发 flume

恢复数据

删除分区表:alter table xxx drop partition(deptno=10);
1.hdfs 有数据
2.元数据 没有
=》 之前如果hdfs数据和元数据不 同时 都存在时,hive table 是查不了数据的
hive 3.1.2版本可以
alter table emp_p add partition(deptno=10);元数据和hdfs上数据就相关联了

压缩数据

a1.sinks.k1.hdfs.fileSuffix=.bzip2
a1.sinks.k1.hdfs.fileType=CompressedStream
a1.sinks.k1.hdfs.codeC=bzip2

多输出sink时 控制输出均衡:load_balance

agent1.sinkgroups = g1
agent1.sinkgroups.g1.sinks = k1 k2
agent1.sinkgroups.g1.processor.type = load_balance
agent1.sinkgroups.g1.processor.backoff = true
agent1.sinkgroups.g1.processor.selector = round_robin/random
agent1.sinkgroups.g1.processor.selector.maxTimeOut=2000
均衡:load_balance
1.将数据分开 提供并行度的功能 减轻sink 压力
2.如果 第二个或者第三个 agent挂掉 数据都会发送到 没挂的sink 对应的agent上面
1.随机发送数据:random
2.轮循发送数据:round_robin

负载 Failover

agent1.sinkgroups = g1
agent1.sinkgroups.g1.sinks = k1 k2
agent1.sinkgroups.g1.processor.type = failover
agent1.sinkgroups.g1.processor.priority.k1 = 5
agent1.sinkgroups.g1.processor.priority.k2 = 10
agent1.sinkgroups.g1.processor.maxpenalty = 2000
容灾:sink 出现故障
负载常用来处理sink出故障时,常于均衡连用

flume核心组件

interceptors 拦截器 => 主要处理 采集的数据 进行数据转换/数据清洗的操作和数据分发
agent1.sources.r1.interceptors = i1
agent1.sources.r1.interceptors.i1.type = static
agent1.sources.r1.interceptors.i1.key = dl2262
agent1.sources.r1.interceptors.i1.value = boy***
***agent4.sources.r1.selector.type = multiplexing
agent4.sources.r1.selector.header = dl2262
agent4.sources.r1.selector.mapping.boy = c1
agent4.sources.r1.selector.mapping.girl = c2
agent4.sources.r1.selector.default = c3
多种日志采集到一个agent里面 之后 通过这个agent进行指定数据分发

channel selectors =》 采集的数据 发送到哪个 channle
agent1.sources.r1.selector.type = replicating 两个channel数据同步
sink processers =》 采集的数据 发送到 哪个sink

监控channel json方式 通过http接口 对进行channle监控

启动时加上***-Dflume.monitoring.type=http
-Dflume.monitoring.port=9527
http://bigdata12:9527/metrics***
channle:
1.默认容量
capacity 100
2.事务容量
transactionCapacity 100
souce -》channle
channle =》 sink
手段:
1.flume 提供 ganglia 框架 指标 【需要安装ganglia + 】
2.通过 agent 启动 配置一些参数 http 方式获取 【建议用这个 easy】
json数据 =》 http接口数据 =》1.前端人员 可视化界面展示
2.采集 http接口数据 =》 mysql =》 可视化
参数解释:
SOURCE:
OpenConnectionCount(打开的连接数)
Type(组件类型)
AppendBatchAcceptedCount(追加到channel中的批数量)
AppendBatchReceivedCount(source端刚刚追加的批数量)
EventAcceptedCount(成功放入channel的event数量)
AppendReceivedCount(source追加目前收到的数量)
StartTime(组件开始时间)
StopTime(组件停止时间)
EventReceivedCount(source端成功收到的event数量)
AppendAcceptedCount(放入channel的event数量)
CHANNEL:
EventPutSuccessCount(成功放入channel的event数量)
ChannelFillPercentage(通道使用比例)
Type(组件类型)
EventPutAttemptCount(尝试放入将event放入channel的次数)
ChannelSize(目前在channel中的event数量)
StartTime(组件开始时间)
StopTime(组件停止时间)
EventTakeSuccessCount(从channel中成功取走的event数量)
ChannelCapacity(通道容量)
EventTakeAttemptCount(尝试从channel中取走event的次数)
SINK
BatchCompleteCount(完成的批数量)
ConnectionFailedCount(连接失败数)
EventDrainAttemptCount(尝试提交的event数量)
ConnectionCreatedCount(创建连接数)
Type(组件类型)
BatchEmptyCount(批量取空的数量)
ConnectionClosedCount(关闭连接数量)
EventDrainSuccessCount(成功发送event的数量)
StartTime(组件开始时间)
StopTime(组件停止时间)
BatchUnderflowCount(正处于批量处理的batch数)

hive

构建在hadoop之上的数据仓库
适用于离线/批处理
版本介绍: x.y.z
x 大版本
y 小版本
z 小版本的bug修复
spark on hive =》 sparksql 查询hive的里面表
hive仅仅就是个客户端而已,不存在集群的概念,构建在hadoop之上的,相当于在hadoop之上做了一个客户端完成数据分析
Metastore 【Hive的元数据管理】
sparksql presto impala 只要能够访问hive 的Metastore元数据 ,就可以访问 Hive里面表的数据,hive和其他框架可以共享元数据【可以共享Metastore】,相当于后面的计算框架只需要负责计算就可以,不需要负责存储,存储的功能交给hive,因为hive既要负责存储也要负责计算,如果觉得hive计算慢就用之后的计算框架,直接查询hive里面的元数据,就可以访问hive表里面的数据,进而进行数据的分析计算
MySQL:
TBLS 存的是Hive里面表的信息
DBS 存的是Hive 数据库相关的信息
COLUMNS_V2 存的是Hive table里面的字段信息
DATABASE_PARAMS 存的是Hive 数据库相关的信息
hive -e xxx.sql 语句
-f xxx.sql文件

hive和RDBMS关系型数据库(关系型数据库首选mysql)的区别【面试】

1.共同点:都可以使用sql
2.延时性(处理数据快慢):hive适用于离线计算,处理数据慢,千万不要拿hive和mysql的执行性能对比,数据量都很小时,mysql处理性能高些,数据量上来之后mysql执行性能要比hive低
3.事务(一次操作要么成功要么失败):都支持,但hive不关心事务,mysql可能会用到事务
4. update delete这两个语句hive和mysql都有,但hive不会更新某个表的某条数据,hive里面基本不用, 因为性能太差,我们不是通过这种方式更新数据的
5.分布式 都支持
6.成本:hive部署机器比较廉价,对机器要求不高,mysql对机器要求高,成本高
7.数据体量: hive操作数据量很大,mysql存TB级别的数据处理就很慢

hive sql语法

CREATE TABLE [IF NOT EXISTS] table_name
row format delimited fields terminated by ‘,’
stored as textfile
desc extended test;
desc formatted test;
导入数据:
LOAD DATA [LOCAL] INPATH ‘filepath’ [OVERWRITE] INTO TABLE tablename [PARTITION (partcol1=val1, partcol2=val2 …)]
create table emp3 as select * from emp;
insert into(追加数据)|overwrite(覆盖数据) table tablename selectQury
update delete => hive 不要用 效率低
Inserting values into tables from SQL
truncate table emp2;
union 去重
union all 不去重
union和union all 字段个数和字段类型相同即可
空值处理:coalesce(null,null,1)
nvl(null,1)
ifnull => hive里没有
show functions like nvl; => 判断 function hive 是否存在
desc function nvl; =》 查看某个函数具体使用
where在group by之前使用
where和order by不能使用别名
order by在group by之后使用

内部表和外部表的区别

内部表(MANAGED_TABLE) [受hive管控的表] 建表时默认内部表
外部表:EXTERNAL
create时已经将元数据和hdfs上的数据连接上了
load不仅是上传数据,还会将hdfs上数据和元数据进行关联
区别:
删除一个内部表时,表中的数据(hdfs)和元数据(mysql)都会被删除
删除一个外部表时,表中数据(hdfs)不会被删除,元数据(mysql)会被删除
重新创建create一下外部表,就可以恢复误删的外部表了
内部表和外部表的转变:
alter table emp_external set tblproperties (“EXTERNAL”=“false”);
alter table emp_external set tblproperties (“EXTERNAL”=“true”);
alter table emp_external set tblproperties (“external”=“false”); =》 小写不行

复杂数据类型

1.arrays: ARRAY<data_type>

create table hive_array(
name string,
locations array<string>
)
row format  delimited fields terminated by '\t'   每个字段之间以\t进行分隔
collection items terminated by ',';   集合间的元素以,进行分隔

A[n] 取出数组的第几位

select name,locations[0] as first_loc_work from hive_array;

size(Array 计算数组的长度

select name,size(locations) as cnt from hive_array;

boolean array_contains<Array,value> 判断数组中是否存在某个元素

select * from hive_array where array_contains(locations,'shanghai');
select * from hive_array where array_contains(locations,'dalian');

行转列:
Lateral View 侧写视图:
lateral view udtf(expression) tableAlias as columnAlias
udtf =》传一个返回多个 =》 一进多出

select
name,location
from hive_array lateral view explode(locations) loc_table as location;
  1. maps: MAP<primitive_type, data_type>
create table hive_map(
id int  comment '用户id',
name string comment '用户名字',
relation map<string,string> comment '家庭成员',
age int comment '年龄'
)
row format  delimited fields terminated by ','
collection items terminated by '#'
map keys terminated by ':';

M[key]通过key取value

select id,name,age,relation['father'] as father from hive_map;

map_keys(Map <k.v>) 取出key

select id,name,age,map_keys(relation) as members from hive_map;

map_values(Map <k.v>)取出value

select id,name,age,map_values(relation) as members from hive_map;

3.structs:STRUCT<col_name : data_type>

create table hive_struct(
    ip string,
    userinfo struct<name:string,age:int>
)
row format delimited fields terminated by '#'
collection items terminated by ':';

取出结构体中的对应属性----S.x

select ip,userinfo.name as name,userinfo.age as age
from hive_struct;

分区表

create table order_info(
   order_id string,
   order_time string 
)partitioned by (dt string)
row format delimited fields terminated by '\t';
load data local inpath'/home/hadoop/tmp/order.txt' (overwrite)into table order_info partition(dt='20211014');
insert into/overwrite table emp_p partition(deptno=20)
insert into/overwrite table emp_p partition(deptno=20)
select
empno,
ename,
job  ,
mgr  ,
hiredate,
sal  ,
comm 
from emp where deptno=20;
show partitions order_info;
alter table order_info drop partition(dt='__HIVE_DEFAULT_PARTITION__');
这个分区hdfs上数据和mysql上的元数据都会被删除

开窗函数

rank() 从1开始 按照顺序 生产分组内记录的编号,排序相同会重复 在名次中留下空位
row_number(): 从1开始 按照顺序 生产分组内记录的编号,排序相同不会重复
dense_rank():从1开始 按照顺序 生产分组内记录的编号,排序相同会重复 在名次中不会留下空位

维度组合分析 grouping sets

select
shop,
user_id,
channle,
os
from user_shop_log
group by
shop,
user_id,
channle,
os
grouping sets(
    (shop),
    (shop,user_id),
    (shop,channle),
    (shop,os),
    (shop,user_id,channle),
    (shop,user_id,os),
    (shop,channle,os),
    (shop,user_id,channle,os),
    (user_id),
    (user_id,channle),
    (user_id,os),
    (user_id,channle,os),
    (channle),
    (channle,os),
    (os)
);

列转行和行转列

列传行:
聚合函数:array collect_set(col) 集合里的数据不可重复
聚合函数:array collect_list(col) 集合里的数据可重复

create table t1(
    name string,
    interesting string
)
row format delimited fields terminated by ',';
load data local inpath'/home/hadoop/tmp/t1.txt' into table t1;

select
name,
collect_list(interesting) as interestings
from t1
group by name;
// zuan	["王者荣耀","吃饭","rap","唱歌"]

拼接:
1.string concat =》 字符串拼接

select concat("tom","|","jack","|","marry");
// tom|jack|marry

2.string concat_ws(string SEP, string A, string B…(可变参数)) =》 字符串拼接

select concat_ws("|","tom","jack","marry");
// tom|jack|marry

split返回一个数组
类型转换cast(expr as )
cast(sql as bigint) as sql_alias

四大by–order by,sort by,cluster by,distribute by

order by 全局排序 reduce只有一个,reduce阶段仅仅有一个task进行处理,性能不高(不影响用)
当安全模式开启时,order by需要加上limit使用
partition分区需要加上where使用
sort by 分区排序 reduce task个数按照reduce有多少个进行排序的 不能保证全局有序
hive里面reduce task个数默认为-1,会自动改变,hadoop里reduce task默认是1
如果 你的reduce task 个数是1 order by 和sort by 效果是一样的
Distribute By 数据分发
Distribute By意思是把我的数据发送到哪个分区,按照分区发送到哪个reduce task上,发送完之后按照sort by进行分区排序
map阶段到reduce阶段默认是按照hash,为了防止数据倾斜(一个map或者reduce处理很多,另一个map或者reduce处理很少),我们可以指定分发
Cluster By是distribute by和sort by的简写
distribute by year sort by year 《=》 Cluster By year 正确
当distribute by xxx和sort by xxx后面指定相同时,就等同于cluster by xxx

文件存储格式

1.行式存储:
1.一行内容所有的列都在一个 block里面
2.里面的列 掺杂很多数据类型
行式存储加载 是把所有的列都查询出来 再过滤出 用户需要的列
如果用户 仅仅查几个字段 =》 磁盘io 开销比较大
2.列式存储
按照列进行存储

Function:

show functions like upper; => hive内置函数是否有 upper
desc function extended upper; =》 查看uppper 函数详细使用
时间相关函数:
1.current_date => 打印当前时间
2.date_format( ,‘yyyy-MM-dd HH:mm:ss’))
3.date_add/date_sub/last_day
datediff 查看日期相差的天数
4.add_months
months_between 查看日期相差几个月
算术相关函数
1.round 四舍五入:select round(3.8769123,3); 3.877
2.ceil 向上取整 >= select ceil(4.56);5 select ceil(-7.6);-7 select ceil(5);5
3.floor 向下取整 <= select floor(5);5 select floor(3.14);3 select floor(-3.14);-4
4.rand() (0,1)
select rand(); 0.45868403341590114
select 10rand(); 7.314893834590635
字符串相关函数:
upper select upper(‘abc’); ABC
lower select lower(‘ABC’); abc
length select length(‘dl2262’); 6
trim 去掉前后的空格,不能去掉中间的空格 select trim(’ ab c d e ‘); ab c d e
lpad 左边补全 select lpad(‘hi’,6,’?'); ??_hi select lpad(‘hi’,1,‘>?’);h
rpad 右边补齐 select rpad(‘hi’,8,'<
>‘); hi<><>
replace/ regexp_replace
select replace(‘hi and hello’,‘h’,‘H’); Hi and Hello
select regexp_replace(‘dl2262’,’[0-9]‘,‘num’); dlnumnumnumnum
select regexp_replace(‘dl2262’,’[0-9 || a-z]‘,‘num’); numnumnumnumnumnum
substr 字符串截取 select substr(‘Facebook’,5,4); book select substr(‘Facebook’,-5);ebook
concat 字符串拼接 select concat(‘a’,’,‘,‘b’,’,‘,‘c’); a,b,c
concat_ws 字符串拼接 select concat_ws(’,‘,array(‘a’,‘b’,‘c’)); a,b,c
split 字符串分割 select split(‘oneAtwoBthreeC’, ‘[ABC]’); [“one”,“two”,“three”,“”]
select split(‘192.168.41.110’,’\.'); [“192”,“168”,“41”,“110”]
json数据处理:
1.get_json_object ok
2.json_tuple 首选
3.udf函数
判断类function:
case when

sum(case when gender='男' then 1 else 0 end) as male_cnt,
sum(case when gender='女' then 1 else 0 end) as female_cnt

if()

sum(if(gender='男',1,0)) as male_cnt,
sum(if(gender='女',1,0)) as female_cnt

临时函数

udf 一进一出 upper lower :
1.extends UDF
2.实现 evaluate
udaf 多进一出 sum max
udtf 一进多出 explode
打包上传服务器
临时函数 【推荐】

add jar /home/hadoop/lib/dl2262-hive-udf-1.0.jar;

create temporary function hello_udf as 'com.dl2262.UDFHello';

show functions like hello_udf;

select hello_udf(name) as etl_name from emp_info;

注意:仅仅是当前session有效
另外一种使用方式;
1.把自己开发jar =》 hive目录下 auxlib下面
add jar =》 可以省略 直接创建临时函数即可使用
HIVE_AUX_JARS_PATH

create temporary function hello_udf as 'com.dl2262.UDFHello';
show functions like hello_udf;
select hello_udf(name) as etl_name from emp_info;

hive调优【面试】

问题:谈谈你再工作中针对SQL(hive、sparksql…)的优化 ,做的好的3个点?
1.结合场景 + 数据量:
调优前 vs 调优后 的对比情况
2.常见的调优点: groupby join count(distinct ) =》 shuffle =》 数据倾斜
shuffle:根据 map输出的key进行数据分发 各自的reducer上去的
数据倾斜 =》 倾斜在key上
3.没有一劳永逸的调优
1.fetch抓取策略
符合抓取策略 =》 不走mr

hive.fetch.task.conversion

2.本地化执行
决策 =》hive引擎自己去判断

hive.exec.mode.local.auto  =》 开关 
hive.exec.mode.local.auto.inputbytes.max  =》 按照加载的数据量
hive.exec.mode.local.auto.tasks.max =》按照task
hive.exec.mode.local.auto.input.files.max  =》按照文件加载的个数 

3.模式限制
hive.mapred.mode严格模式strict和非严格模式nonstrict
In strict mode,full table scans are prevented 分区表(需要加过滤条件)and ORDER BY (只有一个reduce task)requires a LIMIT clause.
4.推测式执行
1.假设 node1 node2 node3 机器上运行我们的task
2.假设node3机器负载比较高
场景1:
某个时刻、某个节点 负载比较高: cpu使用率比较高、mem被别的作业占用比较多
思考:
task1 和task2 很快运行完成了 ,但由于 node3负载高 ,task3运行比较慢
=》 “木桶效应/短板效应 ” “桶中能装多少水是由最短的这块板来决定的 ”
大数据里:一个job跑完需要耗费多长时间 由最慢的一个task来决定的
hadoop{mR} hive spark…
内部都有一个机制:推测式执行 去解决这个问题
推测式:
1.node3节点上task 跑了 “一定时间”时
会在另外一个节点上页启动一个相同的task 【node5】
这个task3 同时运行在node3节点 node5上 ,谁先跑完 就采用谁的结果 同时kill掉另外一个task

mapreduce: 
	mapreduce.map.speculative
	mapreduce.reduce.speculative
hive:
	hive.mapred.reduce.tasks.speculative.execution 

5.裁剪 【了解】

hive.optimize.cp  =》 是否开启列裁剪
hive.optimize.ppd  谓词下压 

eg: table:emp ,columns: a,b,c,d,e
select a,b,c from emp ; 查询只需要3个字段

  1. 行式存储 文件无法进行列裁剪 一定是加载全部表中字段
  2. 列式存储 : orc、parquet 列式存储的文件 可以进行列裁剪的 节省 网络io和磁盘io
    hive.optimize.ppd 谓词下压 =》 节省 网络io和磁盘io 【减少首次加载的数据量】
    谓词: 条件相关的东西 where on
    下压:取数据从数据源头取数 先过滤会减少数据量的加载
    要求:table : 列式存储,直接where某个字段,会直接定位到该位置
    6.设置 map task数量 和 reduce task 数量
    1.设置 map task 数量
    map task 个数 取决于 切片的个数
mapreduce.input.fileinputformat.split.minsize
mapreduce.input.fileinputformat.split.maxsize

map task数量越多越好吗 ? 越多可能有什么问题?
mapreduce作业:进程级别 task,一个task对应一个jvm启动运行销毁的,task越多代表jvm开启越多,是比较耗费资源的
2.设置reduce task个数 reduce 个数 决定了 最终文件的个数

set hive.exec.reducers.bytes.per.reducer=<number>
set hive.exec.reducers.max=<number>
set mapreduce.job.reduces=<number>

1.用户指定 :

set mapreduce.job.reduces  =》 reduce task个数 

2.用户设置参数 hive引擎自己去算

set hive.exec.reducers.bytes.per.reducer  =》 每个reduce 处理的数据量
set hive.exec.reducers.max =》 reduce task最多有多少个

reduce数据设置? 按照你的作业复杂度 最终输出文件大小来确定 => 如果设置不合理会出现小文件问题
hive 小文件合并问题?
Q1: 为什么说hdfs 不适合处理/存储小文件?
1.从存储角度来说,如果hdfs存储过多小文件,每个小文件都是有自己的元数据的,会增加namenode的压力
2.处理角度:一个小文件对应一个task进行处理
Q2: 如何合并小文件 ?
1. hdfs api 来完成 =》 行式存储
github.com
2.hive 里面支持 DDL
Alter Table/Partition Concatenate =》 合并小文件命令
前提:table 存储 orc存储 =》 列式存储
3.减少reduce task个数 set参数
4.spark api coalsce repartition
5.spark sql hint语法 coalsce

alter table stu_info_orc concatenate;

每隔几天做个小文件合并
7.并行执行
mr: 可以以 任务链chain方式去运行 job,一个作业可以拆分成很多个阶段
mr1=》mr2 => mr3 [explain查看执行计划的功能,查看一个job究竟走了多少map reduce以及map reduce之间有没有依赖关系]
hive : sql =>mr
sql的复杂度 不一样 =》 翻译成 mr的个数 以及依赖 都不一样的
EXPLAIN: 查看sql 执行计划
1.The Abstract Syntax Tree for the query 【sql的语法树 现在不显示了】
2.The dependencies between the different stages of the plan 【一个job 分为多个stage】
3.The description of each of the stages 【每个stage详细信息】

explain
select  
a.*,
b.*
from user_click as a left join product_info as b  
on a.product_id=b.product_id;

一个sql 可以转换成多个mr job
1.可能是串行执行
2.也可能是并行执行
假如sql =》 4个job
1 2 3 job是没有任何依赖关系的
前提:资源够 并行跑 一般性能会好一些的

1.并行执行的参数【一般不开启】
hive.exec.parallel  =false   开关 
hive.exec.parallel.thread.number  =》 运行并行跑的job数

8.数据倾斜
1.什么是数据倾斜?
RT2和RT3 处理的数据的时间会很短
RT1 待处理的数据量过多【数据倾斜】,可能会导致什么问题?
1.处理速度慢 能跑完
2.由于数据倾斜 跑不完 【99%】
数据倾斜?
就是由于某个或者某几个 key对应的数据量过大 从而导致对应的task处理非常慢 或者运行报错
导致的原因?
只有shuffle才有可能导致数据倾斜
join(没有reduce的join不会导致数据倾斜的)、groupby 、count(distinct)
解决:
1.group by
map端输出的某些key 数据量过大 =》 skew 【数据倾斜 】
解决思想: “先打散,再聚合”
hive:
1.参数来解决
hive.groupby.skewindata => sql处于数据倾斜是 会优化 groupby
hive.map.aggr => map端开启一个聚合
2.不通过参数,用户自己定义的 udf函数
1.一个mr作业:
两个mr作业 解决数据倾斜的问题
udf:
add_suffix
pre_suffix

select 
pre_suffix(n_deptno) as pre_deptno,
sum(cnt) as cnt_sum
from 
(
	select 
	add_suffix(deptno) as n_deptno,
	count(1) as cnt 
	from emp 
	group by  add_suffix(deptno)
) as a 
 group by pre_suffix(n_deptno);

2.count(distinct)
distinct => job只有一个 task ,只有一个reduce task来完成 =》 必然导致数据倾斜问题
设置reduce 个数 是没有用的
解决: group by
3.join
1.shuffle join/ mapreduce join 普通join
2.map join =》不走reduce 不会导致数据倾斜
a 表 b 表 得有一个表是小表
1.map join:
1.参数设置

set hive.auto.convert.join=true;
		select  
		a.*,
		b.*
		from user_click as a left join product_info as b  
		on a.product_id=b.product_id limit 2;

2.hints写法: sparksql 也有这种写法 好用的

set hive.auto.convert.join=true;
select  /*+ MAPJOIN(product_info) */ 
a.*,
b.*
from user_click as a left join product_info as b  
on a.product_id=b.product_id 
limit 2;

1.普通join 导致数据倾斜 如何解决? 工作遇到了 可能low怎么解决
2. 直接抽取 skew数据
sql:
2个sql :
1sql =》 skew key join
2sql =》 no skew key join
加前缀

@Description(name = "add_prefix",
        value = "_FUNC_(input, random_limit) - "
                + "Returns add random num prefix string",
        extended = "Example:\n  > SELECT _FUNC_('abc', 5) FROM src LIMIT 1;\n" + "3_abc"
                + "\n  > SELECT _FUNC_('abc', 5) LIMIT 1;\n"
                + "1_abc.\n")
public class UDFAddRandomPrefix extends UDF {
    public String evaluate(Object input,Integer limit){//object
        int num = new Random().nextInt(limit) + 1;
        return num+"_"+input;
    }

    public static void main(String[] args) {
        UDFAddRandomPrefix udfAddRandomPrefix = new UDFAddRandomPrefix();
        System.out.println(udfAddRandomPrefix.evaluate("abc", 10));
    }
}
add jar /home/hadoop/lib/dl2262-hive-udf-1.0.jar.1;
create temporary function add_prefix as 'com.dl2262.UDFAddRandomPrefix';

减前缀

@Description(name = "remove_prefix",
        value = "_FUNC_(input) - "
                + "Returns remove random num prefix string",
        extended = "Example:\n  > SELECT _FUNC_('123_abc') FROM src LIMIT 1;\n" + "abc"
                + "\n  > SELECT _FUNC_('abc_123') LIMIT 1;\n"
                + "123\n")

public class UDFRemovePrefix extends UDF {
    public String evaluate(String input){//object
        return input.split("_")[1];
    }

    public static void main(String[] args) {
        UDFRemovePrefix udfRemovePrefix = new UDFRemovePrefix();
        System.out.println(udfRemovePrefix.evaluate("123_abc"));
    }
}
add jar /home/hadoop/lib/dl2262-hive-udf-1.0.jar.0;
create temporary function remove_prefix as 'com.dl2262.UDFRemovePrefix';

hadoop

参数设置的优先级

1.默认配置文件
	core-default.xml
	hdfs-default.xml
	mapred-default.xml
	yarn-default.xml
2.生产配置文件
	core-site.xml
	hdfs-site.xml
	mapred-site.xml
	yarn-site.xml
3.代码里面设置的参数
	 Configuration
优先级排序:代码里面设置的参数 > 生产配置文件 > 默认配置文件

HDFS架构设计以及各个角色的作用

hdfs是主从架构主从架构–一个namenode,多个datanode
生产上用两个namenode,高可用设计模式
当一个namenode突然挂掉了,另一个namenode马上顶上去实时切换
snn nn 冷备 因为snn是定期拿镜像文件和编辑日志进行合并备份和推送给nn dfs.namenode.checkpoint.period 3600s 1h 会导致有一个空档期1h,在这个期间,上传文件即使成功了也检查不到,会间接导致文件丢失
dfs.namenode.checkpoint.txns 1000000 100w 每有一百万个文件块产生就会触发snn拿编辑日志和镜像文件进行合并
namenode: 名称节点 nn
1.负责存储metadata元数据–描述数据的数据–文件名称、文件的目录结构、文件的属性、权限、创建时间、副本数据等
2.负责 映射块文件–一个文件被切分成多少个数据块,以及数据块对应在哪些节点上存储 the mapping of blocks to DataNodes
作用:
1.管理文件系统的命名空间–其实就是维护文件系统树的文件和文件夹 manage the file system namespace
是以镜像文件fsimage和编辑日志文件editlogs(已经写好的和正在写的)两种文件永久的保存在本地磁盘上
2.namenode对外提供服务(客户端要访问HDFS上的文件必须经过namenode同意)regulate access to files clients
secondery namenode: 第二名称节点 snn
定期拿取镜像文件和编辑日志文件(正在写的)进行合并,备份并推送给namenode
fsimage216+editlogs217=>fsimage217=>namenode
datanode:数据节点 dn
每个分布式都有datanode
serve read and write request from the file system’s clients负责文件的读写(具体干活)
1.存储数据块 store in datanodes和数据块的校验(时时刻刻记录文件变化,把发生的变化记录在镜像文件和编辑文件日志里)
作用:
1.每隔三秒发送一次心跳给namenode告诉namenode我还活着 dfs.heartbeat.internal 3s
2.每隔一定时间发送一次块报告
块映射不会永久持久化这个存储
是通过集群启动和运行时,datanode定期发送块报告给namenode来进行动态维护这种映射关系(存在内存中)dfs.blockreport.intervalMsec 21600000ms 6h
dfs.datanode.directoryscan.interval 21600s 6h 每隔6h扫描磁盘和内存中的块进行比较,判断块有没有进行更新
发送块报告的目的:
因为生产上可能会发生文件块丢失或损坏,就是通过datanode每隔6h是扫描判断块是否发生丢失或损坏

hdfs存储时block

block取决于块大小blocksize含有多少个128M和副本数 伪分布式 1
完全分布式 3(大于等于3时)
160M 2个副本 (1)文件在hdfs上存了多少个块?
(2)实际存储到hdfs 存储的大小是多少?
160M:128M => 1 32M => 1
(1)1+1 =2 块 * 2 = 4个块
(2)160M * 2 = 320M

HDFS写流程【面试】

1.客户端调用程序入口FileSystem.create(filrpath)去和namenode通过RPC协议进行通信
namenode会去检查要上传的文件是否已经存在,并且会去检查客户端是否有权限去访问,只有当要上传的文件不存在且客户端有权限访问时,才能创建一个新的文件。但这时还没有写数据,所以是不关联任何block的
namenode会根据客户端要上传文件的大小以及块的大小和副本参数,计算出要上传多少块和块存储在datanode的位置
最终将这些信息以FSDataOutputStream对象返回给客户端
2.拿到信息后,客户端会调用FSDataOutputStream对象的write方法,将文件的第一个块的第一个副本写到第一个datanode节点,第一个副本写完后去第二个datanode节点写第二个副本,第二个副本写完后再去第三个datanode节点写第三个副本,当第三个副本写完时就返回一个ack的确认包给datanode2节点,当datanode2节点接收到这个ack确认包并且自己也写完之后会返回一个ack确认包给datanode1节点,当datanode1节点接收到这个ack确认包并且自己也写完之后会返回给FSDataOutputStream对象一个ack确认包,此时表示第一个块的三个副本写完了。剩余文件块也按照这个方式进行写入。
3.当所有的文件块都写完之后,客户端会调用FSDataOutputStream对象的close方法告知namenode文件已经全部写入完成。

HDFS读流程【面试】

hdfs读写流程对用户操作是无感知的
1.客户端调用程序入口FileSystem.open(filrpath)的open方法和namenode进行RPC通信,namenode会以FSDataInputStream对象返回要读文件部分或全部的块列表(要读取的块具体在哪些datanode上面)
2.客户端通过调用FSDataInputStream对象的read方法,去与第一个块最近的datanode进行读取,读取完成会检查是否读取成功,如果读取成功就关闭与datanode的通信,如果读取失败会记录所读机器的datanode节点和块信息(标记该节点已经挂了),下次就不会从该节点读取信息,并且从第二个节点读取信息,如果读取成功就关闭通道,如果读取失败就从第三个节点读取信息,当第一个块读取成功后,然后会去与第二个块最近的datanode进行读取,以此类推。当块列表读取完成后,文件还没有全部读取时会继续调用FileSystem从namenode获取下一个批次的块列表,以此类推。
3.当全部读取完毕后,客户端会调用FSDataInputStream对象的close方法关闭输入流。

HDFS副本放置策略【面试】【机架】

读写操作会选择datanode节点进行读取
第一副本:放置在客户端上传的datanode节点
当客户端不在datanode节点时,就会随机选择一个datanode节点
第二个副本:放置在与第一个副本不同机架上的某个datanode节点
第三个副本:放置在与第二个副本相同机架上的不同datanode节点
如果副本数设置超过三个,其他副本就随机放置在不同的datanode节点

HDFS安全模式

1.什么时候会发生安全模式?
(1)启动hadoop
(2)HDFS故障【集群文件块大量丢失10%,说明集群不稳的,会进入安全模式】
(3)我们认为主动进入安全模式:业务场景有关 集群维护
2.进入安全模式对业务有什么影响?
读文件:可以
写文件:不可以
3.相关命令:hdfs dfsadmin -safemode <enter进入安全模式 | leave退出安全模式 | get查看安全模式状态 | wait | forceExit>

如何查看HDFS块是否丢失?hdfs fsck /

HDFS块丢失该怎么解决?
(1)不用解决 hdfs高容错 多副本情况下 datanode–6h
(2)手动进行恢复丢失的数据块
hdfs debug recoverLease -path [-retries num]

MapReduce数据分析计算

以并行方式(多个task)处理大量数据可以部署在廉价的机器上以容错的方式运行
hdfs容错体现在副本数上,mr容错体现在task上,重试机制,当一个task挂掉时,再重新启动一个task完成刚才挂掉task的任务
适用于离线数据计算,不适用于流式数据计算
mapreduce先从hdfs上获取数据然后经过map阶段和reduce阶段对数据进行处理,最后输出
mapreduce流程:
(input)<k1,v1> -> map-><k2,v2> -> reduce-><k3,v3> (output)<k3,v3>
整个阶段都是对kv进行开发,每个阶段输出都是kv,并且kv数据类型必须要被序列化
把磁盘上的文件读取到内存中的过程叫序列化 把内存上的文件写到磁盘的过程叫反序列化
kv数据类型都要实现了Writable接口,此外key的数据类型还要实现WritableComparable接口
key要实现序列化+排序 value只要实现序列化即可
String:Text
数值:intWritable longWritable flaotWritable doubleWritable等等
Text和intWritable longWritable flaotWritable doubleWritable等等均实现了WritableComparable

Map task 个数由什么东西决定的?由切片数量决定

数据输入input :
如果是文件:
FileInputFormat:(FileInputFormat默认是TextInputFormat)
TextInputFormat:<LongWritable, Text>
key:读取文件内容的位置
value:一行一行的内容
1.isSplitable =》 判断你的文件是否可以被切分
1.可以被切分
分片数量 等同于 map task的数据
补充: map task数量由数据input的切片数量决定的
2.不可以被切分
切片数量就是1 对应一个map task
一个文件加载的时候会形成几个切片 ?前提 文件可以被切分
split 切片数量取决于splitsize大小
生产上:splitsize等于blocksize=128M
1.文件能被切分
1.文件大小 小于128M
就有一个切片 =》 一个map task
2.文件大小 大于 128M
fileszie/splitsize = num 切片数
filesize剩余的部分和splitsize的百分之十进行比较
如果剩余部分比splitsize的百分之十大 那么就会额外开启一个切片
如果剩余部分比splitsize的百分之十小 那么就不会开启一个新切片 剩余部分会放在上一个切片里进行处理
2.不能切分的文件
某些压缩文件

Reduce task 个数由什么东西决定的?

1.mr 用户自己决定 job.setNumReduceTasks(num)
2.默认reduce task个数是 1
3.reduce task 个数 =》 最终文件输出的时候 就有多少个文件
总结:
1.reduce task个数 > partitions 会有空文件
2.reduce task个数 < partitions 会报错
3.reduce task个数 = partitions 没问题
4.reduce task个数1 就是默认值 最终会有一个文件产生
map task是几,Mapper里的setup()和clear up()就执行几次

Yarn架构:主从架构

1.resourcemanager:负责资源的分配
2.nodemanager:负责资源的供给与隔离
资源调度?resourcemanager将nodemanager上资源分配给task
资源隔离?nodemanager按照要求给task提供资源,保证提供的资源具有独占性
每个container之间相互隔离的
资源:nodemanager指挥分配的资源:container[一定比列cpu和内存]
一个container对应一个task

yarn的架构设计【面试】

1.客户端给ResourceManager的ApplicationsManager发送请求去运行jar包 包含一个作业(app master)
2.ApplicationsManager通知nodemanager分配一个container去运行app master
3.app master向ApplicationsManager去注册作业(完成之后yarn web ui 可以看到作业的运行情况)
4.app master向Resource Scheduler申请资源去运行我的代码
5-6.nodeManager收到Resource Scheduler的通知,会去开启container资源去运行map task和reduce task
7.task会向app master汇报代码的运行情况
8.当代码运行完成后,app master会给ApplicationsManager通知我的作业运行完成了,请求释放资源(container资源)
9.ApplicationsManager收到请求之后,通知客户端,你的代码运行完成了
input: map task个数会决定container 申请的个数
reduce : reduce task个数会决定container 申请的个数
container 申请的个数 =map task个数+reduce task个数

调度器

1.FIFO scheduler : 先进先出 单队列
2.Capacity scheduler 容量调度器:(离线任务,实时任务,临时查询任务)
多队列、每个队列之间 互不影响 先进先出
3.Fair scheduler 公平调度器
多队列、 每个队列之间 job 有影响 不是先进先出 队列间按job的优先级决定
默认调度器:Capacity scheduler 容量调度器 3.x yarn-site.xml
2.x默认是公平调度器
yarn.resourcemanager.scheduler.class =》 CapacityScheduler
yarn web : 可以查看queue Scheduler

yarn资源调优

针对集群中 每个节点 对container进行配置
刀片服务器配置: 128G 16物理core
1.刀片服务器 装完系统 消耗1G
2.系统预留 20%内存 [包含 装完系统 消耗1G]128G20%
为什么系统要预留20%内存?
1.给未来部署组件预留内存空间
2.防止 全部使用 会导致 系统夯住 oom机制(资源不足时会杀死进程)【linux系统】
目前位置 大数据服务资源: 102G
hadoop:Datanode 进程内存 2G
nodemanager 进程内存 4G
102G -2g -4G = 96G => yarn资源 container 一共 96G
container资源划分 : 1.内存 2.cpu 【core】
1.container内存:
总:yarn.nodemanager.resource.memory-mb 96G 【默认值是8G】
最小:yarn.scheduler.minimum-allocation-mb 1g 极限情况下 会有96个container
最大:yarn.scheduler.maximum-allocation-mb 96G 最大不超过32G 极限情况下 会有1个container
注意: container内存会自动增加 默认1g递增
2.container cpu 【虚拟核 vcore =》 设计初衷 考虑不同节点的cpu性能不一样】
第一机器: 强悍 pcore:vcore=1:2 【1core 当成2core使用】
第二机器: 不强悍 pcore:vcore=1:1
16个物理核 : 16vcore
1.虚拟核 和物理核的比例 :yarn.nodemanager.resource.pcores-vcores-multiplier 2
yarn core =》 vcore 16
2 = 32 vcore
总: yarn.nodemanager.resource.cpu-vcores 32 【默认是8vcore】
最小:yarn.scheduler.minimum-allocation-vcores 1 极限情况下 只有32个container
最大:yarn.scheduler.maximum-allocation-vcores 32 极限情况下 只有1个container
实际开发角度: 1.mem 为主
2.cpu :cloudera 公司推荐 一个contaier 的vcore 最大值最好不要超过5 4
16个物理核 : 16vcore
1.虚拟核 和物理核的比例 :yarn.nodemanager.resource.pcores-vcores-multiplier 2
yarn core =》 vcore 16*2 = 32 vcore
总:yarn.nodemanager.resource.cpu-vcores 32 【默认是8vcore】
最小:yarn.scheduler.minimum-allocation-vcores 1 极限情况下 只有32个container
最大:yarn.scheduler.maximum-allocation-vcores 4 极限情况下 只有8个container
反推内存:

  1. vcore 4 container 8个
    总:yarn.nodemanager.resource.memory-mb 96G 【默认值是8G】
    最小:yarn.scheduler.minimum-allocation-mb 1g 极限情况下 会有96个container
    最大:yarn.scheduler.maximum-allocation-mb 12G 极限情况下 会有8个container
    注意: container内存会自动增加 默认1g递增
    container:
  2. 8-32 个container => task 8-32个
    2.实际上以内存为主
    总:yarn.nodemanager.resource.memory-mb 96G 【默认值是8G】
    最小:yarn.scheduler.minimum-allocation-mb 2G
    最大:yarn.scheduler.maximum-allocation-mb 20G
    20G => container ? 5个container
    2g => container ? 48个container

mapreduce:map task reduce task 默认申请的container:cpu 内存 分别是多少?

map task:
1.内存 :mapreduce.map.memory.mb 默认是1024
一个map task 申请的内存资源是 1024M
如果map task 实际使用的资源量超过该值 task将会被强制杀死
2.cpu mapreduce.map.cpu.vcores 默认是1
reduce task :
1.内存 mapreduce.reduce.memory.mb 默认是1024
2.cpu mapreduce.reduce.memory.mb 默认是1

jvm调优

mr: 进程级别 运行一个作业会开启很多进程进程,这个进程和yarn和hdfs没关系,它开启的是maptask相关进程可能多个,reduce task相关进程可能多个 =》 jvm (java运行时数据区)
map task :mapreduce.map.java.opts jvm相关调优参数即可
reduce task :mapreduce.reduce.java.opts jvm相关调优参数即可
jvm参数调优:
1.提交mr作业时可以指定 ?当前job生效
hadoop jar xxx.jar xxx参数 指定job运行时资源的参数
2.集群环境里面可以配置:? 全局生效
mapreude-site.xml
3.最常见的 code =》 当前job生效
code Configration设置参数

存储文件进行调优【压缩】

1.为什么要使用压缩?
1.节省空间 (1file hdfs 3个副本)
2.节省时间(数据发送时间): 网络io 和磁盘io 会减少
1.mapreduce 过程中 map端输出采用压缩
1.经过网络传输的数据量会变少 【减少了网络io】
2.磁盘上数据压缩后,读取到内存的数据量也会变少 【减少磁盘io】
2.使用场景?
1.采用压缩,对机器的cpu要求比较高
2.存储数据的空间不够
3.凡事都有两面性?
1.采用压缩 1.空间 和读取数据和网络传输时间会减少
2.cpu消耗比较大 cpu利用率高 =》 会导致整个mr作业处理数据时间会稍微长一些(发送数据时间的减少不能弥补压缩的时间)
4.如何使用压缩?
1.存储角度
上传到hdfs上的文件直接压缩,压缩普通文件
2.计算角度 mr spark flink
1.input mr 加载压缩文件不用考虑,因为文件已经压缩完了,压缩完的文件通过inputformat(切片)直接对文件进行读取 切片会对压缩格式进行校验 =》 源码里面会判断是否是压缩文件,如果是压缩文件进行强转
2.map out 配置参数即可
3.reduce out 配置参数即可
5.常见的压缩格式
gzip .gz
bzip2 .bz2
LZO .lzo
Snappy .snappy
LZ4 .lzo4
1.压缩比
Bzip2:30% GZIP snappy、lzo:50%
解压速度:
snappy、lzo > GZIP > Bzip2
2.压缩文件是否可以被切分?
1.假设一个 5G文件 不能被切分split意味着 只能使用一个map task去处理 效率不高
map task 处理的数据量是5G
2.假设一个 5G文件 能被切片splits 假如被切分为10个分片,10map task 去并行处理
5*1024 /10 = 一个map task 处理的数据量M
3. 能否被切分 决定了 你的 一个map task处理的数据量有多少,在资源充足的情况下,多并行度处理要比单并行度处理效率高些
3.压缩后的文件是否支持分割?
gzip 不可分割
bzip2 可分割
lzo 带索引的可以分割 (默认是不支持分割的)
snappy 不可分割的
4.mapreduce 每个阶段该如何采用这些算法?
compressed input =>decompressed input=> maps(一个切片对应一个map task) =>map out compressed =>decompressed map out=> reduce => reduce out compressed=> output
input:建议使用压缩,支持分片
1.Bzip2
支持分割 多个map task 进行
map out:解压速度(网络传输),不用考虑是否能切片,切片是读取数据时要考虑的
1. shuffle 过程 要选择一个压/解 速度快的压缩格式
2.snappy 、lzo
reduce out :高压缩比的目的是节省空间,因为reduce输出的数据将来还有可能作为下一个map的输入,还要考虑能否切片的问题
1.高的压缩比 + 支持分片 =》 节省空间
2.bzip2 、lzo带索引的
reduce out 数据 作为下一个map 的输入咋办?
建议使用bzip2【如果采用压缩的话】
如何进行配置?
1.某个作业 =》 code代码里面添加 【某个job生效】
2.集群所有作业 =》 在配置文件里面加 【全局生效】
mapreduce 压缩配置:input阶段不需要配置
1.配置压缩的codec
2.map reduce 输出配置:
1.先打开压缩的开关
2.配置codec 即可
hadoop集群hdfs 支持哪些压缩?gzip(默认)、snappy、bzip2、lz4
1.命令 hadoop checknative
2.core-site.xml可以配置:配置支持的压缩有哪些
io.compression.codecs 控制
mapred-site.xml里面可以配置:
1.先打开压缩的开关
2.map reduce 输出 压缩算法
补充:
原生 hadoop 默认不支持 lzo的压缩
vim core-site.xml 配置支持的压缩有哪些
bzip2、gzip、snappy
hadoop fs -text 压缩文件 可以查看压缩文件 -text是以mr的方式进行查看文件内容,一定有input阶段,input阶段对压缩文件没有要求,任何压缩文件都可以看到

各个DN节点数据平衡

sbin目录下start-balancer.sh
eg:DN1 存储空间 90%
DN2 存储空间 60%
DN3 存储空间 80%
数据平衡的默认阈值:threshold = 10.0
每个节点的磁盘使用率 - 平均的磁盘使用率 <10%
avg=90 + 80 +60 /3 = 76%
DN1 存储空间 90% -76% = 14% 说明这个节点数据多 往别的节点迁移数据 出
DN2 存储空间 60% -76% = -12% 说明这个节点数据少 别的节点迁移数据 进
DN3 存储空间 80% -76% = 4%
生产上 从现在开始 start-balancer.sh -threshold 10 每天要定时做的
放到业务低谷期去做 数据平衡操作 ,不要在业务高峰期做
数据平衡 数据传输 带宽有关
调优参数 :平衡的网络带宽 w
(3.x)dfs.datanode.balance.bandwidthPerSec 默认是100M 【2.x 默认是10M】
单个DN节点 多块磁盘的数据平衡 nodename有副本数,不要做raid
做raid:备份,把磁盘分成两份,一份读一份写,但是内容是一样的
查看磁盘挂载df -h
1.dn 配置多个磁盘

dfs.datanode.data.dir
/data01,/data02,/data03磁盘

2.为什么要使用多块物理磁盘?
1.存储
2.因为多个磁盘的io也是叠加的
每块磁盘 磁盘io 每秒 100M
三块磁盘 1s 能 300M文件内容
一块磁盘 1s 100M
3./data01,/data02,/data03
做多个磁盘数据均衡
dfs.disk.balancer.enabled true 【3.x有这个功能 cdh 2.x 也有】 apache 2.x 没有这个功能
得通过命令去解决磁盘数据均衡?
hdfs diskbalancer
1.步骤
hdfs diskbalancer -plan bigdata32 => 生成一个 bigdata32.plan.json 文件
hdfs diskbalancer -execute bigdata32.plan.json =》 执行disk 数据均衡计划文件
hdfs diskbalancer -query bigdata32
生产上 当你发现 磁盘写入不均衡 可以做一下 【一般 一个月 半个月 做一次即可】

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值