将导航和图片路径转换为相对路径
This commit is contained in:
parent
e84d335a48
commit
33525c5b4b
@ -1,196 +0,0 @@
|
||||
# BigData-Notes(离线版)
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img width="470px" src="pictures/bigdata-notes-icon.png"/> </div>
|
||||
<br/>
|
||||
|
||||
> **大数据入门指南 ( 离线版)**
|
||||
|
||||
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th><img width="50px" src="pictures/hadoop.jpg"></th>
|
||||
<th><img width="50px" src="pictures/hive.jpg"></th>
|
||||
<th><img width="50px" src="pictures/spark.jpg"></th>
|
||||
<th><img width="50px" src="pictures/storm.png"></th>
|
||||
<th><img width="50px" src="pictures/flink.png"></th>
|
||||
<th><img width="50px" src="pictures/hbase.png"></th>
|
||||
<th><img width="50px" src="pictures/kafka.png"></th>
|
||||
<th><img width="50px" src="pictures/zookeeper.jpg"></th>
|
||||
<th><img width="50px" src="pictures/flume.png"></th>
|
||||
<th><img width="50px" src="pictures/sqoop.png"></th>
|
||||
<th><img width="50px" src="pictures/azkaban.png"></th>
|
||||
<th><img width="50px" src="pictures/scala.jpg"></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="#一hadoop">Hadoop</a></td>
|
||||
<td align="center"><a href="#二hive">Hive</a></td>
|
||||
<td align="center"><a href="#三spark">Spark</a></td>
|
||||
<td align="center"><a href="#四storm">Storm</a></td>
|
||||
<td align="center"><a href="#五flink">Flink</a></td>
|
||||
<td align="center"><a href="#六hbase">HBase</a></td>
|
||||
<td align="center"><a href="#七kafka">Kafka</a></td>
|
||||
<td align="center"><a href="#八zookeeper">Zookeeper</a></td>
|
||||
<td align="center"><a href="#九flume">Flume</a></td>
|
||||
<td align="center"><a href="#十sqoop">Sqoop</a></td>
|
||||
<td align="center"><a href="#十一azkaban">Azkaban</a></td>
|
||||
<td align="center"><a href="#十二scala">Scala</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<br/>
|
||||
|
||||
## :black_nib: 前 言
|
||||
|
||||
1. [大数据学习路线](offline-notes/大数据学习路线.md)
|
||||
2. [大数据技术栈思维导图](offline-notes/大数据技术栈思维导图.md)
|
||||
3. [大数据常用软件安装指南](offline-notes/大数据常用软件安装指南.md)
|
||||
|
||||
## 一、Hadoop
|
||||
|
||||
1. [分布式文件存储系统 —— HDFS](offline-notes/Hadoop-HDFS.md)
|
||||
2. [分布式计算框架 —— MapReduce](offline-notes/Hadoop-MapReduce.md)
|
||||
3. [集群资源管理器 —— YARN](offline-notes/Hadoop-YARN.md)
|
||||
4. [Hadoop 单机伪集群环境搭建](offline-notes/installation/Hadoop单机环境搭建.md)
|
||||
5. [Hadoop 集群环境搭建](offline-notes/installation/Hadoop集群环境搭建.md)
|
||||
6. [HDFS 常用 Shell 命令](offline-notes/HDFS常用Shell命令.md)
|
||||
7. [HDFS Java API 的使用](offline-notes/HDFS-Java-API.md)
|
||||
8. [基于 Zookeeper 搭建 Hadoop 高可用集群](offline-notes/installation/基于Zookeeper搭建Hadoop高可用集群.md)
|
||||
|
||||
## 二、Hive
|
||||
|
||||
1. [Hive 简介及核心概念](offline-notes/Hive简介及核心概念.md)
|
||||
2. [Linux 环境下 Hive 的安装部署](offline-notes/installation/Linux环境下Hive的安装部署.md)
|
||||
4. [Hive CLI 和 Beeline 命令行的基本使用](offline-notes/HiveCLI和Beeline命令行的基本使用.md)
|
||||
6. [Hive 常用 DDL 操作](offline-notes/Hive常用DDL操作.md)
|
||||
7. [Hive 分区表和分桶表](offline-notes/Hive分区表和分桶表.md)
|
||||
8. [Hive 视图和索引](offline-notes/Hive视图和索引.md)
|
||||
9. [Hive常用 DML 操作](offline-notes/Hive常用DML操作.md)
|
||||
10. [Hive 数据查询详解](offline-notes/Hive数据查询详解.md)
|
||||
|
||||
## 三、Spark
|
||||
|
||||
**Spark Core :**
|
||||
|
||||
1. [Spark 简介](offline-notes/Spark简介.md)
|
||||
2. [Spark 开发环境搭建](offline-notes/installation/Spark开发环境搭建.md)
|
||||
4. [弹性式数据集 RDD](offline-notes/Spark_RDD.md)
|
||||
5. [RDD 常用算子详解](offline-notes/Spark_Transformation和Action算子.md)
|
||||
5. [Spark 运行模式与作业提交](offline-notes/Spark部署模式与作业提交.md)
|
||||
6. [Spark 累加器与广播变量](offline-notes/Spark累加器与广播变量.md)
|
||||
7. [基于 Zookeeper 搭建 Spark 高可用集群](offline-notes/installation/Spark集群环境搭建.md)
|
||||
|
||||
**Spark SQL :**
|
||||
|
||||
1. [DateFrame 和 DataSet ](offline-notes/SparkSQL_Dataset和DataFrame简介.md)
|
||||
2. [Structured API 的基本使用](offline-notes/Spark_Structured_API的基本使用.md)
|
||||
3. [Spark SQL 外部数据源](offline-notes/SparkSQL外部数据源.md)
|
||||
4. [Spark SQL 常用聚合函数](offline-notes/SparkSQL常用聚合函数.md)
|
||||
5. [Spark SQL JOIN 操作](offline-notes/SparkSQL联结操作.md)
|
||||
|
||||
**Spark Streaming :**
|
||||
|
||||
1. [Spark Streaming 简介](offline-notes/Spark_Streaming与流处理.md)
|
||||
2. [Spark Streaming 基本操作](offline-notes/Spark_Streaming基本操作.md)
|
||||
3. [Spark Streaming 整合 Flume](offline-notes/Spark_Streaming整合Flume.md)
|
||||
4. [Spark Streaming 整合 Kafka](offline-notes/Spark_Streaming整合Kafka.md)
|
||||
|
||||
## 四、Storm
|
||||
|
||||
1. [Storm 和流处理简介](offline-notes/Storm和流处理简介.md)
|
||||
2. [Storm 核心概念详解](offline-notes/Storm核心概念详解.md)
|
||||
3. [Storm 单机环境搭建](offline-notes/installation/Storm单机环境搭建.md)
|
||||
4. [Storm 集群环境搭建](offline-notes/installation/Storm集群环境搭建.md)
|
||||
5. [Storm 编程模型详解](offline-notes/Storm编程模型详解.md)
|
||||
6. [Storm 项目三种打包方式对比分析](offline-notes/Storm三种打包方式对比分析.md)
|
||||
7. [Storm 集成 Redis 详解](offline-notes/Storm集成Redis详解.md)
|
||||
8. [Storm 集成 HDFS/HBase](offline-notes/Storm集成HBase和HDFS.md)
|
||||
9. [Storm 集成 Kafka](offline-notes/Storm集成Kakfa.md)
|
||||
|
||||
## 五、Flink
|
||||
|
||||
1. [Flink 核心概念综述](offline-notes/Flink核心概念综述.md)
|
||||
2. [Flink 开发环境搭建](offline-notes/Flink开发环境搭建.md)
|
||||
3. [Flink Data Source](offline-notes/Flink_Data_Source.md)
|
||||
4. [Flink Data Transformation](offline-notes/Flink_Data_Transformation.md)
|
||||
4. [Flink Data Sink](offline-notes/Flink_Data_Sink.md)
|
||||
6. [Flink 窗口模型](offline-notes/Flink_Windows.md)
|
||||
7. [Flink 状态管理与检查点机制](offline-notes/Flink状态管理与检查点机制.md)
|
||||
8. [Flink Standalone 集群部署](offline-notes/installation/Flink_Standalone_Cluster.md)
|
||||
|
||||
|
||||
## 六、HBase
|
||||
|
||||
1. [Hbase 简介](offline-notes/Hbase简介.md)
|
||||
2. [HBase 系统架构及数据结构](offline-notes/Hbase系统架构及数据结构.md)
|
||||
3. [HBase 基本环境搭建 (Standalone /pseudo-distributed mode)](offline-notes/installation/HBase单机环境搭建.md)
|
||||
4. [HBase 集群环境搭建](offline-notes/installation/HBase集群环境搭建.md)
|
||||
5. [HBase 常用 Shell 命令](offline-notes/Hbase_Shell.md)
|
||||
6. [HBase Java API](offline-notes/Hbase_Java_API.md)
|
||||
7. [Hbase 过滤器详解](offline-notes/Hbase过滤器详解.md)
|
||||
8. [HBase 协处理器详解](offline-notes/Hbase协处理器详解.md)
|
||||
9. [HBase 容灾与备份](offline-notes/Hbase容灾与备份.md)
|
||||
10. [HBase的 SQL 中间层 —— Phoenix](offline-notes/Hbase的SQL中间层_Phoenix.md)
|
||||
11. [Spring/Spring Boot 整合 Mybatis + Phoenix](offline-notes/Spring+Mybtais+Phoenix整合.md)
|
||||
|
||||
## 七、Kafka
|
||||
|
||||
1. [Kafka 简介](offline-notes/Kafka简介.md)
|
||||
2. [基于 Zookeeper 搭建 Kafka 高可用集群](offline-notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
|
||||
3. [Kafka 生产者详解](offline-notes/Kafka生产者详解.md)
|
||||
4. [Kafka 消费者详解](offline-notes/Kafka消费者详解.md)
|
||||
5. [深入理解 Kafka 副本机制](offline-notes/Kafka深入理解分区副本机制.md)
|
||||
|
||||
## 八、Zookeeper
|
||||
|
||||
1. [Zookeeper 简介及核心概念](offline-notes/Zookeeper简介及核心概念.md)
|
||||
2. [Zookeeper 单机环境和集群环境搭建](offline-notes/installation/Zookeeper单机环境和集群环境搭建.md)
|
||||
3. [Zookeeper 常用 Shell 命令](offline-notes/Zookeeper常用Shell命令.md)
|
||||
4. [Zookeeper Java 客户端 —— Apache Curator](offline-notes/Zookeeper_Java客户端Curator.md)
|
||||
5. [Zookeeper ACL 权限控制](offline-notes/Zookeeper_ACL权限控制.md)
|
||||
|
||||
## 九、Flume
|
||||
|
||||
1. [Flume 简介及基本使用](offline-notes/Flume简介及基本使用.md)
|
||||
2. [Linux 环境下 Flume 的安装部署](offline-notes/installation/Linux下Flume的安装.md)
|
||||
3. [Flume 整合 Kafka](offline-notes/Flume整合Kafka.md)
|
||||
|
||||
## 十、Sqoop
|
||||
|
||||
1. [Sqoop 简介与安装](offline-notes/Sqoop简介与安装.md)
|
||||
2. [Sqoop 的基本使用](offline-notes/Sqoop基本使用.md)
|
||||
|
||||
## 十一、Azkaban
|
||||
|
||||
1. [Azkaban 简介](offline-notes/Azkaban简介.md)
|
||||
2. [Azkaban3.x 编译及部署](offline-notes/installation/Azkaban_3.x_编译及部署.md)
|
||||
3. [Azkaban Flow 1.0 的使用](offline-notes/Azkaban_Flow_1.0_的使用.md)
|
||||
4. [Azkaban Flow 2.0 的使用](offline-notes/Azkaban_Flow_2.0_的使用.md)
|
||||
|
||||
## 十二、Scala
|
||||
|
||||
1. [Scala 简介及开发环境配置](offline-notes/Scala简介及开发环境配置.md)
|
||||
2. [基本数据类型和运算符](offline-notes/Scala基本数据类型和运算符.md)
|
||||
3. [流程控制语句](offline-notes/Scala流程控制语句.md)
|
||||
4. [数组 —— Array](offline-notes/Scala数组.md)
|
||||
5. [集合类型综述](offline-notes/Scala集合类型.md)
|
||||
6. [常用集合类型之 —— List & Set](offline-notes/Scala列表和集.md)
|
||||
7. [常用集合类型之 —— Map & Tuple](offline-notes/Scala映射和元组.md)
|
||||
8. [类和对象](offline-notes/Scala类和对象.md)
|
||||
9. [继承和特质](offline-notes/Scala继承和特质.md)
|
||||
10. [函数 & 闭包 & 柯里化](offline-notes/Scala函数和闭包.md)
|
||||
11. [模式匹配](offline-notes/Scala模式匹配.md)
|
||||
12. [类型参数](offline-notes/Scala类型参数.md)
|
||||
13. [隐式转换和隐式参数](offline-notes/Scala隐式转换和隐式参数.md)
|
||||
|
||||
|
||||
## 十三、公共内容
|
||||
|
||||
1. [大数据应用常用打包方式](offline-notes/大数据应用常用打包方式.md)
|
||||
|
||||
<br>
|
||||
|
||||
## :bookmark_tabs: 后 记
|
||||
|
||||
[资料分享与开发工具推荐](offline-notes/资料分享与工具推荐.md)
|
224
README.md
224
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img width="470px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/bigdata-notes-icon.png"/> </div>
|
||||
<div align="center"> <img width="470px" src="pictures/bigdata-notes-icon.png"/> </div>
|
||||
<br/>
|
||||
|
||||
> **大数据入门指南 ( 2019 )**
|
||||
@ -11,18 +11,18 @@
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop.jpg"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive.jpg"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark.jpg"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm.png"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink.png"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase.png"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka.png"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper.jpg"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume.png"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop.png"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban.png"></th>
|
||||
<th><img width="50px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala.jpg"></th>
|
||||
<th><img width="50px" src="pictures/hadoop.jpg"></th>
|
||||
<th><img width="50px" src="pictures/hive.jpg"></th>
|
||||
<th><img width="50px" src="pictures/spark.jpg"></th>
|
||||
<th><img width="50px" src="pictures/storm.png"></th>
|
||||
<th><img width="50px" src="pictures/flink.png"></th>
|
||||
<th><img width="50px" src="pictures/hbase.png"></th>
|
||||
<th><img width="50px" src="pictures/kafka.png"></th>
|
||||
<th><img width="50px" src="pictures/zookeeper.jpg"></th>
|
||||
<th><img width="50px" src="pictures/flume.png"></th>
|
||||
<th><img width="50px" src="pictures/sqoop.png"></th>
|
||||
<th><img width="50px" src="pictures/azkaban.png"></th>
|
||||
<th><img width="50px" src="pictures/scala.jpg"></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center"><a href="#一hadoop">Hadoop</a></td>
|
||||
@ -41,160 +41,156 @@
|
||||
</table>
|
||||
<br/>
|
||||
|
||||
>**离线版本使用说明**:为方便大家查看,本仓库新增离线版本。Clone 到本地后,使用 Markdown 阅读器即可查看,我个人使用的是 [Typora]( https://www.typora.io/ ) 。离线版本的导航页为 : *OFFLINE-README.md* ,按住 `Ctrl` 键并点击目录,即可打开对应文章。
|
||||
|
||||
|
||||
|
||||
## :black_nib: 前 言
|
||||
|
||||
1. [大数据学习路线](https://github.com/heibaiying/BigData-Notes/blob/master/notes/大数据学习路线.md)
|
||||
2. [大数据技术栈思维导图](https://github.com/heibaiying/BigData-Notes/blob/master/notes/大数据技术栈思维导图.md)
|
||||
3. [大数据常用软件安装指南](https://github.com/heibaiying/BigData-Notes/blob/master/notes/大数据常用软件安装指南.md)
|
||||
1. [大数据学习路线](notes/大数据学习路线.md)
|
||||
2. [大数据技术栈思维导图](notes/大数据技术栈思维导图.md)
|
||||
3. [大数据常用软件安装指南](notes/大数据常用软件安装指南.md)
|
||||
|
||||
## 一、Hadoop
|
||||
|
||||
1. [分布式文件存储系统 —— HDFS](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hadoop-HDFS.md)
|
||||
2. [分布式计算框架 —— MapReduce](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hadoop-MapReduce.md)
|
||||
3. [集群资源管理器 —— YARN](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hadoop-YARN.md)
|
||||
4. [Hadoop 单机伪集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Hadoop单机环境搭建.md)
|
||||
5. [Hadoop 集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Hadoop集群环境搭建.md)
|
||||
6. [HDFS 常用 Shell 命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/HDFS常用Shell命令.md)
|
||||
7. [HDFS Java API 的使用](https://github.com/heibaiying/BigData-Notes/blob/master/notes/HDFS-Java-API.md)
|
||||
8. [基于 Zookeeper 搭建 Hadoop 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Hadoop高可用集群.md)
|
||||
1. [分布式文件存储系统 —— HDFS](notes/Hadoop-HDFS.md)
|
||||
2. [分布式计算框架 —— MapReduce](notes/Hadoop-MapReduce.md)
|
||||
3. [集群资源管理器 —— YARN](notes/Hadoop-YARN.md)
|
||||
4. [Hadoop 单机伪集群环境搭建](notes/installation/Hadoop单机环境搭建.md)
|
||||
5. [Hadoop 集群环境搭建](notes/installation/Hadoop集群环境搭建.md)
|
||||
6. [HDFS 常用 Shell 命令](notes/HDFS常用Shell命令.md)
|
||||
7. [HDFS Java API 的使用](notes/HDFS-Java-API.md)
|
||||
8. [基于 Zookeeper 搭建 Hadoop 高可用集群](notes/installation/基于Zookeeper搭建Hadoop高可用集群.md)
|
||||
|
||||
## 二、Hive
|
||||
|
||||
1. [Hive 简介及核心概念](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hive简介及核心概念.md)
|
||||
2. [Linux 环境下 Hive 的安装部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Linux环境下Hive的安装部署.md)
|
||||
4. [Hive CLI 和 Beeline 命令行的基本使用](https://github.com/heibaiying/BigData-Notes/blob/master/notes/HiveCLI和Beeline命令行的基本使用.md)
|
||||
6. [Hive 常用 DDL 操作](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hive常用DDL操作.md)
|
||||
7. [Hive 分区表和分桶表](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hive分区表和分桶表.md)
|
||||
8. [Hive 视图和索引](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hive视图和索引.md)
|
||||
9. [Hive常用 DML 操作](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hive常用DML操作.md)
|
||||
10. [Hive 数据查询详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hive数据查询详解.md)
|
||||
1. [Hive 简介及核心概念](notes/Hive简介及核心概念.md)
|
||||
2. [Linux 环境下 Hive 的安装部署](notes/installation/Linux环境下Hive的安装部署.md)
|
||||
4. [Hive CLI 和 Beeline 命令行的基本使用](notes/HiveCLI和Beeline命令行的基本使用.md)
|
||||
6. [Hive 常用 DDL 操作](notes/Hive常用DDL操作.md)
|
||||
7. [Hive 分区表和分桶表](notes/Hive分区表和分桶表.md)
|
||||
8. [Hive 视图和索引](notes/Hive视图和索引.md)
|
||||
9. [Hive常用 DML 操作](notes/Hive常用DML操作.md)
|
||||
10. [Hive 数据查询详解](notes/Hive数据查询详解.md)
|
||||
|
||||
## 三、Spark
|
||||
|
||||
**Spark Core :**
|
||||
|
||||
1. [Spark 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark简介.md)
|
||||
2. [Spark 开发环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Spark开发环境搭建.md)
|
||||
4. [弹性式数据集 RDD](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark_RDD.md)
|
||||
5. [RDD 常用算子详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark_Transformation和Action算子.md)
|
||||
5. [Spark 运行模式与作业提交](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark部署模式与作业提交.md)
|
||||
6. [Spark 累加器与广播变量](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark累加器与广播变量.md)
|
||||
7. [基于 Zookeeper 搭建 Spark 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Spark集群环境搭建.md)
|
||||
1. [Spark 简介](notes/Spark简介.md)
|
||||
2. [Spark 开发环境搭建](notes/installation/Spark开发环境搭建.md)
|
||||
4. [弹性式数据集 RDD](notes/Spark_RDD.md)
|
||||
5. [RDD 常用算子详解](notes/Spark_Transformation和Action算子.md)
|
||||
5. [Spark 运行模式与作业提交](notes/Spark部署模式与作业提交.md)
|
||||
6. [Spark 累加器与广播变量](notes/Spark累加器与广播变量.md)
|
||||
7. [基于 Zookeeper 搭建 Spark 高可用集群](notes/installation/Spark集群环境搭建.md)
|
||||
|
||||
**Spark SQL :**
|
||||
|
||||
1. [DateFrame 和 DataSet ](https://github.com/heibaiying/BigData-Notes/blob/master/notes/SparkSQL_Dataset和DataFrame简介.md)
|
||||
2. [Structured API 的基本使用](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark_Structured_API的基本使用.md)
|
||||
3. [Spark SQL 外部数据源](https://github.com/heibaiying/BigData-Notes/blob/master/notes/SparkSQL外部数据源.md)
|
||||
4. [Spark SQL 常用聚合函数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/SparkSQL常用聚合函数.md)
|
||||
5. [Spark SQL JOIN 操作](https://github.com/heibaiying/BigData-Notes/blob/master/notes/SparkSQL联结操作.md)
|
||||
1. [DateFrame 和 DataSet ](notes/SparkSQL_Dataset和DataFrame简介.md)
|
||||
2. [Structured API 的基本使用](notes/Spark_Structured_API的基本使用.md)
|
||||
3. [Spark SQL 外部数据源](notes/SparkSQL外部数据源.md)
|
||||
4. [Spark SQL 常用聚合函数](notes/SparkSQL常用聚合函数.md)
|
||||
5. [Spark SQL JOIN 操作](notes/SparkSQL联结操作.md)
|
||||
|
||||
**Spark Streaming :**
|
||||
|
||||
1. [Spark Streaming 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark_Streaming与流处理.md)
|
||||
2. [Spark Streaming 基本操作](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark_Streaming基本操作.md)
|
||||
3. [Spark Streaming 整合 Flume](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark_Streaming整合Flume.md)
|
||||
4. [Spark Streaming 整合 Kafka](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spark_Streaming整合Kafka.md)
|
||||
1. [Spark Streaming 简介](notes/Spark_Streaming与流处理.md)
|
||||
2. [Spark Streaming 基本操作](notes/Spark_Streaming基本操作.md)
|
||||
3. [Spark Streaming 整合 Flume](notes/Spark_Streaming整合Flume.md)
|
||||
4. [Spark Streaming 整合 Kafka](notes/Spark_Streaming整合Kafka.md)
|
||||
|
||||
## 四、Storm
|
||||
|
||||
1. [Storm 和流处理简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Storm和流处理简介.md)
|
||||
2. [Storm 核心概念详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Storm核心概念详解.md)
|
||||
3. [Storm 单机环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Storm单机环境搭建.md)
|
||||
4. [Storm 集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Storm集群环境搭建.md)
|
||||
5. [Storm 编程模型详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Storm编程模型详解.md)
|
||||
6. [Storm 项目三种打包方式对比分析](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Storm三种打包方式对比分析.md)
|
||||
7. [Storm 集成 Redis 详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Storm集成Redis详解.md)
|
||||
8. [Storm 集成 HDFS/HBase](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Storm集成HBase和HDFS.md)
|
||||
9. [Storm 集成 Kafka](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Storm集成Kakfa.md)
|
||||
1. [Storm 和流处理简介](notes/Storm和流处理简介.md)
|
||||
2. [Storm 核心概念详解](notes/Storm核心概念详解.md)
|
||||
3. [Storm 单机环境搭建](notes/installation/Storm单机环境搭建.md)
|
||||
4. [Storm 集群环境搭建](notes/installation/Storm集群环境搭建.md)
|
||||
5. [Storm 编程模型详解](notes/Storm编程模型详解.md)
|
||||
6. [Storm 项目三种打包方式对比分析](notes/Storm三种打包方式对比分析.md)
|
||||
7. [Storm 集成 Redis 详解](notes/Storm集成Redis详解.md)
|
||||
8. [Storm 集成 HDFS/HBase](notes/Storm集成HBase和HDFS.md)
|
||||
9. [Storm 集成 Kafka](notes/Storm集成Kakfa.md)
|
||||
|
||||
## 五、Flink
|
||||
|
||||
1. [Flink 核心概念综述](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flink核心概念综述.md)
|
||||
2. [Flink 开发环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flink开发环境搭建.md)
|
||||
3. [Flink Data Source](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flink_Data_Source.md)
|
||||
4. [Flink Data Transformation](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flink_Data_Transformation.md)
|
||||
4. [Flink Data Sink](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flink_Data_Sink.md)
|
||||
6. [Flink 窗口模型](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flink_Windows.md)
|
||||
7. [Flink 状态管理与检查点机制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flink状态管理与检查点机制.md)
|
||||
8. [Flink Standalone 集群部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Flink_Standalone_Cluster.md)
|
||||
1. [Flink 核心概念综述](notes/Flink核心概念综述.md)
|
||||
2. [Flink 开发环境搭建](notes/Flink开发环境搭建.md)
|
||||
3. [Flink Data Source](notes/Flink_Data_Source.md)
|
||||
4. [Flink Data Transformation](notes/Flink_Data_Transformation.md)
|
||||
4. [Flink Data Sink](notes/Flink_Data_Sink.md)
|
||||
6. [Flink 窗口模型](notes/Flink_Windows.md)
|
||||
7. [Flink 状态管理与检查点机制](notes/Flink状态管理与检查点机制.md)
|
||||
8. [Flink Standalone 集群部署](notes/installation/Flink_Standalone_Cluster.md)
|
||||
|
||||
|
||||
## 六、HBase
|
||||
|
||||
1. [Hbase 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase简介.md)
|
||||
2. [HBase 系统架构及数据结构](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase系统架构及数据结构.md)
|
||||
3. [HBase 基本环境搭建 (Standalone /pseudo-distributed mode)](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/HBase单机环境搭建.md)
|
||||
4. [HBase 集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/HBase集群环境搭建.md)
|
||||
5. [HBase 常用 Shell 命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase_Shell.md)
|
||||
6. [HBase Java API](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase_Java_API.md)
|
||||
7. [Hbase 过滤器详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase过滤器详解.md)
|
||||
8. [HBase 协处理器详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase协处理器详解.md)
|
||||
9. [HBase 容灾与备份](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase容灾与备份.md)
|
||||
10. [HBase的 SQL 中间层 —— Phoenix](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Hbase的SQL中间层_Phoenix.md)
|
||||
11. [Spring/Spring Boot 整合 Mybatis + Phoenix](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spring+Mybtais+Phoenix整合.md)
|
||||
1. [Hbase 简介](notes/Hbase简介.md)
|
||||
2. [HBase 系统架构及数据结构](notes/Hbase系统架构及数据结构.md)
|
||||
3. [HBase 基本环境搭建 (Standalone /pseudo-distributed mode)](notes/installation/HBase单机环境搭建.md)
|
||||
4. [HBase 集群环境搭建](notes/installation/HBase集群环境搭建.md)
|
||||
5. [HBase 常用 Shell 命令](notes/Hbase_Shell.md)
|
||||
6. [HBase Java API](notes/Hbase_Java_API.md)
|
||||
7. [Hbase 过滤器详解](notes/Hbase过滤器详解.md)
|
||||
8. [HBase 协处理器详解](notes/Hbase协处理器详解.md)
|
||||
9. [HBase 容灾与备份](notes/Hbase容灾与备份.md)
|
||||
10. [HBase的 SQL 中间层 —— Phoenix](notes/Hbase的SQL中间层_Phoenix.md)
|
||||
11. [Spring/Spring Boot 整合 Mybatis + Phoenix](notes/Spring+Mybtais+Phoenix整合.md)
|
||||
|
||||
## 七、Kafka
|
||||
|
||||
1. [Kafka 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka简介.md)
|
||||
2. [基于 Zookeeper 搭建 Kafka 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
|
||||
3. [Kafka 生产者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka生产者详解.md)
|
||||
4. [Kafka 消费者详解](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka消费者详解.md)
|
||||
5. [深入理解 Kafka 副本机制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Kafka深入理解分区副本机制.md)
|
||||
1. [Kafka 简介](notes/Kafka简介.md)
|
||||
2. [基于 Zookeeper 搭建 Kafka 高可用集群](notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
|
||||
3. [Kafka 生产者详解](notes/Kafka生产者详解.md)
|
||||
4. [Kafka 消费者详解](notes/Kafka消费者详解.md)
|
||||
5. [深入理解 Kafka 副本机制](notes/Kafka深入理解分区副本机制.md)
|
||||
|
||||
## 八、Zookeeper
|
||||
|
||||
1. [Zookeeper 简介及核心概念](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper简介及核心概念.md)
|
||||
2. [Zookeeper 单机环境和集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Zookeeper单机环境和集群环境搭建.md)
|
||||
3. [Zookeeper 常用 Shell 命令](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper常用Shell命令.md)
|
||||
4. [Zookeeper Java 客户端 —— Apache Curator](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_Java客户端Curator.md)
|
||||
5. [Zookeeper ACL 权限控制](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Zookeeper_ACL权限控制.md)
|
||||
1. [Zookeeper 简介及核心概念](notes/Zookeeper简介及核心概念.md)
|
||||
2. [Zookeeper 单机环境和集群环境搭建](notes/installation/Zookeeper单机环境和集群环境搭建.md)
|
||||
3. [Zookeeper 常用 Shell 命令](notes/Zookeeper常用Shell命令.md)
|
||||
4. [Zookeeper Java 客户端 —— Apache Curator](notes/Zookeeper_Java客户端Curator.md)
|
||||
5. [Zookeeper ACL 权限控制](notes/Zookeeper_ACL权限控制.md)
|
||||
|
||||
## 九、Flume
|
||||
|
||||
1. [Flume 简介及基本使用](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flume简介及基本使用.md)
|
||||
2. [Linux 环境下 Flume 的安装部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Linux下Flume的安装.md)
|
||||
3. [Flume 整合 Kafka](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Flume整合Kafka.md)
|
||||
1. [Flume 简介及基本使用](notes/Flume简介及基本使用.md)
|
||||
2. [Linux 环境下 Flume 的安装部署](notes/installation/Linux下Flume的安装.md)
|
||||
3. [Flume 整合 Kafka](notes/Flume整合Kafka.md)
|
||||
|
||||
## 十、Sqoop
|
||||
|
||||
1. [Sqoop 简介与安装](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Sqoop简介与安装.md)
|
||||
2. [Sqoop 的基本使用](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Sqoop基本使用.md)
|
||||
1. [Sqoop 简介与安装](notes/Sqoop简介与安装.md)
|
||||
2. [Sqoop 的基本使用](notes/Sqoop基本使用.md)
|
||||
|
||||
## 十一、Azkaban
|
||||
|
||||
1. [Azkaban 简介](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Azkaban简介.md)
|
||||
2. [Azkaban3.x 编译及部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Azkaban_3.x_编译及部署.md)
|
||||
3. [Azkaban Flow 1.0 的使用](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Azkaban_Flow_1.0_的使用.md)
|
||||
4. [Azkaban Flow 2.0 的使用](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Azkaban_Flow_2.0_的使用.md)
|
||||
1. [Azkaban 简介](notes/Azkaban简介.md)
|
||||
2. [Azkaban3.x 编译及部署](notes/installation/Azkaban_3.x_编译及部署.md)
|
||||
3. [Azkaban Flow 1.0 的使用](notes/Azkaban_Flow_1.0_的使用.md)
|
||||
4. [Azkaban Flow 2.0 的使用](notes/Azkaban_Flow_2.0_的使用.md)
|
||||
|
||||
## 十二、Scala
|
||||
|
||||
1. [Scala 简介及开发环境配置](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala简介及开发环境配置.md)
|
||||
2. [基本数据类型和运算符](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala基本数据类型和运算符.md)
|
||||
3. [流程控制语句](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala流程控制语句.md)
|
||||
4. [数组 —— Array](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala数组.md)
|
||||
5. [集合类型综述](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala集合类型.md)
|
||||
6. [常用集合类型之 —— List & Set](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala列表和集.md)
|
||||
7. [常用集合类型之 —— Map & Tuple](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala映射和元组.md)
|
||||
8. [类和对象](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala类和对象.md)
|
||||
9. [继承和特质](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala继承和特质.md)
|
||||
10. [函数 & 闭包 & 柯里化](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala函数和闭包.md)
|
||||
11. [模式匹配](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala模式匹配.md)
|
||||
12. [类型参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala类型参数.md)
|
||||
13. [隐式转换和隐式参数](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Scala隐式转换和隐式参数.md)
|
||||
1. [Scala 简介及开发环境配置](notes/Scala简介及开发环境配置.md)
|
||||
2. [基本数据类型和运算符](notes/Scala基本数据类型和运算符.md)
|
||||
3. [流程控制语句](notes/Scala流程控制语句.md)
|
||||
4. [数组 —— Array](notes/Scala数组.md)
|
||||
5. [集合类型综述](notes/Scala集合类型.md)
|
||||
6. [常用集合类型之 —— List & Set](notes/Scala列表和集.md)
|
||||
7. [常用集合类型之 —— Map & Tuple](notes/Scala映射和元组.md)
|
||||
8. [类和对象](notes/Scala类和对象.md)
|
||||
9. [继承和特质](notes/Scala继承和特质.md)
|
||||
10. [函数 & 闭包 & 柯里化](notes/Scala函数和闭包.md)
|
||||
11. [模式匹配](notes/Scala模式匹配.md)
|
||||
12. [类型参数](notes/Scala类型参数.md)
|
||||
13. [隐式转换和隐式参数](notes/Scala隐式转换和隐式参数.md)
|
||||
|
||||
|
||||
## 十三、公共内容
|
||||
|
||||
1. [大数据应用常用打包方式](https://github.com/heibaiying/BigData-Notes/blob/master/notes/大数据应用常用打包方式.md)
|
||||
1. [大数据应用常用打包方式](notes/大数据应用常用打包方式.md)
|
||||
|
||||
<br>
|
||||
|
||||
## :bookmark_tabs: 后 记
|
||||
|
||||
[资料分享与开发工具推荐](https://github.com/heibaiying/BigData-Notes/blob/master/notes/资料分享与工具推荐.md)
|
||||
[资料分享与开发工具推荐](notes/资料分享与工具推荐.md)
|
@ -27,7 +27,7 @@ Azkaban 主要通过界面上传配置文件来进行任务的调度。它有两
|
||||
|
||||
在 Azkaban 主界面可以创建对应的项目:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-create-project.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-create-project.png"/> </div>
|
||||
|
||||
### 2.2 任务配置
|
||||
|
||||
@ -43,29 +43,29 @@ command=echo 'Hello Azkaban!'
|
||||
|
||||
将 `Hello-Azkaban.job ` 打包为 `zip` 压缩文件:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-zip.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-zip.png"/> </div>
|
||||
|
||||
通过 Web UI 界面上传:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-upload.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-upload.png"/> </div>
|
||||
|
||||
上传成功后可以看到对应的 Flows:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-flows.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-flows.png"/> </div>
|
||||
|
||||
### 2.4 执行任务
|
||||
|
||||
点击页面上的 `Execute Flow` 执行任务:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-execute.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-execute.png"/> </div>
|
||||
|
||||
### 2.5 执行结果
|
||||
|
||||
点击 `detail` 可以查看到任务的执行日志:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-successed.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-successed.png"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-log.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-log.png"/> </div>
|
||||
|
||||
## 三、多任务调度
|
||||
|
||||
@ -114,17 +114,17 @@ dependencies=Task-D
|
||||
|
||||
压缩后进行上传,这里需要注意的是一个 Project 只能接收一个压缩包,这里我还沿用上面的 Project,默认后面的压缩包会覆盖前面的压缩包:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-task-abcde-zip.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-task-abcde-zip.png"/> </div>
|
||||
|
||||
### 3.3 依赖关系
|
||||
|
||||
多个任务存在依赖时,默认采用最后一个任务的文件名作为 Flow 的名称,其依赖关系如图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-dependencies.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-dependencies.png"/> </div>
|
||||
|
||||
### 3.4 执行结果
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-task-abcde.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-task-abcde.png"/> </div>
|
||||
|
||||
从这个案例可以看出,Flow1.0 无法通过一个 job 文件来完成多个任务的配置,但是 Flow 2.0 就很好的解决了这个问题。
|
||||
|
||||
@ -139,7 +139,7 @@ command=/usr/app/hadoop-2.6.0-cdh5.15.2/bin/hadoop fs -ls /
|
||||
|
||||
执行结果:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-hdfs.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-hdfs.png"/> </div>
|
||||
|
||||
## 五、调度MR作业
|
||||
|
||||
@ -152,7 +152,7 @@ command=/usr/app/hadoop-2.6.0-cdh5.15.2/bin/hadoop jar /usr/app/hadoop-2.6.0-cdh
|
||||
|
||||
执行结果:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-mr.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-mr.png"/> </div>
|
||||
|
||||
## 六、调度Hive作业
|
||||
|
||||
@ -185,25 +185,25 @@ desc emp;
|
||||
|
||||
打包的时候将 `job` 文件与 `sql` 文件一并进行打包:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-hive.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-hive.png"/> </div>
|
||||
|
||||
执行结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-hive-result.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-hive-result.png"/> </div>
|
||||
|
||||
## 七、在线修改作业配置
|
||||
|
||||
在测试时,我们可能需要频繁修改配置,如果每次修改都要重新打包上传,这会比较麻烦。所以 Azkaban 支持配置的在线修改,点击需要修改的 Flow,就可以进入详情页面:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-project-edit.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-project-edit.png"/> </div>
|
||||
|
||||
在详情页面点击 `Eidt` 按钮可以进入编辑页面:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-edit.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-edit.png"/> </div>
|
||||
|
||||
在编辑页面可以新增配置或者修改配置:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-click-edit.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-click-edit.png"/> </div>
|
||||
|
||||
## 附:可能出现的问题
|
||||
|
||||
@ -213,7 +213,7 @@ desc emp;
|
||||
Cannot request memory (Xms 0 kb, Xmx 0 kb) from system for job
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-memory.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-memory.png"/> </div>
|
||||
|
||||
如果你的执行主机没办法增大内存,那么可以通过修改 `plugins/jobtypes/` 目录下的 `commonprivate.properties` 文件来关闭内存检查,配置如下:
|
||||
|
||||
|
@ -198,7 +198,7 @@ azkaban-flow-version: 2.0
|
||||
|
||||
### 3.2 打包上传
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-simple.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-simple.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -206,7 +206,7 @@ azkaban-flow-version: 2.0
|
||||
|
||||
由于在 1.0 版本中已经介绍过 Web UI 的使用,这里就不再赘述。对于 1.0 和 2.0 版本,只有配置方式有所不同,其他上传执行的方式都是相同的。执行结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-simle-result.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-simle-result.png"/> </div>
|
||||
|
||||
## 四、多任务调度
|
||||
|
||||
@ -281,11 +281,11 @@ nodes:
|
||||
|
||||
内嵌流的 DAG 图如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-embeded-flow.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-embeded-flow.png"/> </div>
|
||||
|
||||
执行情况如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-embeded-success.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-embeded-success.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -32,7 +32,7 @@ Azkaban 产生于 LinkedIn,并经过多年生产环境的检验,它具备以
|
||||
|
||||
Azkaban 的设计理念是在保证功能实现的基础上兼顾易用性,其页面风格清晰明朗,下面是其 WEB UI 界面:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-web.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/azkaban-web.png"/> </div>
|
||||
|
||||
## 二、Azkaban 和 Oozie
|
||||
|
||||
|
@ -163,7 +163,7 @@ bin/kafka-console-consumer.sh --bootstrap-server hadoop001:9092 --topic flink-st
|
||||
|
||||
在 Kafka 生产者上发送消息到 Flink 程序,观察 Flink 程序转换后的输出情况,具体如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-kafka-producer-consumer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-kafka-producer-consumer.png"/> </div>
|
||||
|
||||
|
||||
可以看到 Kafka 生成者发出的数据已经被 Flink 程序正常接收到,并经过转换后又输出到 Kafka 对应的 Topic 上。
|
||||
@ -172,7 +172,7 @@ bin/kafka-console-consumer.sh --bootstrap-server hadoop001:9092 --topic flink-st
|
||||
|
||||
除了使用内置的第三方连接器外,Flink 还支持使用自定义的 Sink 来满足多样化的输出需求。想要实现自定义的 Sink ,需要直接或者间接实现 SinkFunction 接口。通常情况下,我们都是实现其抽象类 RichSinkFunction,相比于 SinkFunction ,其提供了更多的与生命周期相关的方法。两者间的关系如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-richsink.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-richsink.png"/> </div>
|
||||
|
||||
|
||||
这里我们以自定义一个 FlinkToMySQLSink 为例,将计算结果写出到 MySQL 数据库中,具体步骤如下:
|
||||
@ -251,7 +251,7 @@ env.execute();
|
||||
|
||||
启动程序,观察数据库写入情况:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-mysql-sink.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-mysql-sink.png"/> </div>
|
||||
|
||||
|
||||
数据库成功写入,代表自定义 Sink 整合成功。
|
||||
|
@ -154,7 +154,7 @@ Exception in thread "main" java.lang.IllegalArgumentException: Source: 1 is not
|
||||
|
||||
如果你想要实现具有并行度的输入流,则需要实现 ParallelSourceFunction 或 RichParallelSourceFunction 接口,其与 SourceFunction 的关系如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-RichParallelSourceFunction.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-RichParallelSourceFunction.png"/> </div>
|
||||
ParallelSourceFunction 直接继承自 ParallelSourceFunction,具有并行度的功能。RichParallelSourceFunction 则继承自 AbstractRichFunction,同时实现了 ParallelSourceFunction 接口,所以其除了具有并行度的功能外,还提供了额外的与生命周期相关的方法,如 open() ,closen() 。
|
||||
|
||||
## 三、Streaming Connectors
|
||||
@ -269,10 +269,10 @@ bin/kafka-console-producer.sh --broker-list hadoop001:9092 --topic flink-stream-
|
||||
|
||||
在 Producer 上输入任意测试数据,之后观察程序控制台的输出:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-kafka-datasource-producer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-kafka-datasource-producer.png"/> </div>
|
||||
程序控制台的输出如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-kafka-datasource-console.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-kafka-datasource-console.png"/> </div>
|
||||
可以看到已经成功接收并打印出相关的数据。
|
||||
|
||||
|
||||
|
@ -234,7 +234,7 @@ dataStream.rescale();
|
||||
|
||||
ReScale 这个单词具有重新缩放的意义,其对应的操作也是如此,具体如下:如果上游 operation 并行度为 2,而下游的 operation 并行度为 6,则其中 1 个上游的 operation 会将元素分发到 3 个下游 operation,另 1 个上游 operation 则会将元素分发到另外 3 个下游 operation。反之亦然,如果上游的 operation 并行度为 6,而下游 operation 并行度为 2,则其中 3 个上游 operation 会将元素分发到 1 个下游 operation,另 3 个上游 operation 会将元素分发到另外 1 个下游operation:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-Rescaling.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-Rescaling.png"/> </div>
|
||||
|
||||
|
||||
### 3.4 Broadcasting [DataStream → DataStream]
|
||||
|
@ -23,7 +23,7 @@ Time Windows 用于以时间为维度来进行数据聚合,具体分为以下
|
||||
|
||||
滚动窗口 (Tumbling Windows) 是指彼此之间没有重叠的窗口。例如:每隔1小时统计过去1小时内的商品点击量,那么 1 天就只能分为 24 个窗口,每个窗口彼此之间是不存在重叠的,具体如下:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-tumbling-windows.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/flink-tumbling-windows.png"/> </div>
|
||||
|
||||
|
||||
这里我们以词频统计为例,给出一个具体的用例,代码如下:
|
||||
@ -46,7 +46,7 @@ env.execute("Flink Streaming");
|
||||
|
||||
测试结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-window-word-count.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-window-word-count.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -55,7 +55,7 @@ env.execute("Flink Streaming");
|
||||
|
||||
滑动窗口用于滚动进行聚合分析,例如:每隔 6 分钟统计一次过去一小时内所有商品的点击量,那么统计窗口彼此之间就是存在重叠的,即 1天可以分为 240 个窗口。图示如下:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-sliding-windows.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/flink-sliding-windows.png"/> </div>
|
||||
|
||||
|
||||
可以看到 window 1 - 4 这四个窗口彼此之间都存在着时间相等的重叠部分。想要实现滑动窗口,只需要在使用 timeWindow 方法时额外传递第二个参数作为滚动时间即可,具体如下:
|
||||
@ -69,7 +69,7 @@ timeWindow(Time.minutes(1),Time.seconds(3))
|
||||
|
||||
当用户在进行持续浏览时,可能每时每刻都会有点击数据,例如在活动区间内,用户可能频繁的将某类商品加入和移除购物车,而你只想知道用户本次浏览最终的购物车情况,此时就可以在用户持有的会话结束后再进行统计。想要实现这类统计,可以通过 Session Windows 来进行实现。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-session-windows.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/flink-session-windows.png"/> </div>
|
||||
|
||||
|
||||
具体的实现代码如下:
|
||||
@ -85,7 +85,7 @@ window(EventTimeSessionWindows.withGap(Time.seconds(10)))
|
||||
|
||||
最后一个窗口是全局窗口, 全局窗口会将所有 key 相同的元素分配到同一个窗口中,其通常配合触发器 (trigger) 进行使用。如果没有相应触发器,则计算将不会被执行。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-non-windowed.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/flink-non-windowed.png"/> </div>
|
||||
|
||||
|
||||
这里继续以上面词频统计的案例为例,示例代码如下:
|
||||
|
@ -20,7 +20,7 @@
|
||||
|
||||
Flink 分别提供了基于 Java 语言和 Scala 语言的 API ,如果想要使用 Scala 语言来开发 Flink 程序,可以通过在 IDEA 中安装 Scala 插件来提供语法提示,代码高亮等功能。打开 IDEA , 依次点击 `File => settings => plugins` 打开插件安装页面,搜索 Scala 插件并进行安装,安装完成后,重启 IDEA 即可生效。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-plugin.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-plugin.png"/> </div>
|
||||
|
||||
## 二、Flink 项目初始化
|
||||
|
||||
@ -71,11 +71,11 @@ mvn archetype:generate \
|
||||
|
||||
如果你使用的是开发工具是 IDEA ,可以直接在项目创建页面选择 Maven Flink Archetype 进行项目初始化:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-maven.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-maven.png"/> </div>
|
||||
|
||||
如果你的 IDEA 没有上述 Archetype, 可以通过点击右上角的 `ADD ARCHETYPE` ,来进行添加,依次填入所需信息,这些信息都可以从上述的 `archetype:generate ` 语句中获取。点击 `OK` 保存后,该 Archetype 就会一直存在于你的 IDEA 中,之后每次创建项目时,只需要直接选择该 Archetype 即可:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-maven-new.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-maven-new.png"/> </div>
|
||||
|
||||
选中 Flink Archetype ,然后点击 `NEXT` 按钮,之后的所有步骤都和正常的 Maven 工程相同。
|
||||
|
||||
@ -85,7 +85,7 @@ mvn archetype:generate \
|
||||
|
||||
创建完成后的自动生成的项目结构如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-basis-project.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-basis-project.png"/> </div>
|
||||
|
||||
其中 BatchJob 为批处理的样例代码,源码如下:
|
||||
|
||||
@ -149,7 +149,7 @@ object StreamingJob {
|
||||
|
||||
需要特别注意的以上依赖的 `scope` 标签全部被标识为 provided ,这意味着这些依赖都不会被打入最终的 JAR 包。因为 Flink 的安装包中已经提供了这些依赖,位于其 lib 目录下,名为 `flink-dist_*.jar` ,它包含了 Flink 的所有核心类和依赖:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-lib.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-lib.png"/> </div>
|
||||
|
||||
`scope` 标签被标识为 provided 会导致你在 IDEA 中启动项目时会抛出 ClassNotFoundException 异常。基于这个原因,在使用 IDEA 创建项目时还自动生成了以下 profile 配置:
|
||||
|
||||
@ -193,7 +193,7 @@ object StreamingJob {
|
||||
|
||||
在 id 为 `add-dependencies-for-IDEA` 的 profile 中,所有的核心依赖都被标识为 compile,此时你可以无需改动任何代码,只需要在 IDEA 的 Maven 面板中勾选该 profile,即可直接在 IDEA 中运行 Flink 项目:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-maven-profile.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-maven-profile.png"/> </div>
|
||||
|
||||
## 四、词频统计案例
|
||||
|
||||
@ -230,7 +230,7 @@ d,d
|
||||
|
||||
本机不需要配置其他任何的 Flink 环境,直接运行 Main 方法即可,结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-word-count.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-word-count.png"/> </div>
|
||||
|
||||
### 4.2 流处理示例
|
||||
|
||||
@ -275,7 +275,7 @@ https://flink.apache.org/downloads.html
|
||||
|
||||
Flink 大多数版本都提供有 Scala 2.11 和 Scala 2.12 两个版本的安装包可供下载:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-download.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-download.png"/> </div>
|
||||
|
||||
下载完成后进行解压即可,Scala Shell 位于安装目录的 bin 目录下,直接使用以下命令即可以本地模式启动:
|
||||
|
||||
@ -285,7 +285,7 @@ Flink 大多数版本都提供有 Scala 2.11 和 Scala 2.12 两个版本的安
|
||||
|
||||
命令行启动完成后,其已经提供了批处理 (benv 和 btenv)和流处理(senv 和 stenv)的运行环境,可以直接运行 Scala Flink 程序,示例如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-scala-shell.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-scala-shell.png"/> </div>
|
||||
|
||||
最后解释一个常见的异常:这里我使用的 Flink 版本为 1.9.1,启动时会抛出如下异常。这里因为按照官方的说明,目前所有 Scala 2.12 版本的安装包暂时都不支持 Scala Shell,所以如果想要使用 Scala Shell,只能选择 Scala 2.11 版本的安装包。
|
||||
|
||||
|
@ -26,14 +26,14 @@ Apache Flink 诞生于柏林工业大学的一个研究性项目,原名 Strato
|
||||
|
||||
Flink 有界数据流和无界数据流:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-bounded-unbounded.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/flink-bounded-unbounded.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
||||
Spark Streaming 数据流的拆分:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/streaming-flow.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/streaming-flow.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -42,7 +42,7 @@ Spark Streaming 数据流的拆分:
|
||||
|
||||
Flink 采用分层的架构设计,从而保证各层在功能和职责上的清晰。如下图所示,由上而下分别是 API & Libraries 层、Runtime 核心层以及物理部署层:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-stack.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/flink-stack.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -66,7 +66,7 @@ Flink 的物理部署层,用于支持在不同平台上部署运行 Flink 应
|
||||
|
||||
在上面介绍的 API & Libraries 这一层,Flink 又进行了更为具体的划分。具体如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-api-stack.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-api-stack.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -96,7 +96,7 @@ Stateful Stream Processing 是最低级别的抽象,它通过 Process Function
|
||||
- **Dispatcher**:负责接收客户端提交的执行程序,并传递给 JobManager 。除此之外,它还提供了一个 WEB UI 界面,用于监控作业的执行情况。
|
||||
- **ResourceManager** :负责管理 slots 并协调集群资源。ResourceManager 接收来自 JobManager 的资源请求,并将存在空闲 slots 的 TaskManagers 分配给 JobManager 执行任务。Flink 基于不同的部署平台,如 YARN , Mesos,K8s 等提供了不同的资源管理器,当 TaskManagers 没有足够的 slots 来执行任务时,它会向第三方平台发起会话来请求额外的资源。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-application-submission.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-application-submission.png"/> </div>
|
||||
|
||||
|
||||
### 4.2 Task & SubTask
|
||||
@ -105,7 +105,7 @@ Stateful Stream Processing 是最低级别的抽象,它通过 Process Function
|
||||
|
||||
在执行分布式计算时,Flink 将可以链接的操作 (operators) 链接到一起,这就是 Task。之所以这样做, 是为了减少线程间切换和缓冲而导致的开销,在降低延迟的同时可以提高整体的吞吐量。 但不是所有的 operator 都可以被链接,如下 keyBy 等操作会导致网络 shuffle 和重分区,因此其就不能被链接,只能被单独作为一个 Task。 简单来说,一个 Task 就是一个可以链接的最小的操作链 (Operator Chains) 。如下图,source 和 map 算子被链接到一块,因此整个作业就只有三个 Task:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-task-subtask.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-task-subtask.png"/> </div>
|
||||
|
||||
|
||||
解释完 Task ,我们在解释一下什么是 SubTask,其准确的翻译是: *A subtask is one parallel slice of a task*,即一个 Task 可以按照其并行度拆分为多个 SubTask。如上图,source & map 具有两个并行度,KeyBy 具有两个并行度,Sink 具有一个并行度,因此整个虽然只有 3 个 Task,但是却有 5 个 SubTask。Jobmanager 负责定义和拆分这些 SubTask,并将其交给 Taskmanagers 来执行,每个 SubTask 都是一个单独的线程。
|
||||
@ -114,7 +114,7 @@ Stateful Stream Processing 是最低级别的抽象,它通过 Process Function
|
||||
|
||||
理解了 SubTasks ,我们再来看看其与 Slots 的对应情况。一种可能的分配情况如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-tasks-slots.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-tasks-slots.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -123,14 +123,14 @@ Stateful Stream Processing 是最低级别的抽象,它通过 Process Function
|
||||
|
||||
基于这个原因,Flink 允许多个 subtasks 共享 slots,即使它们是不同 tasks 的 subtasks,但只要它们来自同一个 Job 就可以。假设上面 souce & map 和 keyBy 的并行度调整为 6,而 Slot 的数量不变,此时情况如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-subtask-slots.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-subtask-slots.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
||||
可以看到一个 Task Slot 中运行了多个 SubTask 子任务,此时每个子任务仍然在一个独立的线程中执行,只不过共享一组 Sot 资源而已。那么 Flink 到底如何确定一个 Job 至少需要多少个 Slot 呢?Flink 对于这个问题的处理很简单,默认情况一个 Job 所需要的 Slot 的数量就等于其 Operation 操作的最高并行度。如下, A,B,D 操作的并行度为 4,而 C,E 操作的并行度为 2,那么此时整个 Job 就需要至少四个 Slots 来完成。通过这个机制,Flink 就可以不必去关心一个 Job 到底会被拆分为多少个 Tasks 和 SubTasks。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-task-parallelism.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-task-parallelism.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -141,7 +141,7 @@ Stateful Stream Processing 是最低级别的抽象,它通过 Process Function
|
||||
|
||||
Flink 的所有组件都基于 Actor System 来进行通讯。Actor system是多种角色的 actor 的容器,它提供调度,配置,日志记录等多种服务,并包含一个可以启动所有 actor 的线程池,如果 actor 是本地的,则消息通过共享内存进行共享,但如果 actor 是远程的,则通过 RPC 的调用来传递消息。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-process.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-process.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
|
||||
相对于其他流计算框架,Flink 一个比较重要的特性就是其支持有状态计算。即你可以将中间的计算结果进行保存,并提供给后续的计算使用:
|
||||
|
||||
<div align="center"> <img width="500px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-stateful-stream.png"/> </div>
|
||||
<div align="center"> <img width="500px" src="../pictures/flink-stateful-stream.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
算子状态 (Operator State):顾名思义,状态是和算子进行绑定的,一个算子的状态不能被其他算子所访问到。官方文档上对 Operator State 的解释是:*each operator state is bound to one parallel operator instance*,所以更为确切的说一个算子状态是与一个并发的算子实例所绑定的,即假设算子的并行度是 2,那么其应有两个对应的算子状态:
|
||||
|
||||
<div align="center"> <img width="500px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-operator-state.png"/> </div>
|
||||
<div align="center"> <img width="500px" src="../pictures/flink-operator-state.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@
|
||||
|
||||
键控状态 (Keyed State) :是一种特殊的算子状态,即状态是根据 key 值进行区分的,Flink 会为每类键值维护一个状态实例。如下图所示,每个颜色代表不同 key 值,对应四个不同的状态实例。需要注意的是键控状态只能在 `KeyedStream` 上进行使用,我们可以通过 `stream.keyBy(...)` 来得到 `KeyedStream` 。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-keyed-state.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-keyed-state.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -118,7 +118,7 @@ env.execute("Managed Keyed State");
|
||||
|
||||
输出如下结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-state-management.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-state-management.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -232,13 +232,13 @@ env.execute("Managed Keyed State");
|
||||
|
||||
此时输出如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-operator-state-para1.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-operator-state-para1.png"/> </div>
|
||||
|
||||
|
||||
|
||||
在上面的调用代码中,我们将程序的并行度设置为 1,可以看到三次输出中状态实例的 hashcode 全是一致的,证明它们都同一个状态实例。假设将并行度设置为 2,此时输出如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-operator-state-para2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-operator-state-para2.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -250,7 +250,7 @@ env.execute("Managed Keyed State");
|
||||
|
||||
为了使 Flink 的状态具有良好的容错性,Flink 提供了检查点机制 (CheckPoints) 。通过检查点机制,Flink 定期在数据流上生成 checkpoint barrier ,当某个算子收到 barrier 时,即会基于当前状态生成一份快照,然后再将该 barrier 传递到下游算子,下游算子接收到该 barrier 后,也基于当前状态生成一份快照,依次传递直至到最后的 Sink 算子上。当出现异常后,Flink 就可以根据最近的一次的快照数据将所有算子恢复到先前的状态。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-stream-barriers.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-stream-barriers.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -297,7 +297,7 @@ bin/flink savepoint :jobId [:targetDirectory]
|
||||
|
||||
默认情况下,所有的状态都存储在 JVM 的堆内存中,在状态数据过多的情况下,这种方式很有可能导致内存溢出,因此 Flink 该提供了其它方式来存储状态数据,这些存储方式统一称为状态后端 (或状态管理器):
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-checkpoints-backend.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flink-checkpoints-backend.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
以实时流处理项目为例,由于采集的数据量可能存在峰值和峰谷,假设是一个电商项目,那么峰值通常出现在秒杀时,这时如果直接将 Flume 聚合后的数据输入到 Storm 等分布式计算框架中,可能就会超过集群的处理能力,这时采用 Kafka 就可以起到削峰的作用。Kafka 天生为大数据场景而设计,具有高吞吐的特性,能很好地抗住峰值数据的冲击。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-kafka.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-kafka.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -109,8 +109,8 @@ flume-ng agent \
|
||||
|
||||
向监听的 `/tmp/kafka.log ` 文件中追加内容,查看 Kafka 消费者的输出:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-kafka-01.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-kafka-01.png"/> </div>
|
||||
|
||||
可以看到 `flume-kafka` 主题的消费端已经收到了对应的消息:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-kafka-2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-kafka-2.png"/> </div>
|
||||
|
@ -23,7 +23,7 @@ Apache Flume 是一个分布式,高可用的数据收集系统。它可以从
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-architecture.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-architecture.png"/> </div>
|
||||
|
||||
### 2.1 基本架构
|
||||
|
||||
@ -80,7 +80,7 @@ Flume 支持多种架构模式,分别介绍如下
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-multi-agent-flow.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-multi-agent-flow.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
@ -88,7 +88,7 @@ Flume 支持跨越多个 Agent 的数据传递,这要求前一个 Agent 的 Si
|
||||
|
||||
### 3.2 Consolidation
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-consolidation.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-consolidation.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -98,7 +98,7 @@ Flume 支持跨越多个 Agent 的数据传递,这要求前一个 Agent 的 Si
|
||||
|
||||
### 3.3 Multiplexing the flow
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-multiplexing-the-flow.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-multiplexing-the-flow.png"/> </div>
|
||||
|
||||
Flume 支持从一个 Source 向多个 Channel,也就是向多个 Sink 传递事件,这个操作称之为 `Fan Out`(扇出)。默认情况下 `Fan Out` 是向所有的 Channel 复制 `Event`,即所有 Channel 收到的数据都是相同的。同时 Flume 也支持在 `Source` 上自定义一个复用选择器 (multiplexing selector) 来实现自定义的路由规则。
|
||||
|
||||
@ -201,11 +201,11 @@ flume-ng agent \
|
||||
|
||||
向文件中追加数据:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-example-1.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-example-1.png"/> </div>
|
||||
|
||||
控制台的显示:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-example-2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-example-2.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -263,7 +263,7 @@ flume-ng agent \
|
||||
# cp log.txt logs/
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-example-3.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-example-3.png"/> </div>
|
||||
|
||||
查看上传到 HDFS 上的文件内容与本地是否一致:
|
||||
|
||||
@ -271,7 +271,7 @@ flume-ng agent \
|
||||
# hdfs dfs -cat /flume/events/19-04-09/13/log.txt.1554788567801
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-example-4.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-example-4.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -362,14 +362,14 @@ flume-ng agent \
|
||||
|
||||
这里建议按以上顺序启动,原因是 `avro.source` 会先与端口进行绑定,这样 `avro sink` 连接时才不会报无法连接的异常。但是即使不按顺序启动也是没关系的,`sink` 会一直重试,直至建立好连接。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-retry.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-retry.png"/> </div>
|
||||
|
||||
#### 4.测试
|
||||
|
||||
向文件 `tmp/log.txt` 中追加内容:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-example-8.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-example-8.png"/> </div>
|
||||
|
||||
可以看到已经从 8888 端口监听到内容,并成功输出到控制台:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-example-9.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-example-9.png"/> </div>
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
## 二、HDFS 设计原理
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfsarchitecture.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/hdfsarchitecture.png"/> </div>
|
||||
|
||||
### 2.1 HDFS 架构
|
||||
|
||||
@ -56,7 +56,7 @@ HDFS 的 ` 文件系统命名空间 ` 的层次结构与大多数文件系统类
|
||||
|
||||
由于 Hadoop 被设计运行在廉价的机器上,这意味着硬件是不可靠的,为了保证容错性,HDFS 提供了数据复制机制。HDFS 将每一个文件存储为一系列**块**,每个块由多个副本来保证容错,块的大小和复制因子可以自行配置(默认情况下,块大小是 128M,默认复制因子是 3)。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfsdatanodes.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/hdfsdatanodes.png"/> </div>
|
||||
|
||||
### 2.4 数据复制的实现原理
|
||||
|
||||
@ -64,7 +64,7 @@ HDFS 的 ` 文件系统命名空间 ` 的层次结构与大多数文件系统类
|
||||
|
||||
在写入程序位于 `datanode` 上时,就优先将写入文件的一个副本放置在该 `datanode` 上,否则放在随机 `datanode` 上。之后在另一个远程机架上的任意一个节点上放置另一个副本,并在该机架上的另一个节点上放置最后一个副本。此策略可以减少机架间的写入流量,从而提高写入性能。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-机架.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-机架.png"/> </div>
|
||||
|
||||
如果复制因子大于 3,则随机确定第 4 个和之后副本的放置位置,同时保持每个机架的副本数量低于上限,上限值通常为 `(复制系数 - 1)/机架数量 + 2`,需要注意的是不允许同一个 `dataNode` 上具有同一个块的多个副本。
|
||||
|
||||
@ -128,43 +128,43 @@ HDFS 具有良好的跨平台移植性,这使得其他大数据计算框架都
|
||||
|
||||
### 1. HDFS写数据原理
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-write-1.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-write-1.jpg"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-write-2.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-write-2.jpg"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-write-3.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-write-3.jpg"/> </div>
|
||||
|
||||
|
||||
|
||||
### 2. HDFS读数据原理
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-read-1.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-read-1.jpg"/> </div>
|
||||
|
||||
|
||||
|
||||
### 3. HDFS故障类型和其检测方法
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-tolerance-1.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-tolerance-1.jpg"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-tolerance-2.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-tolerance-2.jpg"/> </div>
|
||||
|
||||
|
||||
|
||||
**第二部分:读写故障的处理**
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-tolerance-3.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-tolerance-3.jpg"/> </div>
|
||||
|
||||
|
||||
|
||||
**第三部分:DataNode 故障处理**
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-tolerance-4.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-tolerance-4.jpg"/> </div>
|
||||
|
||||
|
||||
|
||||
**副本布局策略**:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hdfs-tolerance-5.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hdfs-tolerance-5.jpg"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -34,7 +34,7 @@ MapReduce 作业通过将输入的数据集拆分为独立的块,这些块由
|
||||
|
||||
这里以词频统计为例进行说明,MapReduce 处理的流程如下:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/mapreduceProcess.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/mapreduceProcess.png"/> </div>
|
||||
|
||||
1. **input** : 读取文本文件;
|
||||
|
||||
@ -50,7 +50,7 @@ MapReduce 编程模型中 `splitting` 和 `shuffing` 操作都是由框架实现
|
||||
|
||||
## 三、combiner & partitioner
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Detailed-Hadoop-MapReduce-Data-Flow-14.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/Detailed-Hadoop-MapReduce-Data-Flow-14.png"/> </div>
|
||||
|
||||
### 3.1 InputFormat & RecordReaders
|
||||
|
||||
@ -68,11 +68,11 @@ MapReduce 编程模型中 `splitting` 和 `shuffing` 操作都是由框架实现
|
||||
|
||||
不使用 combiner 的情况:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/mapreduce-without-combiners.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/mapreduce-without-combiners.png"/> </div>
|
||||
|
||||
使用 combiner 的情况:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/mapreduce-with-combiners.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/mapreduce-with-combiners.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -145,7 +145,7 @@ public class WordCountMapper extends Mapper<LongWritable, Text, Text, IntWritabl
|
||||
|
||||
`WordCountMapper` 对应下图的 Mapping 操作:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-code-mapping.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hadoop-code-mapping.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -187,7 +187,7 @@ public class WordCountReducer extends Reducer<Text, IntWritable, Text, IntWritab
|
||||
|
||||
如下图,`shuffling` 的输出是 reduce 的输入。这里的 key 是每个单词,values 是一个可迭代的数据类型,类似 `(1,1,1,...)`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-code-reducer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hadoop-code-reducer.png"/> </div>
|
||||
|
||||
### 4.4 WordCountApp
|
||||
|
||||
@ -290,7 +290,7 @@ hadoop fs -ls /wordcount/output/WordCountApp
|
||||
hadoop fs -cat /wordcount/output/WordCountApp/part-r-00000
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-wordcountapp.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hadoop-wordcountapp.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -311,11 +311,11 @@ job.setCombinerClass(WordCountReducer.class);
|
||||
|
||||
没有加入 `combiner` 的打印日志:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-no-combiner.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hadoop-no-combiner.png"/> </div>
|
||||
|
||||
加入 `combiner` 后的打印日志如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-combiner.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hadoop-combiner.png"/> </div>
|
||||
|
||||
这里我们只有一个输入文件并且小于 128M,所以只有一个 Map 进行处理。可以看到经过 combiner 后,records 由 `3519` 降低为 `6`(样本中单词种类就只有 6 种),在这个用例中 combiner 就能极大地降低需要传输的数据量。
|
||||
|
||||
@ -368,7 +368,7 @@ job.setNumReduceTasks(WordCountDataUtils.WORD_LIST.size());
|
||||
|
||||
执行结果如下,分别生成 6 个文件,每个文件中为对应单词的统计结果:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-wordcountcombinerpartition.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hadoop-wordcountcombinerpartition.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -18,13 +18,13 @@
|
||||
|
||||
**Apache YARN** (Yet Another Resource Negotiator) 是 hadoop 2.0 引入的集群资源管理系统。用户可以将各种服务框架部署在 YARN 上,由 YARN 进行统一地管理和资源分配。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/yarn-base.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/yarn-base.png"/> </div>
|
||||
|
||||
|
||||
|
||||
## 二、YARN架构
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Figure3Architecture-of-YARN.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/Figure3Architecture-of-YARN.png"/> </div>
|
||||
|
||||
### 1. ResourceManager
|
||||
|
||||
@ -57,7 +57,7 @@
|
||||
|
||||
## 三、YARN工作原理简述
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/yarn工作原理简图.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/yarn工作原理简图.png"/> </div>
|
||||
|
||||
1. `Client` 提交作业到 YARN 上;
|
||||
|
||||
@ -71,7 +71,7 @@
|
||||
|
||||
## 四、YARN工作原理详述
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/yarn工作原理.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/yarn工作原理.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -410,7 +410,7 @@ public class HBaseUtilsTest {
|
||||
|
||||
2.x 版本相比于 1.x 废弃了一部分方法,关于废弃的方法在源码中都会指明新的替代方法,比如,在 2.x 中创建表时:`HTableDescriptor` 和 `HColumnDescriptor` 等类都标识为废弃,取而代之的是使用 `TableDescriptorBuilder` 和 `ColumnFamilyDescriptorBuilder` 来定义表和列族。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/deprecated.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/deprecated.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -715,11 +715,11 @@ Connection 是一个集群连接,封装了与多台服务器(Matser/Region S
|
||||
+ **HBase Master** :主要用于执行 HBaseAdmin 接口的一些操作,例如建表等;
|
||||
+ **HBase RegionServer** :用于读、写数据。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-arc.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/hbase-arc.png"/> </div>
|
||||
|
||||
Connection 对象和实际的 Socket 连接之间的对应关系如下图:
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-connection.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/hbase-connection.png"/> </div>
|
||||
|
||||
> 上面两张图片引用自博客:[连接 HBase 的正确姿势](https://yq.aliyun.com/articles/581702?spm=a2c4e.11157919.spm-cont-list.1.146c27aeFxoMsN%20%E8%BF%9E%E6%8E%A5HBase%E7%9A%84%E6%AD%A3%E7%A1%AE%E5%A7%BF%E5%8A%BF)
|
||||
|
||||
|
@ -57,17 +57,17 @@ Observer 协处理器类似于关系型数据库中的触发器,当发生某
|
||||
|
||||
以上四种类型的 Observer 协处理器均继承自 `Coprocessor` 接口,这四个接口中分别定义了所有可用的钩子方法,以便在对应方法前后执行特定的操作。通常情况下,我们并不会直接实现上面接口,而是继承其 Base 实现类,Base 实现类只是简单空实现了接口中的方法,这样我们在实现自定义的协处理器时,就不必实现所有方法,只需要重写必要方法即可。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-coprocessor.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-coprocessor.png"/> </div>
|
||||
|
||||
这里以 `RegionObservers ` 为例,其接口类中定义了所有可用的钩子方法,下面截取了部分方法的定义,多数方法都是成对出现的,有 `pre` 就有 `post`:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/RegionObserver.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/RegionObserver.png"/> </div>
|
||||
|
||||
</br>
|
||||
|
||||
#### 4. 执行流程
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/RegionObservers-works.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/RegionObservers-works.png"/> </div>
|
||||
|
||||
+ 客户端发出 put 请求
|
||||
+ 该请求被分派给合适的 RegionServer 和 region
|
||||
@ -384,7 +384,7 @@ hadoop fs -put /usr/app/hbase-observer-coprocessor-1.0-SNAPSHOT.jar /hbase
|
||||
hadoop fs -ls /hbase
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-cp-hdfs.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-cp-hdfs.png"/> </div>
|
||||
|
||||
### 6.5 加载协处理器
|
||||
|
||||
@ -413,7 +413,7 @@ hbase > desc 'magazine'
|
||||
|
||||
协处理器出现在 `TABLE_ATTRIBUTES` 属性中则代表加载成功,如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-cp-load.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-cp-load.png"/> </div>
|
||||
|
||||
### 6.6 测试加载结果
|
||||
|
||||
@ -428,7 +428,7 @@ hbase > get 'magazine','rowkey1','article:content'
|
||||
|
||||
可以看到对于指定列的值已经执行了 append 操作:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-cp-helloworld.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-cp-helloworld.png"/> </div>
|
||||
|
||||
插入一组对照数据:
|
||||
|
||||
@ -441,7 +441,7 @@ hbase > get 'magazine','rowkey1','article:author'
|
||||
|
||||
可以看到对于正常的列还是执行 update 操作:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-cp-lisi.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-cp-lisi.png"/> </div>
|
||||
|
||||
### 6.7 卸载协处理器
|
||||
1. 卸载协处理器前需要先禁用表
|
||||
@ -467,7 +467,7 @@ hbase > enable 'magazine'
|
||||
hbase > desc 'magazine'
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-co-unload.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-co-unload.png"/> </div>
|
||||
|
||||
### 6.8 测试卸载结果
|
||||
|
||||
@ -479,7 +479,7 @@ hbase > put 'magazine', 'rowkey1','article:content','Hello'
|
||||
hbase > get 'magazine','rowkey1','article:content'
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-unload-test.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-unload-test.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -79,7 +79,7 @@ hbase org.apache.hadoop.hbase.mapreduce.CopyTable \
|
||||
# hbase org.apache.hadoop.hbase.mapreduce.CopyTable --help
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-copy-table.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-copy-table.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -27,7 +27,7 @@
|
||||
|
||||
其次 `Phoenix` 的性能表现也非常优异,`Phoenix` 查询引擎会将 SQL 查询转换为一个或多个 HBase Scan,通过并行执行来生成标准的 JDBC 结果集。它通过直接使用 HBase API 以及协处理器和自定义过滤器,可以为小型数据查询提供毫秒级的性能,为千万行数据的查询提供秒级的性能。同时 Phoenix 还拥有二级索引等 HBase 不具备的特性,因为以上的优点,所以 `Phoenix` 成为了 HBase 最优秀的 SQL 中间层。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Phoenix-hadoop.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/Phoenix-hadoop.png"/> </div>
|
||||
|
||||
|
||||
## 二、Phoenix安装
|
||||
@ -85,7 +85,7 @@ start-hbase.sh
|
||||
|
||||
启动后则进入了 Phoenix 交互式 SQL 命令行,可以使用 `!table` 或 `!tables` 查看当前所有表的信息
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/phoenix-shell.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/phoenix-shell.png"/> </div>
|
||||
|
||||
|
||||
## 三、Phoenix 简单使用
|
||||
@ -100,10 +100,10 @@ CREATE TABLE IF NOT EXISTS us_population (
|
||||
CONSTRAINT my_pk PRIMARY KEY (state, city));
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Phoenix-create-table.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/Phoenix-create-table.png"/> </div>
|
||||
新建的表会按照特定的规则转换为 HBase 上的表,关于表的信息,可以通过 Hbase Web UI 进行查看:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-web-ui-phoenix.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-web-ui-phoenix.png"/> </div>
|
||||
### 3.2 插入数据
|
||||
|
||||
Phoenix 中插入数据采用的是 `UPSERT` 而不是 `INSERT`,因为 Phoenix 并没有更新操作,插入相同主键的数据就视为更新,所以 `UPSERT` 就相当于 `UPDATE`+`INSERT`
|
||||
@ -128,14 +128,14 @@ UPSERT INTO us_population VALUES('CA','San Jose',912332);
|
||||
UPSERT INTO us_population VALUES('NY','New York',999999);
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Phoenix-update.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/Phoenix-update.png"/> </div>
|
||||
### 3.4 删除数据
|
||||
|
||||
```sql
|
||||
DELETE FROM us_population WHERE city='Dallas';
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Phoenix-delete.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/Phoenix-delete.png"/> </div>
|
||||
### 3.5 查询数据
|
||||
|
||||
```sql
|
||||
@ -145,7 +145,7 @@ GROUP BY state
|
||||
ORDER BY sum(population) DESC;
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Phoenix-select.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/Phoenix-select.png"/> </div>
|
||||
|
||||
|
||||
### 3.6 退出命令
|
||||
@ -191,7 +191,7 @@ ORDER BY sum(population) DESC;
|
||||
|
||||
如果是普通项目,则可以从 Phoenix 解压目录下找到对应的 JAR 包,然后手动引入:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/phoenix-core-jar.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/phoenix-core-jar.png"/> </div>
|
||||
### 4.2 简单的Java API实例
|
||||
|
||||
```java
|
||||
@ -231,7 +231,7 @@ public class PhoenixJavaApi {
|
||||
|
||||
结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Phoenix-java-api-result.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/Phoenix-java-api-result.png"/> </div>
|
||||
|
||||
|
||||
实际的开发中我们通常都是采用第三方框架来操作数据库,如 `mybatis`,`Hibernate`,`Spring Data` 等。关于 Phoenix 与这些框架的整合步骤参见下一篇文章:[Spring/Spring Boot + Mybatis + Phoenix](https://github.com/heibaiying/BigData-Notes/blob/master/notes/Spring+Mybtais+Phoenix整合.md)
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
HBase 是一个构建在 Hadoop 文件系统之上的面向列的数据库管理系统。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase.jpg"/> </div>
|
||||
|
||||
要想明白为什么产生 HBase,就需要先了解一下 Hadoop 存在的限制?Hadoop 可以通过 HDFS 来存储结构化、半结构甚至非结构化的数据,它是传统数据库的补充,是海量数据存储的最佳方法,它针对大文件的存储,批量访问和流式访问都做了优化,同时也通过多副本解决了容灾问题。
|
||||
|
||||
@ -52,7 +52,7 @@ HBase 是一个面向 ` 列 ` 的数据库管理系统,这里更为确切的
|
||||
+ 该表具有两个列族,分别是 personal 和 office;
|
||||
+ 其中列族 personal 拥有 name、city、phone 三个列,列族 office 拥有 tel、addres 两个列。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HBase_table-iteblog.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/HBase_table-iteblog.png"/> </div>
|
||||
|
||||
> *图片引用自 : HBase 是列式存储数据库吗* *https://www.iteblog.com/archives/2498.html*
|
||||
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
一个典型的 Hbase Table 表如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-webtable.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-webtable.png"/> </div>
|
||||
|
||||
### 1.1 Row Key (行键)
|
||||
|
||||
@ -79,15 +79,15 @@ HBase 中通过 `row key` 和 `column` 确定的为一个存储单元称为 `Cel
|
||||
|
||||
HBase Table 中的所有行按照 `Row Key` 的字典序排列。HBase Tables 通过行键的范围 (row key range) 被水平切分成多个 `Region`, 一个 `Region` 包含了在 start key 和 end key 之间的所有行。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HBaseArchitecture-Blog-Fig2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/HBaseArchitecture-Blog-Fig2.png"/> </div>
|
||||
|
||||
每个表一开始只有一个 `Region`,随着数据不断增加,`Region` 会不断增大,当增大到一个阀值的时候,`Region` 就会等分为两个新的 `Region`。当 Table 中的行不断增多,就会有越来越多的 `Region`。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-region-splite.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/hbase-region-splite.png"/> </div>
|
||||
|
||||
`Region` 是 HBase 中**分布式存储和负载均衡的最小单元**。这意味着不同的 `Region` 可以分布在不同的 `Region Server` 上。但一个 `Region` 是不会拆分到多个 Server 上的。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-region-dis.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/hbase-region-dis.png"/> </div>
|
||||
|
||||
### 2.2 Region Server
|
||||
|
||||
@ -98,13 +98,13 @@ HBase Table 中的所有行按照 `Row Key` 的字典序排列。HBase Tables
|
||||
- **MemStore**:写缓存。它存储尚未写入磁盘的新数据,并会在数据写入磁盘之前对其进行排序。每个 Region 上的每个列族都有一个 MemStore。
|
||||
- **HFile** :将行数据按照 Key\Values 的形式存储在文件系统上。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-Region-Server.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-Region-Server.png"/> </div>
|
||||
|
||||
|
||||
|
||||
Region Server 存取一个子表时,会创建一个 Region 对象,然后对表的每个列族创建一个 `Store` 实例,每个 `Store` 会有 0 个或多个 `StoreFile` 与之对应,每个 `StoreFile` 则对应一个 `HFile`,HFile 就是实际存储在 HDFS 上的文件。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-hadoop.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-hadoop.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -142,7 +142,7 @@ HBase 系统遵循 Master/Salve 架构,由三种不同类型的组件组成:
|
||||
|
||||
2. Region Server 负责切分在运行过程中变得过大的 Region。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HBaseArchitecture-Blog-Fig1.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/HBaseArchitecture-Blog-Fig1.png"/> </div>
|
||||
|
||||
### 3.2 组件间的协作
|
||||
|
||||
@ -154,7 +154,7 @@ HBase 系统遵循 Master/Salve 架构,由三种不同类型的组件组成:
|
||||
|
||||
+ 如果主 Master 未能定时发送心跳,则其持有的 Zookeeper 会话会过期,相应的临时节点也会被删除,这会触发定义在该节点上的 Watcher 事件,使得备用的 Master Servers 得到通知。所有备用的 Master Servers 在接到通知后,会再次去竞争性地创建临时节点,完成主 Master 的选举。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HBaseArchitecture-Blog-Fig5.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/HBaseArchitecture-Blog-Fig5.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -194,7 +194,7 @@ HBase 系统遵循 Master/Salve 架构,由三种不同类型的组件组成:
|
||||
|
||||
注:`META` 表是 HBase 中一张特殊的表,它保存了所有 Region 的位置信息,META 表自己的位置信息则存储在 ZooKeeper 上。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HBaseArchitecture-Blog-Fig7.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/HBaseArchitecture-Blog-Fig7.png"/> </div>
|
||||
|
||||
> 更为详细读取数据流程参考:
|
||||
>
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
Hbase 提供了种类丰富的过滤器(filter)来提高数据处理的效率,用户可以通过内置或自定义的过滤器来对数据进行过滤,所有的过滤器都在服务端生效,即谓词下推(predicate push down)。这样可以保证过滤掉的数据不会被传送到客户端,从而减轻网络传输和客户端处理的压力。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-fliter.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-fliter.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -62,7 +62,7 @@ setFilter(Filter filter)
|
||||
}
|
||||
```
|
||||
|
||||
FilterBase 的所有子类过滤器如下:<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-filterbase-subclass.png"/> </div>
|
||||
FilterBase 的所有子类过滤器如下:<div align="center"> <img src="../pictures/hbase-filterbase-subclass.png"/> </div>
|
||||
|
||||
> 说明:上图基于当前时间点(2019.4)最新的 Hbase-2.1.4 ,下文所有说明均基于此版本。
|
||||
|
||||
@ -117,7 +117,7 @@ public enum CompareOperator {
|
||||
|
||||
所有比较器均继承自 `ByteArrayComparable` 抽象类,常用的有以下几种:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-bytearraycomparable.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-bytearraycomparable.png"/> </div>
|
||||
|
||||
- **BinaryComparator** : 使用 `Bytes.compareTo(byte [],byte [])` 按字典序比较指定的字节数组。
|
||||
- **BinaryPrefixComparator** : 按字典序与指定的字节数组进行比较,但只比较到这个字节数组的长度。
|
||||
@ -137,7 +137,7 @@ public enum CompareOperator {
|
||||
|
||||
比较过滤器共有五个(Hbase 1.x 版本和 2.x 版本相同),见下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-compareFilter.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hbase-compareFilter.png"/> </div>
|
||||
|
||||
+ **RowFilter** :基于行键来过滤数据;
|
||||
+ **FamilyFilterr** :基于列族来过滤数据;
|
||||
|
@ -55,7 +55,7 @@ usage: hive
|
||||
hive -e 'select * from emp';
|
||||
```
|
||||
|
||||
<div align="center"> <img width='700px' src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-e.png"/> </div>
|
||||
<div align="center"> <img width='700px' src="../pictures/hive-e.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -129,7 +129,7 @@ hive > select ${hivevar:j} from emp;
|
||||
|
||||
结果如下:
|
||||
|
||||
<div align="center"> <img width='700px' src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-n-j.png"/> </div>
|
||||
<div align="center"> <img width='700px' src="../pictures/hive-n-j.png"/> </div>
|
||||
|
||||
## 二、Beeline
|
||||
|
||||
|
@ -61,7 +61,7 @@ LOAD DATA LOCAL INPATH "/usr/file/emp30.txt" OVERWRITE INTO TABLE emp_partition
|
||||
|
||||
这时候当你的查询语句的 `where` 包含 `deptno=20`,则就去对应的分区目录下进行查找,而不用扫描全表。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-hadoop-partitation.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-hadoop-partitation.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ LOAD DATA LOCAL INPATH "/usr/file/emp30.txt" OVERWRITE INTO TABLE emp_partition
|
||||
|
||||
当调用 HashMap 的 put() 方法存储数据时,程序会先对 key 值调用 hashCode() 方法计算出 hashcode,然后对数组长度取模计算出 index,最后将数据存储在数组 index 位置的链表上,链表达到一定阈值后会转换为红黑树 (JDK1.8+)。下图为 HashMap 的数据结构图:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HashMap-HashTable.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/HashMap-HashTable.png"/> </div>
|
||||
|
||||
> 图片引用自:[HashMap vs. Hashtable](http://www.itcuties.com/java/hashmap-hashtable/)
|
||||
|
||||
@ -123,13 +123,13 @@ INSERT INTO TABLE emp_bucket SELECT * FROM emp; --这里的 emp 表就是一
|
||||
|
||||
可以从执行日志看到 CTAS 触发 MapReduce 操作,且 Reducer 数量和建表时候指定 bucket 数量一致:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-hadoop-mapreducer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-hadoop-mapreducer.png"/> </div>
|
||||
|
||||
### 1.5 查看分桶文件
|
||||
|
||||
bucket(桶) 本质上就是表目录下的具体文件:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-hadoop-bucket.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-hadoop-bucket.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@
|
||||
show databases;
|
||||
```
|
||||
|
||||
<div align="center"> <img width='700px' src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-show-database.png"/> </div>
|
||||
<div align="center"> <img width='700px' src="../pictures/hive-show-database.png"/> </div>
|
||||
|
||||
### 1.2 使用数据库
|
||||
|
||||
@ -161,7 +161,7 @@ CREATE [TEMPORARY] [EXTERNAL] TABLE [IF NOT EXISTS] [db_name.]table_name --
|
||||
|
||||
使用 `desc format emp_external` 命令可以查看表的详细信息如下:
|
||||
|
||||
<div align="center"> <img width='700px' src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-external-table.png"/> </div>
|
||||
<div align="center"> <img width='700px' src="../pictures/hive-external-table.png"/> </div>
|
||||
|
||||
### 2.4 分区表
|
||||
|
||||
@ -292,7 +292,7 @@ load data local inpath "/usr/file/emp.txt" into table emp;
|
||||
|
||||
加载后可查询表中数据:
|
||||
|
||||
<div align="center"> <img width='700px' src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-select-emp.png"/> </div>
|
||||
<div align="center"> <img width='700px' src="../pictures/hive-select-emp.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -65,7 +65,7 @@ LOAD DATA INPATH "hdfs://hadoop001:8020/mydir/emp.txt" OVERWRITE INTO TABLE emp
|
||||
|
||||
加载后表中数据如下,分区列 deptno 全部赋值成 20:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-emp-ptn.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-emp-ptn.png"/> </div>
|
||||
|
||||
## 二、查询结果插入到表
|
||||
|
||||
@ -140,7 +140,7 @@ CREATE TABLE emp(
|
||||
load data local inpath "/usr/file/emp.txt" into table emp;
|
||||
```
|
||||
完成后 `emp` 表中数据如下:
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-emp.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-emp.png"/> </div>
|
||||
|
||||
2. 为清晰演示,先清空 `emp_ptn` 表中加载的数据:
|
||||
|
||||
@ -157,7 +157,7 @@ SELECT empno,ename,job,mgr,hiredate,sal,comm FROM emp WHERE deptno=20;
|
||||
|
||||
完成后 `emp_ptn` 表中数据如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-emp-deptno-20.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-emp-deptno-20.png"/> </div>
|
||||
|
||||
4. 接着演示动态分区:
|
||||
|
||||
@ -172,7 +172,7 @@ SELECT empno,ename,job,mgr,hiredate,sal,comm,deptno FROM emp WHERE deptno=30;
|
||||
|
||||
完成后 `emp_ptn` 表中数据如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-emp-deptno-20-30.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-emp-deptno-20-30.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -261,7 +261,7 @@ INSERT INTO TABLE emp_ts VALUES (1,"ming"),(2,"hong");
|
||||
|
||||
插入数据依靠的是 MapReduce 作业,执行成功后数据如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-emp-ts.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-emp-ts.png"/> </div>
|
||||
|
||||
**4. 测试更新和删除**
|
||||
|
||||
@ -275,7 +275,7 @@ DELETE FROM emp_ts WHERE empno=2;
|
||||
|
||||
更新和删除数据依靠的也是 MapReduce 作业,执行成功后数据如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-emp-ts-2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-emp-ts-2.png"/> </div>
|
||||
|
||||
|
||||
## 五、查询结果写出到文件系统
|
||||
@ -317,7 +317,7 @@ SELECT * FROM emp_ptn;
|
||||
|
||||
导出结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-ouput.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-ouput.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -249,7 +249,7 @@ Hive 支持内连接,外连接,左外连接,右外连接,笛卡尔连接
|
||||
|
||||
需要特别强调:JOIN 语句的关联条件必须用 ON 指定,不能用 WHERE 指定,否则就会先做笛卡尔积,再过滤,这会导致你得不到预期的结果 (下面的演示会有说明)。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sql-join.jpg"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/sql-join.jpg"/> </div>
|
||||
|
||||
### 3.1 INNER JOIN
|
||||
|
||||
@ -286,7 +286,7 @@ ON e.deptno = d.deptno;
|
||||
|
||||
执行右连接后,由于 40 号部门下没有任何员工,所以此时员工信息为 NULL。这个查询可以很好的复述上面提到的——JOIN 语句的关联条件必须用 ON 指定,不能用 WHERE 指定。你可以把 ON 改成 WHERE,你会发现无论如何都查不出 40 号部门这条数据,因为笛卡尔运算不会有 (NULL, 40) 这种情况。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-right-join.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/hive-right-join.png"/> </div>
|
||||
### 3.4 FULL OUTER JOIN
|
||||
|
||||
```sql
|
||||
|
@ -29,7 +29,7 @@ Hive 是一个构建在 Hadoop 之上的数据仓库,它可以将结构化的
|
||||
|
||||
## 二、Hive的体系架构
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive体系架构.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/hive体系架构.png"/> </div>
|
||||
|
||||
### 2.1 command-line shell & thrift/jdbc
|
||||
|
||||
@ -84,7 +84,7 @@ Hive 表中的列支持以下基本数据类型:
|
||||
|
||||
Hive 中基本数据类型遵循以下的层次结构,按照这个层次结构,子类型到祖先类型允许隐式转换。例如 INT 类型的数据允许隐式转换为 BIGINT 类型。额外注意的是:按照类型层次结构允许将 STRING 类型隐式转换为 DOUBLE 类型。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-data-type.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-data-type.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -41,7 +41,7 @@ CREATE VIEW [IF NOT EXISTS] [db_name.]view_name -- 视图名称
|
||||
CREATE VIEW IF NOT EXISTS custom_view AS SELECT empno, empno+deptno , 1+2 FROM emp;
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-1-2-view.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-1-2-view.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -95,7 +95,7 @@ table_properties:
|
||||
ALTER VIEW custom_view SET TBLPROPERTIES ('create'='heibaiying','date'='2019-05-05');
|
||||
```
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-view-properties.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/hive-view-properties.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -189,7 +189,7 @@ alter index emp_index on emp rebuild;
|
||||
|
||||
Hive 会启动 MapReduce 作业去建立索引,建立好后查看索引表数据如下。三个表字段分别代表:索引列的值、该值对应的 HDFS 文件路径、该值在文件中的偏移量。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-index-table.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/hive-index-table.png"/> </div>
|
||||
|
||||
### 3.3 自动使用索引
|
||||
|
||||
@ -207,7 +207,7 @@ SET hive.optimize.index.filter.compact.minsize=0;
|
||||
SHOW INDEX ON emp;
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-index-show.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/hive-index-show.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -21,11 +21,11 @@
|
||||
|
||||
在 Kafka 中,消费者通常是消费者群组的一部分,多个消费者群组共同读取同一个主题时,彼此之间互不影响。Kafka 之所以要引入消费者群组这个概念是因为 Kafka 消费者经常会做一些高延迟的操作,比如把数据写到数据库或 HDFS ,或者进行耗时的计算,在这些情况下,单个消费者无法跟上数据生成的速度。此时可以增加更多的消费者,让它们分担负载,分别处理部分分区的消息,这就是 Kafka 实现横向伸缩的主要手段。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-consumer01.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-consumer01.png"/> </div>
|
||||
|
||||
需要注意的是:同一个分区只能被同一个消费者群组里面的一个消费者读取,不可能存在同一个分区被同一个消费者群里多个消费者共同读取的情况,如图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-consumer02.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-consumer02.png"/> </div>
|
||||
|
||||
可以看到即便消费者 Consumer5 空闲了,但是也不会去读取任何一个分区的数据,这同时也提醒我们在使用时应该合理设置消费者的数量,以免造成闲置和额外开销。
|
||||
|
||||
|
@ -36,7 +36,7 @@ Kafka 使用 Zookeeper 来维护集群成员 (brokers) 的信息。每个 broker
|
||||
|
||||
Kafka 的主题被分为多个分区 ,分区是 Kafka 最基本的存储单位。每个分区可以有多个副本 (可以在创建主题时使用 ` replication-factor` 参数进行指定)。其中一个副本是首领副本 (Leader replica),所有的事件都直接发送给首领副本;其他副本是跟随者副本 (Follower replica),需要通过复制来保持与首领副本数据一致,当首领副本不可用时,其中一个跟随者副本将成为新首领。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-cluster.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-cluster.png"/> </div>
|
||||
|
||||
### 2.2 ISR机制
|
||||
|
||||
@ -49,7 +49,7 @@ Kafka 的主题被分为多个分区 ,分区是 Kafka 最基本的存储单位
|
||||
|
||||
这里给出一个主题创建的示例:使用 `--replication-factor` 指定副本系数为 3,创建成功后使用 `--describe ` 命令可以看到分区 0 的有 0,1,2 三个副本,且三个副本都在 ISR 列表中,其中 1 为首领副本。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-分区副本.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-分区副本.png"/> </div>
|
||||
|
||||
### 2.3 不完全的首领选举
|
||||
|
||||
@ -77,13 +77,13 @@ Kafka 在生产者上有一个可选的参数 ack,该参数指定了必须要
|
||||
|
||||
如果在定时请求的时间间隔内发生的分区副本的选举,则意味着原来缓存的信息可能已经过时了,此时还有可能会收到 `Not a Leader for Partition` 的错误响应,这种情况下客户端会再次求发出元数据请求,然后刷新本地缓存,之后再去正确的 broker 上执行对应的操作,过程如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-元数据请求.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-元数据请求.png"/> </div>
|
||||
|
||||
### 3.2 数据可见性
|
||||
|
||||
需要注意的是,并不是所有保存在分区首领上的数据都可以被客户端读取到,为了保证数据一致性,只有被所有同步副本 (ISR 中所有副本) 都保存了的数据才能被客户端读取到。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-数据可见性.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-数据可见性.png"/> </div>
|
||||
|
||||
### 3.3 零拷贝
|
||||
|
||||
@ -100,13 +100,13 @@ Socket.send(buffer)
|
||||
|
||||
这一过程实际上发生了四次数据拷贝。首先通过系统调用将文件数据读入到内核态 Buffer(DMA 拷贝),然后应用程序将内存态 Buffer 数据读入到用户态 Buffer(CPU 拷贝),接着用户程序通过 Socket 发送数据时将用户态 Buffer 数据拷贝到内核态 Buffer(CPU 拷贝),最后通过 DMA 拷贝将数据拷贝到 NIC Buffer。同时,还伴随着四次上下文切换,如下图所示:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-BIO.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-BIO.png"/> </div>
|
||||
|
||||
#### sendfile和transferTo实现零拷贝
|
||||
|
||||
Linux 2.4+ 内核通过 `sendfile` 系统调用,提供了零拷贝。数据通过 DMA 拷贝到内核态 Buffer 后,直接通过 DMA 拷贝到 NIC Buffer,无需 CPU 拷贝。这也是零拷贝这一说法的来源。除了减少数据拷贝外,因为整个读文件到网络发送由一个 `sendfile` 调用完成,整个过程只有两次上下文切换,因此大大提高了性能。零拷贝过程如下图所示:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-零拷贝.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-零拷贝.png"/> </div>
|
||||
|
||||
从具体实现来看,Kafka 的数据传输通过 TransportLayer 来完成,其子类 `PlaintextTransportLayer` 的 `transferFrom` 方法通过调用 Java NIO 中 FileChannel 的 `transferTo` 方法实现零拷贝,如下所示:
|
||||
|
||||
@ -151,7 +151,7 @@ Exception: Replication factor: 3 larger than available brokers: 1.
|
||||
|
||||
通常保存在磁盘上的数据格式与生产者发送过来消息格式是一样的。 如果生产者发送的是压缩过的消息,那么同一个批次的消息会被压缩在一起,被当作“包装消息”进行发送 (格式如下所示) ,然后保存到磁盘上。之后消费者读取后再自己解压这个包装消息,获取每条消息的具体信息。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-compress-message.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-compress-message.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
+ 接下来,数据被传给分区器。如果之前已经在 ProducerRecord 对象里指定了分区,那么分区器就不会再做任何事情。如果没有指定分区 ,那么分区器会根据 ProducerRecord 对象的键来选择一个分区,紧接着,这条记录被添加到一个记录批次里,这个批次里的所有消息会被发送到相同的主题和分区上。有一个独立的线程负责把这些记录批次发送到相应的 broker 上。
|
||||
+ 服务器在收到这些消息时会返回一个响应。如果消息成功写入 Kafka,就返回一个 RecordMetaData 对象,它包含了主题和分区信息,以及记录在分区里的偏移量。如果写入失败,则会返回一个错误。生产者在收到错误之后会尝试重新发送消息,如果达到指定的重试次数后还没有成功,则直接抛出异常,不再重试。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-send-messgaes.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-send-messgaes.png"/> </div>
|
||||
|
||||
## 二、创建生产者
|
||||
|
||||
@ -118,7 +118,7 @@ bin/kafka-topics.sh --create \
|
||||
|
||||
此时可以看到消费者控制台,输出如下,这里 `kafka-console-consumer` 只会打印出值信息,不会打印出键信息。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-simple-producer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-simple-producer.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -32,7 +32,7 @@ Kafka 的消息通过 Topics(主题) 进行分类,一个主题可以被分为
|
||||
|
||||
由于一个 Topic 包含多个分区,因此无法在整个 Topic 范围内保证消息的顺序性,但可以保证消息在单个分区内的顺序性。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-topic.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-topic.png"/> </div>
|
||||
|
||||
### 2.3 Producers And Consumers
|
||||
|
||||
@ -44,11 +44,11 @@ Kafka 的消息通过 Topics(主题) 进行分类,一个主题可以被分为
|
||||
|
||||
消费者是消费者群组的一部分,消费者负责消费消息。消费者可以订阅一个或者多个主题,并按照消息生成的顺序来读取它们。消费者通过检查消息的偏移量 (offset) 来区分读取过的消息。偏移量是一个不断递增的数值,在创建消息时,Kafka 会把它添加到其中,在给定的分区里,每个消息的偏移量都是唯一的。消费者把每个分区最后读取的偏移量保存在 Zookeeper 或 Kafka 上,如果消费者关闭或者重启,它还可以重新获取该偏移量,以保证读取状态不会丢失。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-producer-consumer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-producer-consumer.png"/> </div>
|
||||
|
||||
一个分区只能被同一个消费者群组里面的一个消费者读取,但可以被不同消费者群组中所组成的多个消费者共同读取。多个消费者群组中消费者共同读取同一个主题时,彼此之间互不影响。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka消费者.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka消费者.png"/> </div>
|
||||
|
||||
### 2.4 Brokers And Clusters
|
||||
|
||||
@ -58,7 +58,7 @@ Broker 是集群 (Cluster) 的组成部分。每一个集群都会选举出一
|
||||
|
||||
在集群中,一个分区 (Partition) 从属一个 Broker,该 Broker 被称为分区的首领 (Leader)。一个分区可以分配给多个 Brokers,这个时候会发生分区复制。这种复制机制为分区提供了消息冗余,如果有一个 Broker 失效,其他 Broker 可以接管领导权。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-cluster.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/kafka-cluster.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -205,7 +205,7 @@ res15: Int = 3
|
||||
|
||||
Int 类中包含了多个重载的 `+` 方法,用于分别接收不同类型的参数。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-int+.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-int+.png"/> </div>
|
||||
|
||||
### 3.2 逻辑运算符
|
||||
|
||||
@ -234,7 +234,7 @@ res10: Int = 1
|
||||
|
||||
操作符的优先级如下:优先级由上至下,逐级递减。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-操作符优先级.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-操作符优先级.png"/> </div>
|
||||
|
||||
在表格中某个字符的优先级越高,那么以这个字符打头的方法就拥有更高的优先级。如 `+` 的优先级大于 `<`,也就意味则 `+` 的优先级大于以 `<` 开头的 `<<`,所以 `2<<2+2` , 实际上等价于 `2<<(2+2)` :
|
||||
|
||||
|
@ -61,7 +61,7 @@ Scala 的运行依赖于 JDK,Scala 2.12.x 需要 JDK 1.8+。
|
||||
|
||||
IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。打开 IDEA,依次点击 **File** => **settings**=> **plugins** 选项卡,搜索 Scala 插件 (如下图)。找到插件后进行安装,并重启 IDEA 使得安装生效。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-plugin.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/idea-scala-plugin.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -69,7 +69,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
在 IDEA 中依次点击 **File** => **New** => **Project** 选项卡,然后选择创建 `Scala—IDEA` 工程:
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-newproject-scala.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/idea-newproject-scala.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -79,7 +79,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
此时看到 `Scala SDK` 为空,依次点击 `Create` => `Download` ,选择所需的版本后,点击 `OK` 按钮进行下载,下载完成点击 `Finish` 进入工程。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-select.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/idea-scala-select.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -89,13 +89,13 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
这里我的系统是 Windows,下载 msi 版本的安装包后,一直点击下一步进行安装,安装完成后会自动配置好环境变量。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-other-resources.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/scala-other-resources.png"/> </div>
|
||||
|
||||
|
||||
|
||||
由于安装时已经自动配置好环境变量,所以 IDEA 会自动选择对应版本的 SDK。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-2.1.8.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/idea-scala-2.1.8.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -103,7 +103,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
在工程 `src` 目录上右击 **New** => **Scala class** 创建 `Hello.scala`。输入代码如下,完成后点击运行按钮,成功运行则代表搭建成功。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-hello-world.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/scala-hello-world.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -113,7 +113,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
在日常的开发中,由于对应软件(如 Spark)的版本切换,可能导致需要切换 Scala 的版本,则可以在 `Project Structures` 中的 `Global Libraries` 选项卡中进行切换。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-change.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/idea-scala-change.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -123,7 +123,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
采用 `msi` 方式安装,程序会自动配置好环境变量。此时可以直接使用命令行工具:
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-shell.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../pictures/scala-shell.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -122,7 +122,7 @@ trait Ordered[A] extends Any with java.lang.Comparable[A] {
|
||||
@inline implicit def intWrapper(x: Int) = new runtime.RichInt(x)
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-richInt.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-richInt.png"/> </div>
|
||||
|
||||
要想解决传入数值无法进行比较的问题,可以使用视图界定。语法为 `T <% U`,代表 T 能够通过隐式转换转为 U,即允许 Int 型参数在无法进行比较的时候转换为 RichInt 类型。示例如下:
|
||||
|
||||
@ -299,7 +299,7 @@ object ScalaApp extends App {
|
||||
|
||||
为什么 Java 中要同时给出这两个比较接口,这是因为你要比较的对象不一定实现了 Comparable 接口,而你又想对其进行比较,这时候当然你可以修改代码实现 Comparable,但是如果这个类你无法修改 (如源码中的类),这时候就可以使用外置的比较器。同样的问题在 Scala 中当然也会出现,所以 Scala 分别使用了 Ordering 和 Ordered 来继承它们。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-ordered-ordering.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-ordered-ordering.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -28,7 +28,7 @@ Scala 中继承关系如下图:
|
||||
+ Null 是所有引用类型的子类型,唯一实例是 null,可以将 null 赋值给除了值类型外的所有类型的变量;
|
||||
+ Nothing 是所有类型的子类型。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala继承层次.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala继承层次.png"/> </div>
|
||||
|
||||
### 1.2 extends & override
|
||||
|
||||
@ -312,7 +312,7 @@ class InfoLogger extends Logger {
|
||||
|
||||
Scala 支持在类定义的时混入 ` 父类 trait`,而在类实例化为具体对象的时候指明其实际使用的 ` 子类 trait`。示例如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala带有特质的对象.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala带有特质的对象.png"/> </div>
|
||||
|
||||
trait Logger:
|
||||
|
||||
|
@ -327,7 +327,7 @@ object Pair extends App {
|
||||
|
||||
为什么要这么麻烦执行隐式转换,原因是 Scala 中的 Int 类型并不能直接进行比较,因为其没有实现 `Ordered` 特质,真正实现 `Ordered` 特质的是 `RichInt`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-richInt.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-richInt.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -44,19 +44,19 @@ res0: scala.collection.immutable.Set[Int] = Set(5, 1, 2, 3, 4)
|
||||
|
||||
scala.collection 包中所有集合如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-collection.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-collection.png"/> </div>
|
||||
|
||||
### 3.2 scala.collection.mutable
|
||||
|
||||
scala.collection.mutable 包中所有集合如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-collection-m.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-collection-m.png"/> </div>
|
||||
|
||||
### 3.2 scala.collection.immutable
|
||||
|
||||
scala.collection.immutable 包中所有集合如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-collection-imm.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-collection-imm.png"/> </div>
|
||||
|
||||
## 三、Trait Traversable
|
||||
|
||||
|
@ -27,7 +27,7 @@ Spark SQL 是 Spark 中的一个子模块,主要用于操作结构化数据。
|
||||
+ 支持优化器,列式存储和代码生成等特性;
|
||||
+ 支持扩展并能保证容错。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sql-hive-arch.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sql-hive-arch.png"/> </div>
|
||||
|
||||
## 二、DataFrame & DataSet
|
||||
|
||||
@ -46,7 +46,7 @@ Spark SQL 是 Spark 中的一个子模块,主要用于操作结构化数据。
|
||||
|
||||
DataFrame 和 RDDs 最主要的区别在于一个面向的是结构化数据,一个面向的是非结构化数据,它们内部的数据结构如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-dataFrame+RDDs.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-dataFrame+RDDs.png"/> </div>
|
||||
|
||||
DataFrame 内部的有明确 Scheme 结构,即列名、列字段类型都是已知的,这带来的好处是可以减少数据读取以及更好地优化执行计划,从而保证查询效率。
|
||||
|
||||
@ -64,7 +64,7 @@ Dataset 也是分布式的数据集合,在 Spark 1.6 版本被引入,它集
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-unifed.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-unifed.png"/> </div>
|
||||
|
||||
### 2.4 静态类型与运行时类型安全
|
||||
|
||||
@ -76,11 +76,11 @@ Dataset 也是分布式的数据集合,在 Spark 1.6 版本被引入,它集
|
||||
|
||||
以上这些最终都被解释成关于类型安全图谱,对应开发中的语法和分析错误。在图谱中,Dataset 最严格,但对于开发者来说效率最高。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-运行安全.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-运行安全.png"/> </div>
|
||||
|
||||
上面的描述可能并没有那么直观,下面的给出一个 IDEA 中代码编译的示例:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-运行时类型安全.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-运行时类型安全.png"/> </div>
|
||||
|
||||
这里一个可能的疑惑是 DataFrame 明明是有确定的 Scheme 结构 (即列名、列字段类型都是已知的),但是为什么还是无法对列名进行推断和错误判断,这是因为 DataFrame 是 Untyped 的。
|
||||
|
||||
@ -106,7 +106,7 @@ val dataSet: Dataset[Person] = spark.read.json("people.json").as[Person]
|
||||
+ 相比于 DataFrame 而言,DataSet 是强类型的 (Typed),有着更为严格的静态类型检查;
|
||||
+ DataSets、DataFrames、SQL 的底层都依赖了 RDDs API,并对外提供结构化的访问接口。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-structure-api.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-structure-api.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -123,7 +123,7 @@ DataFrame、DataSet 和 Spark SQL 的实际执行流程都是相同的:
|
||||
|
||||
执行的第一个阶段是将用户代码转换成一个逻辑计划。它首先将用户代码转换成 `unresolved logical plan`(未解决的逻辑计划),之所以这个计划是未解决的,是因为尽管您的代码在语法上是正确的,但是它引用的表或列可能不存在。 Spark 使用 `analyzer`(分析器) 基于 `catalog`(存储的所有表和 `DataFrames` 的信息) 进行解析。解析失败则拒绝执行,解析成功则将结果传给 `Catalyst` 优化器 (`Catalyst Optimizer`),优化器是一组规则的集合,用于优化逻辑计划,通过谓词下推等方式进行优化,最终输出优化后的逻辑执行计划。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-Logical-Planning.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-Logical-Planning.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -131,7 +131,7 @@ DataFrame、DataSet 和 Spark SQL 的实际执行流程都是相同的:
|
||||
|
||||
得到优化后的逻辑计划后,Spark 就开始了物理计划过程。 它通过生成不同的物理执行策略,并通过成本模型来比较它们,从而选择一个最优的物理计划在集群上面执行的。物理规划的输出结果是一系列的 RDDs 和转换关系 (transformations)。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-Physical-Planning.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-Physical-Planning.png"/> </div>
|
||||
|
||||
### 4.3 执行
|
||||
|
||||
|
@ -350,7 +350,7 @@ jdbcDf.rdd.mapPartitionsWithIndex((index, iterator) => {
|
||||
|
||||
执行结果如下:`help_keyword` 这张表只有 600 条左右的数据,本来数据应该均匀分布在 10 个分区,但是 0 分区里面却有 319 条数据,这是因为设置了下限,所有小于 300 的数据都会被限制在第一个分区,即 0 分区。同理所有大于 500 的数据被分配在 9 分区,即最后一个分区。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-mysql-分区上下限.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-mysql-分区上下限.png"/> </div>
|
||||
|
||||
### 6.2 写入数据
|
||||
|
||||
@ -405,7 +405,7 @@ df.write.mode("overwrite").partitionBy("deptno").save("/tmp/spark/partitions")
|
||||
|
||||
输出结果如下:可以看到输出被按照部门编号分为三个子目录,子目录中才是对应的输出文件。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-分区.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-分区.png"/> </div>
|
||||
|
||||
### 8.3 分桶写入
|
||||
|
||||
|
@ -246,7 +246,7 @@ object SparkSqlApp {
|
||||
|
||||
自定义聚合函数需要实现的方法比较多,这里以绘图的方式来演示其执行流程,以及每个方法的作用:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-sql-自定义函数.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-sql-自定义函数.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -68,7 +68,7 @@ Spark 中支持多种连接类型:
|
||||
|
||||
其中内,外连接,笛卡尔积均与普通关系型数据库中的相同,如下图所示:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sql-join.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/sql-join.jpg"/> </div>
|
||||
|
||||
这里解释一下左半连接和左反连接,这两个连接等价于关系型数据库中的 `IN` 和 `NOT IN` 字句:
|
||||
|
||||
@ -154,7 +154,7 @@ spark.sql("SELECT * FROM emp NATURAL JOIN dept").show()
|
||||
spark.sql("SELECT * FROM emp JOIN dept ON emp.deptno = dept.deptno").show()
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-sql-NATURAL-JOIN.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-sql-NATURAL-JOIN.png"/> </div>
|
||||
|
||||
由于自然连接常常会产生不可预期的结果,所以并不推荐使用。
|
||||
|
||||
@ -164,13 +164,13 @@ spark.sql("SELECT * FROM emp JOIN dept ON emp.deptno = dept.deptno").show()
|
||||
|
||||
在对大表与大表之间进行连接操作时,通常都会触发 `Shuffle Join`,两表的所有分区节点会进行 `All-to-All` 的通讯,这种查询通常比较昂贵,会对网络 IO 会造成比较大的负担。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-Big-table–to–big-table.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-Big-table–to–big-table.png"/> </div>
|
||||
|
||||
|
||||
|
||||
而对于大表和小表的连接操作,Spark 会在一定程度上进行优化,如果小表的数据量小于 Worker Node 的内存空间,Spark 会考虑将小表的数据广播到每一个 Worker Node,在每个工作节点内部执行连接计算,这可以降低网络的 IO,但会加大每个 Worker Node 的 CPU 负担。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-Big-table–to–small-table.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-Big-table–to–small-table.png"/> </div>
|
||||
|
||||
是否采用广播方式进行 `Join` 取决于程序内部对小表的判断,如果想明确使用广播方式进行 `Join`,则可以在 DataFrame API 中使用 `broadcast` 方法指定需要广播的小表:
|
||||
|
||||
|
@ -85,7 +85,7 @@ val dataRDD = sc.parallelize(data,2)
|
||||
|
||||
执行结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-分区数.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/scala-分区数.png"/> </div>
|
||||
|
||||
### 2.2 引用外部存储系统中的数据集
|
||||
|
||||
@ -176,7 +176,7 @@ Spark 会自动监视每个节点上的缓存使用情况,并按照最近最
|
||||
|
||||
在 Spark 中,一个任务对应一个分区,通常不会跨分区操作数据。但如果遇到 `reduceByKey` 等操作,Spark 必须从所有分区读取数据,并查找所有键的所有值,然后汇总在一起以计算每个键的最终结果 ,这称为 `Shuffle`。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-reducebykey.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-reducebykey.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -203,7 +203,7 @@ RDD 和它的父 RDD(s) 之间的依赖关系分为两种不同的类型:
|
||||
|
||||
如下图,每一个方框表示一个 RDD,带有颜色的矩形表示分区:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-窄依赖和宽依赖.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-窄依赖和宽依赖.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -221,7 +221,7 @@ RDD(s) 及其之间的依赖关系组成了 DAG(有向无环图),DAG 定义了
|
||||
+ 对于窄依赖,由于分区的依赖关系是确定的,其转换操作可以在同一个线程执行,所以可以划分到同一个执行阶段;
|
||||
+ 对于宽依赖,由于 Shuffle 的存在,只能在父 RDD(s) 被 Shuffle 处理完成后,才能开始接下来的计算,因此遇到宽依赖就需要重新划分阶段。
|
||||
|
||||
<div align="center"> <img width="600px" height="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-DAG.png"/> </div>
|
||||
<div align="center"> <img width="600px" height="600px" src="../pictures/spark-DAG.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
在流处理之前,数据通常存储在数据库,文件系统或其他形式的存储系统中。应用程序根据需要查询数据或计算数据。这就是传统的静态数据处理架构。Hadoop 采用 HDFS 进行数据存储,采用 MapReduce 进行数据查询或分析,这就是典型的静态数据处理架构。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/01_data_at_rest_infrastructure.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/01_data_at_rest_infrastructure.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@
|
||||
|
||||
接收和发送数据流并执行应用程序或分析逻辑的系统称为**流处理器**。流处理器的基本职责是确保数据有效流动,同时具备可扩展性和容错能力,Storm 和 Flink 就是其代表性的实现。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/02_stream_processing_infrastructure.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/02_stream_processing_infrastructure.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -55,13 +55,13 @@ Spark Streaming 是 Spark 的一个子模块,用于快速构建可扩展,高
|
||||
+ 能够和 Spark 其他模块无缝集成,将流处理与批处理完美结合;
|
||||
+ Spark Streaming 可以从 HDFS,Flume,Kafka,Twitter 和 ZeroMQ 读取数据,也支持自定义数据源。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-arch.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-streaming-arch.png"/> </div>
|
||||
|
||||
### 2.2 DStream
|
||||
|
||||
Spark Streaming 提供称为离散流 (DStream) 的高级抽象,用于表示连续的数据流。 DStream 可以从来自 Kafka,Flume 和 Kinesis 等数据源的输入数据流创建,也可以由其他 DStream 转化而来。**在内部,DStream 表示为一系列 RDD**。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-flow.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-streaming-flow.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -62,7 +62,7 @@ storm storm flink azkaban
|
||||
|
||||
此时控制台输出如下,可以看到已经接收到数据并按行进行了词频统计。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-word-count-v1.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-streaming-word-count-v1.png"/> </div>
|
||||
<br/>
|
||||
|
||||
下面针对示例代码进行讲解:
|
||||
@ -105,7 +105,7 @@ streamingContext.fileStream[KeyClass, ValueClass, InputFormatClass](dataDirector
|
||||
|
||||
DStream 是 Spark Streaming 提供的基本抽象。它表示连续的数据流。在内部,DStream 由一系列连续的 RDD 表示。所以从本质上而言,应用于 DStream 的任何操作都会转换为底层 RDD 上的操作。例如,在示例代码中 flatMap 算子的操作实际上是作用在每个 RDDs 上 (如下图)。因为这个原因,所以 DStream 能够支持 RDD 大部分的*transformation*算子。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-dstream-ops.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-streaming-dstream-ops.png"/> </div>
|
||||
|
||||
### 2.2 updateStateByKey
|
||||
|
||||
@ -167,7 +167,7 @@ storm storm flink azkaban
|
||||
|
||||
此时控制台输出如下,所有输入都被进行了词频累计:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-word-count-v2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-streaming-word-count-v2.png"/> </div>
|
||||
同时在输出日志中还可以看到检查点操作的相关信息:
|
||||
|
||||
```shell
|
||||
@ -323,7 +323,7 @@ storm storm flink azkaban
|
||||
|
||||
使用 Redis Manager 查看写入结果 (如下图),可以看到与使用 `updateStateByKey` 算子得到的计算结果相同。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-word-count-v3.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-streaming-word-count-v3.png"/> </div>
|
||||
<br/>
|
||||
|
||||
> 本片文章所有源码见本仓库:[spark-streaming-basis](https://github.com/heibaiying/BigData-Notes/tree/master/code/spark/spark-streaming-basis)
|
||||
|
@ -206,7 +206,7 @@ object PushBasedWordCount {
|
||||
|
||||
使用 `mvn clean package` 命令打包后会生产以下两个 Jar 包,提交 ` 非 original` 开头的 Jar 即可。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-flume-jar.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-streaming-flume-jar.png"/> </div>
|
||||
|
||||
### 2.5 启动服务和提交作业
|
||||
|
||||
@ -232,11 +232,11 @@ spark-submit \
|
||||
|
||||
这里使用 `echo` 命令模拟日志产生的场景,往日志文件中追加数据,然后查看程序的输出:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-flume-input.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-flume-input.png"/> </div>
|
||||
|
||||
Spark Streaming 程序成功接收到数据并打印输出:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-flume-console.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-flume-console.png"/> </div>
|
||||
|
||||
### 2.7 注意事项
|
||||
|
||||
@ -244,7 +244,7 @@ Spark Streaming 程序成功接收到数据并打印输出:
|
||||
|
||||
这里需要注意的,不论你先启动 Spark 程序还是 Flume 程序,由于两者的启动都需要一定的时间,此时先启动的程序会短暂地抛出端口拒绝连接的异常,此时不需要进行任何操作,等待两个程序都启动完成即可。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flume-retry.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/flume-retry.png"/> </div>
|
||||
|
||||
#### 2. 版本一致
|
||||
|
||||
|
@ -310,7 +310,7 @@ bin/kafka-console-producer.sh --broker-list hadoop001:9092 --topic spark-streami
|
||||
|
||||
从控制台输出中可以看到数据流已经被成功接收,由于采用 `kafka-console-producer.sh` 发送的数据默认是没有 key 的,所以 key 值为 null。同时从输出中也可以看到在程序中指定的 `groupId` 和程序自动分配的 `clientId`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-straming-kafka-console.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-straming-kafka-console.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -25,7 +25,7 @@ import spark.implicits._
|
||||
|
||||
可以使用 `spark-shell` 进行测试,需要注意的是 `spark-shell` 启动后会自动创建一个名为 `spark` 的 `SparkSession`,在命令行中可以直接引用即可:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-sql-shell.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-sql-shell.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
|
@ -301,7 +301,7 @@ sc.parallelize(list,numSlices = 2).aggregateByKey(zeroValue = 0,numPartitions =
|
||||
|
||||
这里使用了 `numSlices = 2` 指定 aggregateByKey 父操作 parallelize 的分区数量为 2,其执行流程如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-aggregateByKey.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-aggregateByKey.png"/> </div>
|
||||
|
||||
基于同样的执行流程,如果 `numSlices = 1`,则意味着只有输入一个分区,则其最后一步 combOp 相当于是无效的,执行结果为:
|
||||
|
||||
@ -328,7 +328,7 @@ sc.parallelize(list,numSlices = 6).aggregateByKey(zeroValue = 0,numPartitions =
|
||||
).getNumPartitions
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-getpartnum.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-getpartnum.png"/> </div>
|
||||
|
||||
## 二、Action
|
||||
|
||||
|
@ -28,7 +28,7 @@ Apache Spark 具有以下特点:
|
||||
+ 丰富的部署模式:支持本地模式和自带的集群模式,也支持在 Hadoop,Mesos,Kubernetes 上运行;
|
||||
+ 多数据源支持:支持访问 HDFS,Alluxio,Cassandra,HBase,Hive 以及数百个其他数据源中的数据。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/future-of-spark.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/future-of-spark.png"/> </div>
|
||||
|
||||
## 三、集群架构
|
||||
|
||||
@ -41,7 +41,7 @@ Apache Spark 具有以下特点:
|
||||
| Executor | 位于工作节点上的应用进程,负责执行计算任务并且将输出数据保存到内存或者磁盘中 |
|
||||
| Task | 被发送到 Executor 中的工作单元 |
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群模式.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-集群模式.png"/> </div>
|
||||
|
||||
**执行过程**:
|
||||
|
||||
@ -53,7 +53,7 @@ Apache Spark 具有以下特点:
|
||||
|
||||
Spark 基于 Spark Core 扩展了四个核心组件,分别用于满足不同领域的计算需求。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-stack.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-stack.png"/> </div>
|
||||
|
||||
### 3.1 Spark SQL
|
||||
|
||||
@ -69,11 +69,11 @@ Spark SQL 主要用于结构化数据的处理。其具有以下特点:
|
||||
|
||||
Spark Streaming 主要用于快速构建可扩展,高吞吐量,高容错的流处理程序。支持从 HDFS,Flume,Kafka,Twitter 和 ZeroMQ 读取数据,并进行处理。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-arch.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-streaming-arch.png"/> </div>
|
||||
|
||||
Spark Streaming 的本质是微批处理,它将数据流进行极小粒度的拆分,拆分为多个批处理,从而达到接近于流处理的效果。
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-streaming-flow.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../pictures/spark-streaming-flow.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -28,7 +28,7 @@ sc.parallelize(data).foreach(x => counter += x)
|
||||
|
||||
counter 最后的结果是 0,导致这个问题的主要原因是闭包。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-累加器1.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-累加器1.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -59,13 +59,13 @@ val addMore = (x: Int) => x + more
|
||||
累加器的原理实际上很简单:就是将每个副本变量的最终值传回 Driver,由 Driver 聚合后得到最终值,并更新原始变量。
|
||||
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群模式.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-集群模式.png"/> </div>
|
||||
|
||||
### 2.2 使用累加器
|
||||
|
||||
`SparkContext` 中定义了所有创建累加器的方法,需要注意的是:被中横线划掉的累加器方法在 Spark 2.0.0 之后被标识为废弃。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-累加器方法.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-累加器方法.png"/> </div>
|
||||
|
||||
使用示例和执行结果分别如下:
|
||||
|
||||
@ -78,7 +78,7 @@ sc.parallelize(data).foreach(x => accum.add(x))
|
||||
accum.value
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-累加器2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-累加器2.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -67,7 +67,7 @@ spark-submit \
|
||||
|
||||
`spark-examples_2.11-2.4.0.jar` 是 Spark 提供的测试用例包,`SparkPi` 用于计算 Pi 值,执行结果如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-pi.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-pi.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -82,7 +82,7 @@ Standalone 是 Spark 提供的一种内置的集群模式,采用内置的资
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群模式.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-集群模式.png"/> </div>
|
||||
|
||||
### 3.1 环境配置
|
||||
|
||||
@ -131,7 +131,7 @@ hadoop002
|
||||
|
||||
访问 8080 端口,查看 Spark 的 Web-UI 界面,,此时应该显示有两个有效的工作节点:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-Standalone-web-ui.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-Standalone-web-ui.png"/> </div>
|
||||
|
||||
### 3.4 提交作业
|
||||
|
||||
@ -166,13 +166,13 @@ Initial job has not accepted any resources;
|
||||
check your cluster UI to ensure that workers are registered and have sufficient resources
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-内存不足2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-内存不足2.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
这时候可以查看 Web UI,我这里是内存空间不足:提交命令中要求作业的 `executor-memory` 是 2G,但是实际的工作节点的 `Memory` 只有 1G,这时候你可以修改 `--executor-memory`,也可以修改 Woker 的 `Memory`,其默认值为主机所有可用内存值减去 1G。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-内存不足.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spark-内存不足.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
|
@ -30,7 +30,7 @@
|
||||
|
||||
### 2.1 项目结构
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spring-mybatis-phoenix.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spring-mybatis-phoenix.png"/> </div>
|
||||
|
||||
### 2.2 主要依赖
|
||||
|
||||
@ -221,7 +221,7 @@ public class PopulationDaoTest {
|
||||
|
||||
### 3.1 项目结构
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spring-boot-mybatis-phoenix.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spring-boot-mybatis-phoenix.png"/> </div>
|
||||
|
||||
### 3.2 主要依赖
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
# sqoop help
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-help.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-help.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
@ -50,7 +50,7 @@ sqoop list-databases \
|
||||
--password root
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-list-databases.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-list-databases.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
@ -92,7 +92,7 @@ sqoop import \
|
||||
+ 添加 `-- autoreset-to-one-mapper` 参数,代表只启动一个 `map task`,即不并行执行;
|
||||
+ 若仍希望并行执行,则可以使用 `--split-by <column-name>` 指明拆分数据的参考列。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-map-task.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-map-task.png"/> </div>
|
||||
|
||||
#### 2. 导入验证
|
||||
|
||||
@ -105,7 +105,7 @@ hadoop fs -text /sqoop/part-m-00000
|
||||
|
||||
查看 HDFS 导入目录,可以看到表中数据被分为 3 部分进行存储,这是由指定的并行度决定的。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop_hdfs_ls.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop_hdfs_ls.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
@ -170,11 +170,11 @@ sqoop import \
|
||||
hive> SELECT * FROM sqoop_test.help_keyword;
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop_hive_tables.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop_hive_tables.png"/> </div>
|
||||
|
||||
#### 3. 可能出现的问题
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop_hive_error.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop_hive_error.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
@ -203,11 +203,11 @@ hive> desc formatted help_keyword;
|
||||
|
||||
`Location` 属性为其存储位置:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-hive-location.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-hive-location.png"/> </div>
|
||||
|
||||
这里可以查看一下这个目录,文件结构如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-hive-hdfs.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-hive-hdfs.png"/> </div>
|
||||
|
||||
#### 3.2 执行导出命令
|
||||
|
||||
@ -265,7 +265,7 @@ hbase> desc 'help_keyword_hbase'
|
||||
|
||||
使用 `scan` 查看表数据:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop_hbase.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop_hbase.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -21,13 +21,13 @@ Sqoop 是一个常用的数据迁移工具,主要用于在不同存储系统
|
||||
|
||||
其原理是将执行命令转化成 MapReduce 作业来实现数据的迁移,如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-tool.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-tool.png"/> </div>
|
||||
|
||||
## 二、安装
|
||||
|
||||
版本选择:目前 Sqoop 有 Sqoop 1 和 Sqoop 2 两个版本,但是截至到目前,官方并不推荐使用 Sqoop 2,因为其与 Sqoop 1 并不兼容,且功能还没有完善,所以这里优先推荐使用 Sqoop 1。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-version-selected.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-version-selected.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -92,7 +92,7 @@ export ZOOCFGDIR=/usr/app/zookeeper-3.4.13/conf
|
||||
|
||||
将 MySQL 驱动包拷贝到 Sqoop 安装目录的 `lib` 目录下, 驱动包的下载地址为 https://dev.mysql.com/downloads/connector/j/ 。在本仓库的[resources](https://github.com/heibaiying/BigData-Notes/tree/master/resources) 目录下我也上传了一份,有需要的话可以自行下载。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-mysql-jar.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-mysql-jar.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -106,7 +106,7 @@ export ZOOCFGDIR=/usr/app/zookeeper-3.4.13/conf
|
||||
|
||||
出现对应的版本信息则代表配置成功:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/sqoop-version.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/sqoop-version.png"/> </div>
|
||||
|
||||
这里出现的两个 `Warning` 警告是因为我们本身就没有用到 `HCatalog` 和 `Accumulo`,忽略即可。Sqoop 在启动时会去检查环境变量中是否有配置这些软件,如果想去除这些警告,可以修改 `bin/configure-sqoop`,注释掉不必要的检查。
|
||||
|
||||
|
@ -176,7 +176,7 @@ maven-assembly-plugin 是官方文档中介绍的打包方法,来源于官方
|
||||
|
||||
打包后会同时生成两个 JAR 包,其中后缀为 `jar-with-dependencies` 是含有第三方依赖的 JAR 包,后缀是由 `assembly.xml` 中 `<id>` 标签指定的,可以自定义修改。提交该 JAR 到集群环境即可直接使用。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-jar.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-jar.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -276,7 +276,7 @@ maven-assembly-plugin 是官方文档中介绍的打包方法,来源于官方
|
||||
|
||||
打包后会生成两个 JAR 包,提交到服务器集群时使用 ` 非 original` 开头的 JAR。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-jar2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-jar2.png"/> </div>
|
||||
|
||||
## 五、结论
|
||||
|
||||
@ -288,7 +288,7 @@ maven-assembly-plugin 是官方文档中介绍的打包方法,来源于官方
|
||||
|
||||
无论采用任何打包方式,都必须排除集群环境中已经提供的 storm jars。这里比较典型的是 storm-core,其在安装目录的 lib 目录下已经存在。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-lib.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-lib.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -306,7 +306,7 @@ jar:file:/usr/appjar/storm-hdfs-integration-1.0.jar!/defaults.yaml]
|
||||
... 39 more
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-jar-complie-error.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-jar-complie-error.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ Hadoop 采用 MapReduce 处理数据,而 MapReduce 主要是对数据进行批
|
||||
|
||||
Spark Streaming 并不是真正意义上的流处理框架。 Spark Streaming 接收实时输入的数据流,并将数据拆分为一系列批次,然后进行微批处理。只不过 Spark Streaming 能够将数据流进行极小粒度的拆分,使得其能够得到接近于流处理的效果,但其本质上还是批处理(或微批处理)。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/streaming-flow.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/streaming-flow.png"/> </div>
|
||||
|
||||
#### 1.4 Strom 与 Flink对比
|
||||
|
||||
@ -64,7 +64,7 @@ storm 和 Flink 都是真正意义上的实时计算框架。其对比如下:
|
||||
|
||||
在流处理之前,数据通常存储在数据库或文件系统中,应用程序根据需要查询或计算数据,这就是传统的静态数据处理架构。Hadoop 采用 HDFS 进行数据存储,采用 MapReduce 进行数据查询或分析,这就是典型的静态数据处理架构。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/01_data_at_rest_infrastructure.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/01_data_at_rest_infrastructure.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -74,7 +74,7 @@ storm 和 Flink 都是真正意义上的实时计算框架。其对比如下:
|
||||
|
||||
接收和发送数据流并执行应用程序或分析逻辑的系统称为**流处理器**。流处理器的基本职责是确保数据有效流动,同时具备可扩展性和容错能力,Storm 和 Flink 就是其代表性的实现。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/02_stream_processing_infrastructure.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/02_stream_processing_infrastructure.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
## 一、Storm核心概念
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spout-bolt.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spout-bolt.png"/> </div>
|
||||
|
||||
### 1.1 Topologies(拓扑)
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
### 1.5 Stream groupings(分组策略)
|
||||
|
||||
<div align="center"> <img width="400px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/topology-tasks.png"/> </div>
|
||||
<div align="center"> <img width="400px" src="../pictures/topology-tasks.png"/> </div>
|
||||
|
||||
`spouts` 和 `bolts` 在集群上执行任务时,是由多个 Task 并行执行 (如上图,每一个圆圈代表一个 Task)。当一个 Tuple 需要从 Bolt A 发送给 Bolt B 执行的时候,程序如何知道应该发送给 Bolt B 的哪一个 Task 执行呢?
|
||||
|
||||
@ -80,7 +80,7 @@
|
||||
|
||||
## 二、Storm架构详解
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/Internal-Working-of-Apache-Storm.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/Internal-Working-of-Apache-Storm.png"/> </div>
|
||||
|
||||
### 2.1 Nimbus进程
|
||||
|
||||
@ -132,7 +132,7 @@ Storm 集群的任务执行者 ,循环执行 Task 代码。主要功能如下
|
||||
|
||||
### 2.6 并行度
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/relationships-worker-processes-executors-tasks.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/relationships-worker-processes-executors-tasks.png"/> </div>
|
||||
|
||||
1 个 Worker 进程执行的是 1 个 Topology 的子集,不会出现 1 个 Worker 为多个 Topology 服务的情况,因此 1 个运行中的 Topology 就是由集群中多台物理机上的多个 Worker 进程组成的。1 个 Worker 进程会启动 1 个或多个 Executor 线程来执行 1 个 Topology 的 Component(组件,即 Spout 或 Bolt)。
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
下图为 Strom 的运行流程图,在开发 Storm 流处理程序时,我们需要采用内置或自定义实现 `spout`(数据源) 和 `bolt`(处理单元),并通过 `TopologyBuilder` 将它们之间进行关联,形成 `Topology`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spout-bolt.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/spout-bolt.png"/> </div>
|
||||
|
||||
## 二、IComponent接口
|
||||
|
||||
@ -101,7 +101,7 @@ public interface ISpout extends Serializable {
|
||||
|
||||
**通常情况下,我们实现自定义的 Spout 时不会直接去实现 `ISpout` 接口,而是继承 `BaseRichSpout`。**`BaseRichSpout` 继承自 `BaseCompont`,同时实现了 `IRichSpout` 接口。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-baseRichSpout.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-baseRichSpout.png"/> </div>
|
||||
|
||||
`IRichSpout` 接口继承自 `ISpout` 和 `IComponent`,自身并没有定义任何方法:
|
||||
|
||||
@ -192,7 +192,7 @@ public interface IBolt extends Serializable {
|
||||
|
||||
同样的,在实现自定义 bolt 时,通常是继承 `BaseRichBolt` 抽象类来实现。`BaseRichBolt` 继承自 `BaseComponent` 抽象类并实现了 `IRichBolt` 接口。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-baseRichbolt.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-baseRichbolt.png"/> </div>
|
||||
|
||||
`IRichBolt` 接口继承自 `IBolt` 和 `IComponent`,自身并没有定义任何方法:
|
||||
|
||||
@ -216,7 +216,7 @@ public interface IRichBolt extends IBolt, IComponent {
|
||||
|
||||
这里我们使用自定义的 `DataSourceSpout` 产生词频数据,然后使用自定义的 `SplitBolt` 和 `CountBolt` 来进行词频统计。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-word-count-p.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-word-count-p.png"/> </div>
|
||||
|
||||
> 案例源码下载地址:[storm-word-count](https://github.com/heibaiying/BigData-Notes/tree/master/code/Storm/storm-word-count)
|
||||
|
||||
@ -382,7 +382,7 @@ public class LocalWordCountApp {
|
||||
|
||||
启动 `WordCountApp` 的 main 方法即可运行,采用本地模式 Storm 会自动在本地搭建一个集群,所以启动的过程会稍慢一点,启动成功后即可看到输出日志。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-word-count-console.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-word-count-console.png"/> </div>
|
||||
|
||||
|
||||
## 六、提交到服务器集群运行
|
||||
@ -437,7 +437,7 @@ storm jar /usr/appjar/storm-word-count-1.0.jar com.heibaiying.wordcount.Cluster
|
||||
|
||||
出现 `successfully` 则代表提交成功:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-submit-success.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-submit-success.png"/> </div>
|
||||
|
||||
### 6.4 查看Topology与停止Topology(命令行方式)
|
||||
|
||||
@ -449,13 +449,13 @@ storm list
|
||||
storm kill ClusterWordCountApp -w 3
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-list-kill.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-list-kill.png"/> </div>
|
||||
|
||||
### 6.5 查看Topology与停止Topology(界面方式)
|
||||
|
||||
使用 UI 界面同样也可进行停止操作,进入 WEB UI 界面(8080 端口),在 `Topology Summary` 中点击对应 Topology 即可进入详情页面进行操作。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-ui-actions.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-ui-actions.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -472,7 +472,7 @@ storm kill ClusterWordCountApp -w 3
|
||||
|
||||
这时候可能大家会有疑惑,在我们的项目中不是使用了 `storm-core` 这个依赖吗?其实上面之所以我们能运行成功,是因为在 Storm 的集群环境中提供了这个 JAR 包,在安装目录的 lib 目录下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-lib.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-lib.png"/> </div>
|
||||
为了说明这个问题我在 Maven 中引入了一个第三方的 JAR 包,并修改产生数据的方法:
|
||||
|
||||
```xml
|
||||
@ -498,7 +498,7 @@ private String productData() {
|
||||
|
||||
此时直接使用 `mvn clean package` 打包运行,就会抛出下图的异常。因此这种直接打包的方式并不适用于实际的开发,因为实际开发中通常都是需要第三方的 JAR 包。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-package-error.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-package-error.png"/> </div>
|
||||
|
||||
|
||||
想把依赖包一并打入最后的 JAR 中,maven 提供了两个插件来实现,分别是 `maven-assembly-plugin` 和 `maven-shade-plugin`。鉴于本篇文章篇幅已经比较长,且关于 Storm 打包还有很多需要说明的地方,所以关于 Storm 的打包方式单独整理至下一篇文章:
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
### 1.1 项目结构
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/datasourcetohdfs.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/datasourcetohdfs.png"/> </div>
|
||||
|
||||
> 本用例源码下载地址:[storm-hdfs-integration](https://github.com/heibaiying/BigData-Notes/tree/master/code/Storm/storm-hdfs-integration)
|
||||
|
||||
@ -218,7 +218,7 @@ hadoop fs -tail -f /strom-hdfs/文件名
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-hdfs-result.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-hdfs-result.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -228,7 +228,7 @@ hadoop fs -tail -f /strom-hdfs/文件名
|
||||
|
||||
集成用例: 进行词频统计并将最后的结果存储到 HBase,项目主要结构如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/WordCountToHBaseApp.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/WordCountToHBaseApp.png"/> </div>
|
||||
|
||||
> 本用例源码下载地址:[storm-hbase-integration](https://github.com/heibaiying/BigData-Notes/tree/master/code/Storm/storm-hbase-integration)
|
||||
|
||||
@ -465,7 +465,7 @@ public class WordCountToHBaseApp {
|
||||
hbase > scan 'WordCount'
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-hbase-result.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-hbase-result.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -20,7 +20,7 @@ Storm 官方对 Kafka 的整合分为两个版本,官方说明文档分别如
|
||||
|
||||
### 2.1 项目结构
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/writetokafka.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/writetokafka.png"/> </div>
|
||||
|
||||
### 2.2 项目主要依赖
|
||||
|
||||
@ -214,7 +214,7 @@ bin/kafka-topics.sh --create --bootstrap-server hadoop001:9092 --replication-fac
|
||||
|
||||
启动后,消费者监听情况如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/strom-kafka-consumer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/strom-kafka-consumer.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -222,7 +222,7 @@ bin/kafka-topics.sh --create --bootstrap-server hadoop001:9092 --replication-fac
|
||||
|
||||
### 3.1 项目结构
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/readfromkafka.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/readfromkafka.png"/> </div>
|
||||
|
||||
### 3.2 ReadingFromKafkaApp
|
||||
|
||||
@ -348,11 +348,11 @@ public class DefaultRecordTranslator<K, V> implements RecordTranslator<K, V> {
|
||||
# bin/kafka-console-producer.sh --broker-list hadoop001:9092 --topic storm-topic
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-kafka-producer.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-kafka-producer.png"/> </div>
|
||||
|
||||
本地运行的项目接收到从 Kafka 发送过来的数据:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-kafka-receiver.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-kafka-receiver.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ Storm-Redis 使用 Jedis 为 Redis 客户端,并提供了如下三个基本的
|
||||
|
||||
这里首先给出一个集成案例:进行词频统计并将最后的结果存储到 Redis。项目结构如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-wordcounttoredis.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-wordcounttoredis.png"/> </div>
|
||||
|
||||
> 用例源码下载地址:[storm-redis-integration](https://github.com/heibaiying/BigData-Notes/tree/master/code/Storm/storm-redis-integration)
|
||||
|
||||
@ -283,7 +283,7 @@ public class WordCountToRedisApp {
|
||||
|
||||
启动后,查看 Redis 中的数据:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/store-redis-manager.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/store-redis-manager.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -295,7 +295,7 @@ public class WordCountToRedisApp {
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-abstractRedisBolt.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-abstractRedisBolt.png"/> </div>
|
||||
|
||||
`AbstractRedisBolt` 中比较重要的是 prepare 方法,在该方法中通过外部传入的 jedis 连接池配置 ( jedisPoolConfig/jedisClusterConfig) 创建用于管理 Jedis 实例的容器 `JedisCommandsInstanceContainer`。
|
||||
|
||||
@ -440,13 +440,13 @@ public class RedisStoreBolt extends AbstractRedisBolt {
|
||||
|
||||
JedisCommands 接口中定义了所有的 Redis 客户端命令,它有以下三个实现类,分别是 Jedis、JedisCluster、ShardedJedis。Strom 中主要使用前两种实现类,具体调用哪一个实现类来执行命令,由传入的是 jedisPoolConfig 还是 jedisClusterConfig 来决定。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-jedicCommands.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-jedicCommands.png"/> </div>
|
||||
|
||||
### 3.4 RedisMapper 和 TupleMapper
|
||||
|
||||
RedisMapper 和 TupleMapper 定义了 tuple 和 Redis 中的数据如何进行映射转换。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-Redis-Mapper.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-Redis-Mapper.png"/> </div>
|
||||
|
||||
#### 1. TupleMapper
|
||||
|
||||
@ -553,7 +553,7 @@ redis>
|
||||
|
||||
### 4.2 项目结构
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/CustomRedisCountApp.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/CustomRedisCountApp.png"/> </div>
|
||||
|
||||
### 4.3 自定义RedisBolt的代码实现
|
||||
|
||||
|
@ -145,7 +145,7 @@ Authentication is not valid : /hive # 当前主机已经不能访问
|
||||
"-Dzookeeper.DigestAuthenticationProvider.superDigest=heibai:sCxtVJ1gPG8UW/jzFHR0A1ZKY5s="
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-super.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/zookeeper-super.png"/> </div>
|
||||
|
||||
修改完成后需要使用 `zkServer.sh restart` 重启服务,此时再次访问限制 IP 的节点:
|
||||
|
||||
|
@ -91,7 +91,7 @@ public class BasicOperation {
|
||||
|
||||
在连接 Zookeeper 时,Curator 提供了多种重试策略以满足各种需求,所有重试策略均继承自 `RetryPolicy` 接口,如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/curator-retry-policy.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/curator-retry-policy.png"/> </div>
|
||||
|
||||
这些重试策略类主要分为以下两类:
|
||||
|
||||
|
@ -42,13 +42,13 @@ Zookeeper 致力于为那些高吞吐的大型分布式系统提供一个高性
|
||||
|
||||
Zookeeper 通过树形结构来存储数据,它由一系列被称为 ZNode 的数据节点组成,类似于常见的文件系统。不过和常见的文件系统不同,Zookeeper 将数据全量存储在内存中,以此来实现高吞吐,减少访问延迟。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-zknamespace.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/zookeeper-zknamespace.jpg"/> </div>
|
||||
|
||||
### 2.2 目标二:构建集群
|
||||
|
||||
可以由一组 Zookeeper 服务构成 Zookeeper 集群,集群中每台机器都会单独在内存中维护自身的状态,并且每台机器之间都保持着通讯,只要集群中有半数机器能够正常工作,那么整个集群就可以正常提供服务。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-zkservice.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/zookeeper-zkservice.jpg"/> </div>
|
||||
|
||||
### 2.3 目标三:顺序访问
|
||||
|
||||
@ -127,7 +127,7 @@ ZAB 协议是 Zookeeper 专门设计的一种支持崩溃恢复的原子广播
|
||||
|
||||
Zookeeper 使用一个单一的主进程来接收并处理客户端的所有事务请求,并采用原子广播协议将数据状态的变更以事务 Proposal 的形式广播到所有的副本进程上去。如下图:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-zkcomponents.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/zookeeper-zkcomponents.jpg"/> </div>
|
||||
|
||||
具体流程如下:
|
||||
|
||||
@ -147,7 +147,7 @@ ZAB 协议的消息广播过程使用的是原子广播协议。在整个消息
|
||||
|
||||
Leader 服务会为每一个 Follower 服务器分配一个单独的队列,然后将事务 Proposal 依次放入队列中,并根据 FIFO(先进先出) 的策略进行消息发送。Follower 服务在接收到 Proposal 后,会将其以事务日志的形式写入本地磁盘中,并在写入成功后反馈给 Leader 一个 Ack 响应。当 Leader 接收到超过半数 Follower 的 Ack 响应后,就会广播一个 Commit 消息给所有的 Follower 以通知其进行事务提交,之后 Leader 自身也会完成对事务的提交。而每一个 Follower 则在接收到 Commit 消息后,完成事务的提交。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-brocast.jpg"/> </div>
|
||||
<div align="center"> <img src="../pictures/zookeeper-brocast.jpg"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -37,7 +37,7 @@ Azkaban 3.70.0 编译需要依赖 `gradle-4.6-all.zip`。Gradle 是一个项目
|
||||
|
||||
需要注意的是不同版本的 Azkaban 依赖 Gradle 版本不同,可以在解压后的 `/gradle/wrapper/gradle-wrapper.properties` 文件查看
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-gradle-wrapper.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/azkaban-gradle-wrapper.png"/> </div>
|
||||
|
||||
在编译时程序会自动去图中所示的地址进行下载,但是下载速度很慢。为避免影响编译过程,建议先手动下载至 `/gradle/wrapper/` 目录下:
|
||||
|
||||
@ -47,7 +47,7 @@ Azkaban 3.70.0 编译需要依赖 `gradle-4.6-all.zip`。Gradle 是一个项目
|
||||
|
||||
然后修改配置文件 `gradle-wrapper.properties` 中的 `distributionUrl` 属性,指明使用本地的 gradle。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-gradle-wrapper-2.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/azkaban-gradle-wrapper-2.png"/> </div>
|
||||
|
||||
#### 3. Git
|
||||
|
||||
@ -100,7 +100,7 @@ tar -zxvf azkaban-solo-server-3.70.0.tar.gz
|
||||
|
||||
这一步不是必须的。但是因为 Azkaban 默认采用的时区是 `America/Los_Angeles`,如果你的调度任务中有定时任务的话,就需要进行相应的更改,这里我更改为常用的 `Asia/Shanghai`
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-setting.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/azkaban-setting.png"/> </div>
|
||||
|
||||
### 2.3 启动
|
||||
|
||||
@ -114,11 +114,11 @@ tar -zxvf azkaban-solo-server-3.70.0.tar.gz
|
||||
|
||||
验证方式一:使用 `jps` 命令查看是否有 `AzkabanSingleServer` 进程:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/akaban-jps.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/akaban-jps.png"/> </div>
|
||||
<br/>
|
||||
|
||||
验证方式二:访问 8081 端口,查看 Web UI 界面,默认的登录名密码都是 `azkaban`,如果需要修改或新增用户,可以在 `conf/azkaban-users.xml ` 文件中进行配置:
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/azkaban-web-ui.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/azkaban-web-ui.png"/> </div>
|
||||
|
||||
|
||||
|
@ -49,7 +49,7 @@ bin/start-cluster.sh
|
||||
|
||||
Flink 提供了 WEB 界面用于直观的管理 Flink 集群,访问端口为 `8081`:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-dashboard.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/flink-dashboard.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -83,13 +83,13 @@ a a b b c c c a e
|
||||
|
||||
可以通过 WEB UI 的控制台查看作业统运行情况:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-socket-wordcount.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/flink-socket-wordcount.png"/> </div>
|
||||
|
||||
|
||||
|
||||
也可以通过 WEB 控制台查看到统计结果:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-socket-wordcount-stdout.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/flink-socket-wordcount-stdout.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -160,7 +160,7 @@ bin/start-cluster.sh
|
||||
|
||||
此时控制台输出如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-start-cluster-shell.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/flink-start-cluster-shell.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -223,13 +223,13 @@ bin/start-cluster.sh
|
||||
|
||||
此时输出如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-standalone-cluster-ha.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/flink-standalone-cluster-ha.png"/> </div>
|
||||
|
||||
|
||||
|
||||
可以看到集群已经以 HA 的模式启动,此时还需要在各个节点上使用 `jps` 命令来查看进程是否启动成功,正常情况如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-standalone-cluster-jps.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/flink-standalone-cluster-jps.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -255,7 +255,7 @@ the classpath/dependencies.
|
||||
|
||||
可以看到是因为在 classpath 目录下找不到 Hadoop 的相关依赖,此时需要检查是否在环境变量中配置了 Hadoop 的安装路径,如果路径已经配置但仍然存在上面的问题,可以从 [Flink 官网](https://flink.apache.org/downloads.html)下载对应版本的 Hadoop 组件包:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/flink-optional-components.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/flink-optional-components.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -106,7 +106,7 @@ export JAVA_HOME=/usr/java/jdk1.8.0_201
|
||||
|
||||
验证方式二 :访问 HBaseWeb UI 页面,默认端口为 `16010` 。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-web-ui.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hbase-web-ui.png"/> </div>
|
||||
|
||||
|
||||
## 三、伪集群模式安装(Pseudo-Distributed)
|
||||
@ -224,4 +224,4 @@ hadoop001
|
||||
|
||||
验证方式二 :访问 HBase Web UI 界面,需要注意的是 1.2 版本的 HBase 的访问端口为 `60010`
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-60010.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hbase-60010.png"/> </div>
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
这里搭建一个 3 节点的 HBase 集群,其中三台主机上均为 `Regin Server`。同时为了保证高可用,除了在 hadoop001 上部署主 `Master` 服务外,还在 hadoop002 上部署备用的 `Master` 服务。Master 服务由 Zookeeper 集群进行协调管理,如果主 `Master` 不可用,则备用 `Master` 会成为新的主 `Master`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase集群规划.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hbase集群规划.png"/> </div>
|
||||
|
||||
## 二、前置条件
|
||||
|
||||
@ -190,11 +190,11 @@ start-hbase.sh
|
||||
|
||||
访问 HBase 的 Web-UI 界面,这里我安装的 HBase 版本为 1.2,访问端口为 `60010`,如果你安装的是 2.0 以上的版本,则访问端口号为 `16010`。可以看到 `Master` 在 hadoop001 上,三个 `Regin Servers` 分别在 hadoop001,hadoop002,和 hadoop003 上,并且还有一个 `Backup Matser` 服务在 hadoop002 上。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-集群搭建1.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hbase-集群搭建1.png"/> </div>
|
||||
<br/>
|
||||
|
||||
hadoop002 上的 HBase 出于备用状态:
|
||||
|
||||
<br/>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hbase-集群搭建2.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hbase-集群搭建2.png"/> </div>
|
||||
|
@ -195,7 +195,7 @@ sudo systemctl stop firewalld.service
|
||||
|
||||
方式二:查看 Web UI 界面,端口为 `50070`:
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop安装验证.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/hadoop安装验证.png"/> </div>
|
||||
|
||||
|
||||
## 四、Hadoop(YARN)环境搭建
|
||||
@ -259,4 +259,4 @@ cp mapred-site.xml.template mapred-site.xml
|
||||
|
||||
方式二:查看 Web UI 界面,端口号为 `8088`:
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-yarn安装验证.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/hadoop-yarn安装验证.png"/> </div>
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
这里搭建一个 3 节点的 Hadoop 集群,其中三台主机均部署 `DataNode` 和 `NodeManager` 服务,但只有 hadoop001 上部署 `NameNode` 和 `ResourceManager` 服务。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop集群规划.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop集群规划.png"/> </div>
|
||||
|
||||
## 二、前置条件
|
||||
|
||||
@ -210,17 +210,17 @@ start-yarn.sh
|
||||
|
||||
在每台服务器上使用 `jps` 命令查看服务进程,或直接进入 Web-UI 界面进行查看,端口为 `50070`。可以看到此时有三个可用的 `Datanode`:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-集群环境搭建.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop-集群环境搭建.png"/> </div>
|
||||
<BR/>
|
||||
|
||||
点击 `Live Nodes` 进入,可以看到每个 `DataNode` 的详细情况:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-集群搭建2.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop-集群搭建2.png"/> </div>
|
||||
<BR/>
|
||||
|
||||
接着可以查看 Yarn 的情况,端口号为 `8088` :
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-集群搭建3.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop-集群搭建3.png"/> </div>
|
||||
|
||||
|
||||
## 五、提交服务到集群
|
||||
|
@ -98,7 +98,7 @@ HADOOP_HOME=/usr/app/hadoop-2.6.0-cdh5.15.2
|
||||
|
||||
将 MySQL 驱动包拷贝到 Hive 安装目录的 `lib` 目录下, MySQL 驱动的下载地址为:https://dev.mysql.com/downloads/connector/j/ , 在本仓库的[resources](https://github.com/heibaiying/BigData-Notes/tree/master/resources) 目录下我也上传了一份,有需要的可以自行下载。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-mysql.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hive-mysql.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -123,11 +123,11 @@ HADOOP_HOME=/usr/app/hadoop-2.6.0-cdh5.15.2
|
||||
# hive
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-install-2.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hive-install-2.png"/> </div>
|
||||
|
||||
在 Mysql 中也能看到 Hive 创建的库和存放元数据信息的表
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-mysql-tables.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hive-mysql-tables.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -178,4 +178,4 @@ Hive 内置了 HiveServer 和 HiveServer2 服务,两者都允许客户端使
|
||||
# beeline -u jdbc:hive2://hadoop001:10000 -n root
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hive-beeline-cli.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hive-beeline-cli.png"/> </div>
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
官方下载地址:http://spark.apache.org/downloads.html ,选择 Spark 版本和对应的 Hadoop 版本后再下载:
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-download.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../../pictures/spark-download.png"/> </div>
|
||||
|
||||
解压安装包:
|
||||
|
||||
@ -54,7 +54,7 @@ spark-shell --master local[2]
|
||||
- **local[k]**:启动 k 个工作线程;
|
||||
- **local[*]**:启动跟 cpu 数目相同的工作线程数。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-shell-local.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-shell-local.png"/> </div>
|
||||
|
||||
<br/>
|
||||
|
||||
@ -86,11 +86,11 @@ wordCounts.collect
|
||||
|
||||
执行过程如下,可以看到已经输出了词频统计的结果:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-shell.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-shell.png"/> </div>
|
||||
|
||||
同时还可以通过 Web UI 查看作业的执行情况,访问端口为 `4040`:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-shell-web-ui.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-shell-web-ui.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -108,7 +108,7 @@ Scala 的运行依赖于 JDK,所以需要你本机有安装对应版本的 JDK
|
||||
|
||||
IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。打开 IDEA,依次点击 **File** => **settings**=> **plugins** 选项卡,搜索 Scala 插件 (如下图)。找到插件后进行安装,并重启 IDEA 使得安装生效。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-plugin.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/idea-scala-plugin.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -116,7 +116,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
在 IDEA 中依次点击 **File** => **New** => **Project** 选项卡,然后选择创建 `Scala—IDEA` 工程:
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-newproject-scala.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/idea-newproject-scala.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -126,7 +126,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
此时看到 `Scala SDK` 为空,依次点击 `Create` => `Download` ,选择所需的版本后,点击 `OK` 按钮进行下载,下载完成点击 `Finish` 进入工程。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-select.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/idea-scala-select.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -136,13 +136,13 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
这里我的系统是 Windows,下载 msi 版本的安装包后,一直点击下一步进行安装,安装完成后会自动配置好环境变量。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-other-resources.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/scala-other-resources.png"/> </div>
|
||||
|
||||
|
||||
|
||||
由于安装时已经自动配置好环境变量,所以 IDEA 会自动选择对应版本的 SDK。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-2.1.8.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/idea-scala-2.1.8.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -150,7 +150,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
在工程 `src` 目录上右击 **New** => **Scala class** 创建 `Hello.scala`。输入代码如下,完成后点击运行按钮,成功运行则代表搭建成功。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-hello-world.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/scala-hello-world.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -160,7 +160,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
在日常的开发中,由于对应软件(如 Spark)的版本切换,可能导致需要切换 Scala 的版本,则可以在 `Project Structures` 中的 `Global Libraries` 选项卡中进行切换。
|
||||
|
||||
<div align="center"> <img width="700px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/idea-scala-change.png"/> </div>
|
||||
<div align="center"> <img width="700px" src="../../pictures/idea-scala-change.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -170,7 +170,7 @@ IDEA 默认不支持 Scala 语言的开发,需要通过插件进行扩展。
|
||||
|
||||
在 IDEA 中有时候重新打开项目后,右击并不会出现新建 `scala` 文件的选项,或者在编写时没有 Scala 语法提示,此时可以先删除 `Global Libraries` 中配置好的 SDK,之后再重新添加:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/scala-sdk.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/scala-sdk.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -22,7 +22,7 @@
|
||||
|
||||
这里搭建一个 3 节点的 Spark 集群,其中三台主机上均部署 `Worker` 服务。同时为了保证高可用,除了在 hadoop001 上部署主 `Master` 服务外,还在 hadoop002 和 hadoop003 上分别部署备用的 `Master` 服务,Master 服务由 Zookeeper 集群进行协调管理,如果主 `Master` 不可用,则备用 `Master` 会成为新的主 `Master`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark集群规划.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark集群规划.png"/> </div>
|
||||
|
||||
## 二、前置条件
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
|
||||
下载所需版本的 Spark,官网下载地址:http://spark.apache.org/downloads.html
|
||||
|
||||
<div align="center"> <img width="600px" src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-download.png"/> </div>
|
||||
<div align="center"> <img width="600px" src="../../pictures/spark-download.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -151,13 +151,13 @@ start-master.sh
|
||||
|
||||
查看 Spark 的 Web-UI 页面,端口为 `8080`。此时可以看到 hadoop001 上的 Master 节点处于 `ALIVE` 状态,并有 3 个可用的 `Worker` 节点。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群搭建1.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-集群搭建1.png"/> </div>
|
||||
|
||||
而 hadoop002 和 hadoop003 上的 Master 节点均处于 `STANDBY` 状态,没有可用的 `Worker` 节点。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群搭建2.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-集群搭建2.png"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群搭建3.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-集群搭建3.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -165,11 +165,11 @@ start-master.sh
|
||||
|
||||
此时可以使用 `kill` 命令杀死 hadoop001 上的 `Master` 进程,此时备用 `Master` 会中会有一个再次成为 ` 主 Master`,我这里是 hadoop002,可以看到 hadoop2 上的 `Master` 经过 `RECOVERING` 后成为了新的主 `Master`,并且获得了全部可以用的 `Workers`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群搭建4.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-集群搭建4.png"/> </div>
|
||||
|
||||
Hadoop002 上的 `Master` 成为主 `Master`,并获得了全部可以用的 `Workers`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/spark-集群搭建5.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/spark-集群搭建5.png"/> </div>
|
||||
|
||||
此时如果你再在 hadoop001 上使用 `start-master.sh` 启动 Master 服务,那么其会作为备用 `Master` 存在。
|
||||
|
||||
|
@ -78,4 +78,4 @@ nohup sh storm logviewer &
|
||||
|
||||
验证方式二: 访问 8080 端口,查看 Web-UI 界面:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-web-ui.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/storm-web-ui.png"/> </div>
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
这里搭建一个 3 节点的 Storm 集群:三台主机上均部署 `Supervisor` 和 `LogViewer` 服务。同时为了保证高可用,除了在 hadoop001 上部署主 `Nimbus` 服务外,还在 hadoop002 上部署备用的 `Nimbus` 服务。`Nimbus` 服务由 Zookeeper 集群进行协调管理,如果主 `Nimbus` 不可用,则备用 `Nimbus` 会成为新的主 `Nimbus`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-集群规划.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/storm-集群规划.png"/> </div>
|
||||
|
||||
## 二、前置条件
|
||||
|
||||
@ -150,18 +150,18 @@ nohup sh storm logviewer &
|
||||
|
||||
使用 `jps` 查看进程,三台服务器的进程应该分别如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-集群-shell.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/storm-集群-shell.png"/> </div>
|
||||
|
||||
|
||||
<br/>
|
||||
|
||||
访问 hadoop001 或 hadoop002 的 `8080` 端口,界面如下。可以看到有一主一备 2 个 `Nimbus` 和 3 个 `Supervisor`,并且每个 `Supervisor` 有四个 `slots`,即四个可用的 `worker` 进程,此时代表集群已经搭建成功。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-集群搭建1.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/storm-集群搭建1.png"/> </div>
|
||||
|
||||
|
||||
## 五、高可用验证
|
||||
|
||||
这里手动模拟主 `Nimbus` 异常的情况,在 hadoop001 上使用 `kill` 命令杀死 `Nimbus` 的线程,此时可以看到 hadoop001 上的 `Nimbus` 已经处于 `offline` 状态,而 hadoop002 上的 `Nimbus` 则成为新的 `Leader`。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm集群搭建2.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/storm集群搭建2.png"/> </div>
|
||||
|
@ -180,8 +180,8 @@ echo "3" > /usr/local/zookeeper-cluster/data/myid
|
||||
|
||||
启动后使用 `zkServer.sh status` 查看集群各个节点状态。如图所示:三个节点进程均启动成功,并且 hadoop002 为 leader 节点,hadoop001 和 hadoop003 为 follower 节点。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-hadoop001.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/zookeeper-hadoop001.png"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-hadoop002.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/zookeeper-hadoop002.png"/> </div>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-hadoop003.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/zookeeper-hadoop003.png"/> </div>
|
||||
|
@ -20,7 +20,7 @@ Hadoop 高可用 (High Availability) 分为 HDFS 高可用和 YARN 高可用,
|
||||
|
||||
HDFS 高可用架构如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HDFS-HA-Architecture-Edureka.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/HDFS-HA-Architecture-Edureka.png"/> </div>
|
||||
|
||||
> *图片引用自:https://www.edureka.co/blog/how-to-set-up-hadoop-cluster-with-hdfs-high-availability/*
|
||||
|
||||
@ -42,13 +42,13 @@ HDFS 高可用架构主要由以下组件所构成:
|
||||
|
||||
需要说明的是向 JournalNode 集群写入 EditLog 是遵循 “过半写入则成功” 的策略,所以你至少要有 3 个 JournalNode 节点,当然你也可以继续增加节点数量,但是应该保证节点总数是奇数。同时如果有 2N+1 台 JournalNode,那么根据过半写的原则,最多可以容忍有 N 台 JournalNode 节点挂掉。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-QJM-同步机制.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop-QJM-同步机制.png"/> </div>
|
||||
|
||||
### 1.3 NameNode 主备切换
|
||||
|
||||
NameNode 实现主备切换的流程下图所示:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-namenode主备切换.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop-namenode主备切换.png"/> </div>
|
||||
1. HealthMonitor 初始化完成之后会启动内部的线程来定时调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法,对 NameNode 的健康状态进行检测。
|
||||
2. HealthMonitor 如果检测到 NameNode 的健康状态发生变化,会回调 ZKFailoverController 注册的相应方法进行处理。
|
||||
3. 如果 ZKFailoverController 判断需要进行主备切换,会首先使用 ActiveStandbyElector 来进行自动的主备选举。
|
||||
@ -63,14 +63,14 @@ YARN ResourceManager 的高可用与 HDFS NameNode 的高可用类似,但是 R
|
||||
|
||||
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop-rm-ha-overview.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop-rm-ha-overview.png"/> </div>
|
||||
|
||||
|
||||
## 二、集群规划
|
||||
|
||||
按照高可用的设计目标:需要保证至少有两个 NameNode (一主一备) 和 两个 ResourceManager (一主一备) ,同时为满足“过半写入则成功”的原则,需要至少要有 3 个 JournalNode 节点。这里使用三台主机进行搭建,集群规划如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop高可用集群规划.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop高可用集群规划.png"/> </div>
|
||||
|
||||
|
||||
## 三、前置条件
|
||||
@ -448,33 +448,33 @@ HDFS 和 YARN 的端口号分别为 `50070` 和 `8080`,界面应该如下:
|
||||
|
||||
此时 hadoop001 上的 `NameNode` 处于可用状态:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop高可用集群1.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop高可用集群1.png"/> </div>
|
||||
而 hadoop002 上的 `NameNode` 则处于备用状态:
|
||||
|
||||
<br/>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop高可用集群3.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop高可用集群3.png"/> </div>
|
||||
<br/>
|
||||
|
||||
hadoop002 上的 `ResourceManager` 处于可用状态:
|
||||
|
||||
<br/>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop高可用集群4.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop高可用集群4.png"/> </div>
|
||||
<br/>
|
||||
|
||||
hadoop003 上的 `ResourceManager` 则处于备用状态:
|
||||
|
||||
<br/>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop高可用集群5.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop高可用集群5.png"/> </div>
|
||||
<br/>
|
||||
|
||||
同时界面上也有 `Journal Manager` 的相关信息:
|
||||
|
||||
<br/>
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/hadoop高可用集群2.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/hadoop高可用集群2.png"/> </div>
|
||||
## 七、集群的二次启动
|
||||
|
||||
上面的集群初次启动涉及到一些必要初始化操作,所以过程略显繁琐。但是集群一旦搭建好后,想要再次启用它是比较方便的,步骤如下(首选需要确保 ZooKeeper 集群已经启动):
|
||||
|
@ -137,7 +137,7 @@ echo "3" > /usr/local/zookeeper-cluster/data/03/myid
|
||||
|
||||
使用 jps 查看进程,并且使用 `zkServer.sh status` 查看集群各个节点状态。如图三个节点进程均启动成功,并且两个节点为 follower 节点,一个节点为 leader 节点。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/zookeeper-cluster.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/zookeeper-cluster.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -229,7 +229,7 @@ bin/kafka-topics.sh --create --bootstrap-server hadoop001:9092 \
|
||||
bin/kafka-topics.sh --describe --bootstrap-server hadoop001:9092 --topic my-replicated-topic
|
||||
```
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/kafka-cluster-shell.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/kafka-cluster-shell.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -38,7 +38,7 @@ ONBOOT=yes
|
||||
|
||||
我的主机配置:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/ipconfig.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/ipconfig.png"/> </div>
|
||||
|
||||
修改后完整配置如下:
|
||||
|
||||
@ -81,13 +81,13 @@ ONBOOT=yes
|
||||
|
||||
这里我是用的虚拟机是 virtualBox,开启多网卡配置方式如下:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/virtualbox-multi-network.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/virtualbox-multi-network.png"/> </div>
|
||||
|
||||
### 2. 查看网卡名称
|
||||
|
||||
使用 `ifconfig`,查看第二块网卡名称,这里我的名称为 `enp0s8`:
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/mutli-net-ip.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/mutli-net-ip.png"/> </div>
|
||||
|
||||
### 3. 配置第二块网卡
|
||||
|
||||
@ -115,4 +115,4 @@ DEVICE=enp0s8
|
||||
|
||||
使用时只需要根据所处的网络环境,勾选对应的网卡即可,不使用的网卡尽量不要勾选启动。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/virtualbox启用网络.png"/> </div>
|
||||
<div align="center"> <img src="../../pictures/virtualbox启用网络.png"/> </div>
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
## 一、大数据处理流程
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/大数据处理简化流程.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/大数据处理简化流程.png"/> </div>
|
||||
上图是一个简化的大数据处理流程图,大数据处理的主要流程包括数据收集、数据存储、数据处理、数据应用等主要环节。下面我们逐一对各个环节所需要的技术栈进行讲解:
|
||||
|
||||
### 1.1 数据收集
|
||||
@ -126,7 +126,7 @@ Scala 是一门综合了面向对象和函数式编程概念的静态类型的
|
||||
|
||||
上面列出的都是比较主流的大数据框架,社区都很活跃,学习资源也比较丰富。建议从 Hadoop 开始入门学习,因为它是整个大数据生态圈的基石,其它框架都直接或者间接依赖于 Hadoop 。接着就可以学习计算框架,Spark 和 Flink 都是比较主流的混合处理框架,Spark 出现得较早,所以其应用也比较广泛。 Flink 是当下最火热的新一代的混合处理框架,其凭借众多优异的特性得到了众多公司的青睐。两者可以按照你个人喜好或者实际工作需要进行学习。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/HADOOP-ECOSYSTEM-Edureka.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/HADOOP-ECOSYSTEM-Edureka.png"/> </div>
|
||||
|
||||
> *图片引用自* :*https://www.edureka.co/blog/hadoop-ecosystem*
|
||||
|
||||
|
@ -4,54 +4,54 @@
|
||||
|
||||
### 一、基础软件安装
|
||||
|
||||
1. [Linux 环境下 JDK 安装](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Linux下JDK安装.md)
|
||||
2. [Linux 环境下 Python 安装](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Linux下Python安装.md)
|
||||
3. [虚拟机静态 IP 及多 IP 配置](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/虚拟机静态IP及多IP配置.md)
|
||||
1. [Linux 环境下 JDK 安装](installation/Linux下JDK安装.md)
|
||||
2. [Linux 环境下 Python 安装](installation/Linux下Python安装.md)
|
||||
3. [虚拟机静态 IP 及多 IP 配置](installation/虚拟机静态IP及多IP配置.md)
|
||||
|
||||
### 二、Hadoop
|
||||
|
||||
1. [Hadoop 单机环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Hadoop单机环境搭建.md)
|
||||
2. [Hadoop 集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Hadoop集群环境搭建.md)
|
||||
3. [基于 Zookeeper 搭建 Hadoop 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Hadoop高可用集群.md)
|
||||
1. [Hadoop 单机环境搭建](installation/Hadoop单机环境搭建.md)
|
||||
2. [Hadoop 集群环境搭建](installation/Hadoop集群环境搭建.md)
|
||||
3. [基于 Zookeeper 搭建 Hadoop 高可用集群](installation/基于Zookeeper搭建Hadoop高可用集群.md)
|
||||
|
||||
### 三、Spark
|
||||
|
||||
1. [Spark 开发环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Spark开发环境搭建.md)
|
||||
2. [基于 Zookeeper 搭建 Spark 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Spark集群环境搭建.md)
|
||||
1. [Spark 开发环境搭建](installation/Spark开发环境搭建.md)
|
||||
2. [基于 Zookeeper 搭建 Spark 高可用集群](installation/Spark集群环境搭建.md)
|
||||
|
||||
### 四、Flink
|
||||
|
||||
1. [Flink Standalone 集群部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Flink_Standalone_Cluster.md)
|
||||
1. [Flink Standalone 集群部署](installation/Flink_Standalone_Cluster.md)
|
||||
|
||||
### 五、Storm
|
||||
|
||||
1. [Storm 单机环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Storm单机环境搭建.md)
|
||||
2. [Storm 集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Storm集群环境搭建.md)
|
||||
1. [Storm 单机环境搭建](installation/Storm单机环境搭建.md)
|
||||
2. [Storm 集群环境搭建](installation/Storm集群环境搭建.md)
|
||||
|
||||
### 六、HBase
|
||||
|
||||
1. [HBase 单机环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/HBase单机环境搭建.md)
|
||||
2. [HBase 集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/HBase集群环境搭建.md)
|
||||
1. [HBase 单机环境搭建](installation/HBase单机环境搭建.md)
|
||||
2. [HBase 集群环境搭建](installation/HBase集群环境搭建.md)
|
||||
|
||||
### 七、Flume
|
||||
|
||||
1. [Linux 环境下 Flume 的安装部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Linux下Flume的安装.md)
|
||||
1. [Linux 环境下 Flume 的安装部署](installation/Linux下Flume的安装.md)
|
||||
|
||||
### 八、Azkaban
|
||||
|
||||
1. [Azkaban3.x 编译及部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Azkaban_3.x_编译及部署.md)
|
||||
1. [Azkaban3.x 编译及部署](installation/Azkaban_3.x_编译及部署.md)
|
||||
|
||||
### 九、Hive
|
||||
|
||||
1. [Linux 环境下 Hive 的安装部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Linux环境下Hive的安装部署.md)
|
||||
1. [Linux 环境下 Hive 的安装部署](installation/Linux环境下Hive的安装部署.md)
|
||||
|
||||
### 十、Zookeeper
|
||||
|
||||
1. [Zookeeper 单机环境和集群环境搭建](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Zookeeper单机环境和集群环境搭建.md)
|
||||
1. [Zookeeper 单机环境和集群环境搭建](installation/Zookeeper单机环境和集群环境搭建.md)
|
||||
|
||||
### 十一、Kafka
|
||||
|
||||
1. [基于 Zookeeper 搭建 Kafka 高可用集群](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/基于Zookeeper搭建Kafka高可用集群.md)
|
||||
1. [基于 Zookeeper 搭建 Kafka 高可用集群](installation/基于Zookeeper搭建Kafka高可用集群.md)
|
||||
|
||||
|
||||
### 版本说明
|
||||
|
@ -112,7 +112,7 @@ assembly.xml 文件内容如下:
|
||||
|
||||
打包后会同时生成两个 JAR 包,其中后缀为 `jar-with-dependencies` 是含有第三方依赖的 JAR 包,后缀是由 `assembly.xml` 中 `<id>` 标签指定的,可以自定义修改。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-jar.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-jar.png"/> </div>
|
||||
|
||||
|
||||
|
||||
@ -194,7 +194,7 @@ assembly.xml 文件内容如下:
|
||||
|
||||
打包后会生成两个 JAR 包,提交到服务器集群时使用非 original 开头的 JAR。
|
||||
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/storm-jar2.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/storm-jar2.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
<div align="center"> <img src="https://github.com/heibaiying/BigData-Notes/blob/master/pictures/大数据技术栈思维导图.png"/> </div>
|
||||
<div align="center"> <img src="../pictures/大数据技术栈思维导图.png"/> </div>
|
||||
|
||||
|
@ -1,225 +0,0 @@
|
||||
# Azkaban Flow 1.0 的使用
|
||||
|
||||
<nav>
|
||||
<a href="#一简介">一、简介</a><br/>
|
||||
<a href="#二基本任务调度">二、基本任务调度</a><br/>
|
||||
<a href="#三多任务调度">三、多任务调度</a><br/>
|
||||
<a href="#四调度HDFS作业">四、调度HDFS作业</a><br/>
|
||||
<a href="#五调度MR作业">五、调度MR作业</a><br/>
|
||||
<a href="#六调度Hive作业">六、调度Hive作业</a><br/>
|
||||
<a href="#七在线修改作业配置">七、在线修改作业配置</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
## 一、简介
|
||||
|
||||
Azkaban 主要通过界面上传配置文件来进行任务的调度。它有两个重要的概念:
|
||||
|
||||
- **Job**: 你需要执行的调度任务;
|
||||
- **Flow**:一个获取多个 Job 及它们之间的依赖关系所组成的图表叫做 Flow。
|
||||
|
||||
目前 Azkaban 3.x 同时支持 Flow 1.0 和 Flow 2.0,本文主要讲解 Flow 1.0 的使用,下一篇文章会讲解 Flow 2.0 的使用。
|
||||
|
||||
## 二、基本任务调度
|
||||
|
||||
### 2.1 新建项目
|
||||
|
||||
在 Azkaban 主界面可以创建对应的项目:
|
||||
|
||||

|
||||
|
||||
### 2.2 任务配置
|
||||
|
||||
新建任务配置文件 `Hello-Azkaban.job`,内容如下。这里的任务很简单,就是输出一句 `'Hello Azkaban!'` :
|
||||
|
||||
```shell
|
||||
#command.job
|
||||
type=command
|
||||
command=echo 'Hello Azkaban!'
|
||||
```
|
||||
|
||||
### 2.3 打包上传
|
||||
|
||||
将 `Hello-Azkaban.job ` 打包为 `zip` 压缩文件:
|
||||
|
||||

|
||||
|
||||
通过 Web UI 界面上传:
|
||||
|
||||

|
||||
|
||||
上传成功后可以看到对应的 Flows:
|
||||
|
||||

|
||||
|
||||
### 2.4 执行任务
|
||||
|
||||
点击页面上的 `Execute Flow` 执行任务:
|
||||
|
||||

|
||||
|
||||
### 2.5 执行结果
|
||||
|
||||
点击 `detail` 可以查看到任务的执行日志:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 三、多任务调度
|
||||
|
||||
### 3.1 依赖配置
|
||||
|
||||
这里假设我们有五个任务(TaskA——TaskE),D 任务需要在 A,B,C 任务执行完成后才能执行,而 E 任务则需要在 D 任务执行完成后才能执行,这种情况下需要使用 `dependencies` 属性定义其依赖关系。各任务配置如下:
|
||||
|
||||
**Task-A.job** :
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=echo 'Task A'
|
||||
```
|
||||
|
||||
**Task-B.job** :
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=echo 'Task B'
|
||||
```
|
||||
|
||||
**Task-C.job** :
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=echo 'Task C'
|
||||
```
|
||||
|
||||
**Task-D.job** :
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=echo 'Task D'
|
||||
dependencies=Task-A,Task-B,Task-C
|
||||
```
|
||||
|
||||
**Task-E.job** :
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=echo 'Task E'
|
||||
dependencies=Task-D
|
||||
```
|
||||
|
||||
### 3.2 压缩上传
|
||||
|
||||
压缩后进行上传,这里需要注意的是一个 Project 只能接收一个压缩包,这里我还沿用上面的 Project,默认后面的压缩包会覆盖前面的压缩包:
|
||||
|
||||

|
||||
|
||||
### 3.3 依赖关系
|
||||
|
||||
多个任务存在依赖时,默认采用最后一个任务的文件名作为 Flow 的名称,其依赖关系如图:
|
||||
|
||||

|
||||
|
||||
### 3.4 执行结果
|
||||
|
||||

|
||||
|
||||
从这个案例可以看出,Flow1.0 无法通过一个 job 文件来完成多个任务的配置,但是 Flow 2.0 就很好的解决了这个问题。
|
||||
|
||||
## 四、调度HDFS作业
|
||||
|
||||
步骤与上面的步骤一致,这里以查看 HDFS 上的文件列表为例。命令建议采用完整路径,配置文件如下:
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=/usr/app/hadoop-2.6.0-cdh5.15.2/bin/hadoop fs -ls /
|
||||
```
|
||||
|
||||
执行结果:
|
||||
|
||||

|
||||
|
||||
## 五、调度MR作业
|
||||
|
||||
MR 作业配置:
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=/usr/app/hadoop-2.6.0-cdh5.15.2/bin/hadoop jar /usr/app/hadoop-2.6.0-cdh5.15.2/share/hadoop/mapreduce/hadoop-mapreduce-examples-2.6.0-cdh5.15.2.jar pi 3 3
|
||||
```
|
||||
|
||||
执行结果:
|
||||
|
||||

|
||||
|
||||
## 六、调度Hive作业
|
||||
|
||||
作业配置:
|
||||
|
||||
```shell
|
||||
type=command
|
||||
command=/usr/app/hive-1.1.0-cdh5.15.2/bin/hive -f 'test.sql'
|
||||
```
|
||||
|
||||
其中 `test.sql` 内容如下,创建一张雇员表,然后查看其结构:
|
||||
|
||||
```sql
|
||||
CREATE DATABASE IF NOT EXISTS hive;
|
||||
use hive;
|
||||
drop table if exists emp;
|
||||
CREATE TABLE emp(
|
||||
empno int,
|
||||
ename string,
|
||||
job string,
|
||||
mgr int,
|
||||
hiredate string,
|
||||
sal double,
|
||||
comm double,
|
||||
deptno int
|
||||
) ROW FORMAT DELIMITED FIELDS TERMINATED BY '\t';
|
||||
-- 查看 emp 表的信息
|
||||
desc emp;
|
||||
```
|
||||
|
||||
打包的时候将 `job` 文件与 `sql` 文件一并进行打包:
|
||||
|
||||

|
||||
|
||||
执行结果如下:
|
||||
|
||||

|
||||
|
||||
## 七、在线修改作业配置
|
||||
|
||||
在测试时,我们可能需要频繁修改配置,如果每次修改都要重新打包上传,这会比较麻烦。所以 Azkaban 支持配置的在线修改,点击需要修改的 Flow,就可以进入详情页面:
|
||||
|
||||

|
||||
|
||||
在详情页面点击 `Eidt` 按钮可以进入编辑页面:
|
||||
|
||||

|
||||
|
||||
在编辑页面可以新增配置或者修改配置:
|
||||
|
||||

|
||||
|
||||
## 附:可能出现的问题
|
||||
|
||||
如果出现以下异常,多半是因为执行主机内存不足,Azkaban 要求执行主机的可用内存必须大于 3G 才能执行任务:
|
||||
|
||||
```shell
|
||||
Cannot request memory (Xms 0 kb, Xmx 0 kb) from system for job
|
||||
```
|
||||
|
||||

|
||||
|
||||
如果你的执行主机没办法增大内存,那么可以通过修改 `plugins/jobtypes/` 目录下的 `commonprivate.properties` 文件来关闭内存检查,配置如下:
|
||||
|
||||
```shell
|
||||
memCheck.enabled=false
|
||||
```
|
||||
|
||||
|
||||
|
@ -1,296 +0,0 @@
|
||||
# Azkaban Flow 2.0的使用
|
||||
|
||||
<nav>
|
||||
<a href="#一Flow-20-简介">一、Flow 2.0 简介</a><br/>
|
||||
<a href="#二YAML语法">二、YAML语法</a><br/>
|
||||
<a href="#三简单任务调度">三、简单任务调度</a><br/>
|
||||
<a href="#四多任务调度">四、多任务调度</a><br/>
|
||||
<a href="#五内嵌流">五、内嵌流</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
## 一、Flow 2.0 简介
|
||||
|
||||
### 1.1 Flow 2.0 的产生
|
||||
|
||||
Azkaban 目前同时支持 Flow 1.0 和 Flow2.0 ,但是官方文档上更推荐使用 Flow 2.0,因为 Flow 1.0 会在将来的版本被移除。Flow 2.0 的主要设计思想是提供 1.0 所没有的流级定义。用户可以将属于给定流的所有 `job / properties` 文件合并到单个流定义文件中,其内容采用 YAML 语法进行定义,同时还支持在流中再定义流,称为为嵌入流或子流。
|
||||
|
||||
### 1.2 基本结构
|
||||
|
||||
项目 zip 将包含多个流 YAML 文件,一个项目 YAML 文件以及可选库和源代码。Flow YAML 文件的基本结构如下:
|
||||
|
||||
+ 每个 Flow 都在单个 YAML 文件中定义;
|
||||
+ 流文件以流名称命名,如:`my-flow-name.flow`;
|
||||
+ 包含 DAG 中的所有节点;
|
||||
+ 每个节点可以是作业或流程;
|
||||
+ 每个节点 可以拥有 name, type, config, dependsOn 和 nodes sections 等属性;
|
||||
+ 通过列出 dependsOn 列表中的父节点来指定节点依赖性;
|
||||
+ 包含与流相关的其他配置;
|
||||
+ 当前 properties 文件中流的所有常见属性都将迁移到每个流 YAML 文件中的 config 部分。
|
||||
|
||||
官方提供了一个比较完善的配置样例,如下:
|
||||
|
||||
```yaml
|
||||
config:
|
||||
user.to.proxy: azktest
|
||||
param.hadoopOutData: /tmp/wordcounthadoopout
|
||||
param.inData: /tmp/wordcountpigin
|
||||
param.outData: /tmp/wordcountpigout
|
||||
|
||||
# This section defines the list of jobs
|
||||
# A node can be a job or a flow
|
||||
# In this example, all nodes are jobs
|
||||
nodes:
|
||||
# Job definition
|
||||
# The job definition is like a YAMLified version of properties file
|
||||
# with one major difference. All custom properties are now clubbed together
|
||||
# in a config section in the definition.
|
||||
# The first line describes the name of the job
|
||||
- name: AZTest
|
||||
type: noop
|
||||
# The dependsOn section contains the list of parent nodes the current
|
||||
# node depends on
|
||||
dependsOn:
|
||||
- hadoopWC1
|
||||
- NoOpTest1
|
||||
- hive2
|
||||
- java1
|
||||
- jobCommand2
|
||||
|
||||
- name: pigWordCount1
|
||||
type: pig
|
||||
# The config section contains custom arguments or parameters which are
|
||||
# required by the job
|
||||
config:
|
||||
pig.script: src/main/pig/wordCountText.pig
|
||||
|
||||
- name: hadoopWC1
|
||||
type: hadoopJava
|
||||
dependsOn:
|
||||
- pigWordCount1
|
||||
config:
|
||||
classpath: ./*
|
||||
force.output.overwrite: true
|
||||
input.path: ${param.inData}
|
||||
job.class: com.linkedin.wordcount.WordCount
|
||||
main.args: ${param.inData} ${param.hadoopOutData}
|
||||
output.path: ${param.hadoopOutData}
|
||||
|
||||
- name: hive1
|
||||
type: hive
|
||||
config:
|
||||
hive.script: src/main/hive/showdb.q
|
||||
|
||||
- name: NoOpTest1
|
||||
type: noop
|
||||
|
||||
- name: hive2
|
||||
type: hive
|
||||
dependsOn:
|
||||
- hive1
|
||||
config:
|
||||
hive.script: src/main/hive/showTables.sql
|
||||
|
||||
- name: java1
|
||||
type: javaprocess
|
||||
config:
|
||||
Xms: 96M
|
||||
java.class: com.linkedin.foo.HelloJavaProcessJob
|
||||
|
||||
- name: jobCommand1
|
||||
type: command
|
||||
config:
|
||||
command: echo "hello world from job_command_1"
|
||||
|
||||
- name: jobCommand2
|
||||
type: command
|
||||
dependsOn:
|
||||
- jobCommand1
|
||||
config:
|
||||
command: echo "hello world from job_command_2"
|
||||
```
|
||||
|
||||
## 二、YAML语法
|
||||
|
||||
想要使用 Flow 2.0 进行工作流的配置,首先需要了解 YAML 。YAML 是一种简洁的非标记语言,有着严格的格式要求的,如果你的格式配置失败,上传到 Azkaban 的时候就会抛出解析异常。
|
||||
|
||||
### 2.1 基本规则
|
||||
|
||||
1. 大小写敏感 ;
|
||||
2. 使用缩进表示层级关系 ;
|
||||
3. 缩进长度没有限制,只要元素对齐就表示这些元素属于一个层级;
|
||||
4. 使用#表示注释 ;
|
||||
5. 字符串默认不用加单双引号,但单引号和双引号都可以使用,双引号表示不需要对特殊字符进行转义;
|
||||
6. YAML 中提供了多种常量结构,包括:整数,浮点数,字符串,NULL,日期,布尔,时间。
|
||||
|
||||
### 2.2 对象的写法
|
||||
|
||||
```yaml
|
||||
# value 与 : 符号之间必须要有一个空格
|
||||
key: value
|
||||
```
|
||||
|
||||
### 2.3 map的写法
|
||||
|
||||
```yaml
|
||||
# 写法一 同一缩进的所有键值对属于一个map
|
||||
key:
|
||||
key1: value1
|
||||
key2: value2
|
||||
|
||||
# 写法二
|
||||
{key1: value1, key2: value2}
|
||||
```
|
||||
|
||||
### 2.3 数组的写法
|
||||
|
||||
```yaml
|
||||
# 写法一 使用一个短横线加一个空格代表一个数组项
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
|
||||
# 写法二
|
||||
[a,b,c]
|
||||
```
|
||||
|
||||
### 2.5 单双引号
|
||||
|
||||
支持单引号和双引号,但双引号不会对特殊字符进行转义:
|
||||
|
||||
```yaml
|
||||
s1: '内容\n 字符串'
|
||||
s2: "内容\n 字符串"
|
||||
|
||||
转换后:
|
||||
{ s1: '内容\\n 字符串', s2: '内容\n 字符串' }
|
||||
```
|
||||
|
||||
### 2.6 特殊符号
|
||||
|
||||
一个 YAML 文件中可以包括多个文档,使用 `---` 进行分割。
|
||||
|
||||
### 2.7 配置引用
|
||||
|
||||
Flow 2.0 建议将公共参数定义在 `config` 下,并通过 `${}` 进行引用。
|
||||
|
||||
|
||||
|
||||
## 三、简单任务调度
|
||||
|
||||
### 3.1 任务配置
|
||||
|
||||
新建 `flow` 配置文件:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- name: jobA
|
||||
type: command
|
||||
config:
|
||||
command: echo "Hello Azkaban Flow 2.0."
|
||||
```
|
||||
|
||||
在当前的版本中,Azkaban 同时支持 Flow 1.0 和 Flow 2.0,如果你希望以 2.0 的方式运行,则需要新建一个 `project` 文件,指明是使用的是 Flow 2.0:
|
||||
|
||||
```shell
|
||||
azkaban-flow-version: 2.0
|
||||
```
|
||||
|
||||
### 3.2 打包上传
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 3.3 执行结果
|
||||
|
||||
由于在 1.0 版本中已经介绍过 Web UI 的使用,这里就不再赘述。对于 1.0 和 2.0 版本,只有配置方式有所不同,其他上传执行的方式都是相同的。执行结果如下:
|
||||
|
||||

|
||||
|
||||
## 四、多任务调度
|
||||
|
||||
和 1.0 给出的案例一样,这里假设我们有五个任务(jobA——jobE), D 任务需要在 A,B,C 任务执行完成后才能执行,而 E 任务则需要在 D 任务执行完成后才能执行,相关配置文件应如下。可以看到在 1.0 中我们需要分别定义五个配置文件,而在 2.0 中我们只需要一个配置文件即可完成配置。
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- name: jobE
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job E"
|
||||
# jobE depends on jobD
|
||||
dependsOn:
|
||||
- jobD
|
||||
|
||||
- name: jobD
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job D"
|
||||
# jobD depends on jobA、jobB、jobC
|
||||
dependsOn:
|
||||
- jobA
|
||||
- jobB
|
||||
- jobC
|
||||
|
||||
- name: jobA
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job A"
|
||||
|
||||
- name: jobB
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job B"
|
||||
|
||||
- name: jobC
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job C"
|
||||
```
|
||||
|
||||
## 五、内嵌流
|
||||
|
||||
Flow2.0 支持在一个 Flow 中定义另一个 Flow,称为内嵌流或者子流。这里给出一个内嵌流的示例,其 `Flow` 配置如下:
|
||||
|
||||
```yaml
|
||||
nodes:
|
||||
- name: jobC
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job C"
|
||||
dependsOn:
|
||||
- embedded_flow
|
||||
|
||||
- name: embedded_flow
|
||||
type: flow
|
||||
config:
|
||||
prop: value
|
||||
nodes:
|
||||
- name: jobB
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job B"
|
||||
dependsOn:
|
||||
- jobA
|
||||
|
||||
- name: jobA
|
||||
type: command
|
||||
config:
|
||||
command: echo "This is job A"
|
||||
```
|
||||
|
||||
内嵌流的 DAG 图如下:
|
||||
|
||||

|
||||
|
||||
执行情况如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
1. [Azkaban Flow 2.0 Design](https://github.com/azkaban/azkaban/wiki/Azkaban-Flow-2.0-Design)
|
||||
2. [Getting started with Azkaban Flow 2.0](https://github.com/azkaban/azkaban/wiki/Getting-started-with-Azkaban-Flow-2.0)
|
||||
|
@ -1,76 +0,0 @@
|
||||
# Azkaban简介
|
||||
|
||||
|
||||
## 一、Azkaban 介绍
|
||||
|
||||
#### 1.1 背景
|
||||
|
||||
一个完整的大数据分析系统,必然由很多任务单元 (如数据收集、数据清洗、数据存储、数据分析等) 组成,所有的任务单元及其之间的依赖关系组成了复杂的工作流。复杂的工作流管理涉及到很多问题:
|
||||
|
||||
- 如何定时调度某个任务?
|
||||
- 如何在某个任务执行完成后再去执行另一个任务?
|
||||
- 如何在任务失败时候发出预警?
|
||||
- ......
|
||||
|
||||
面对这些问题,工作流调度系统应运而生。Azkaban 就是其中之一。
|
||||
|
||||
#### 1.2 功能
|
||||
|
||||
Azkaban 产生于 LinkedIn,并经过多年生产环境的检验,它具备以下功能:
|
||||
|
||||
- 兼容任何版本的 Hadoop
|
||||
- 易于使用的 Web UI
|
||||
- 可以使用简单的 Web 页面进行工作流上传
|
||||
- 支持按项目进行独立管理
|
||||
- 定时任务调度
|
||||
- 模块化和可插入
|
||||
- 身份验证和授权
|
||||
- 跟踪用户操作
|
||||
- 支持失败和成功的电子邮件提醒
|
||||
- SLA 警报和自动查杀失败任务
|
||||
- 重试失败的任务
|
||||
|
||||
Azkaban 的设计理念是在保证功能实现的基础上兼顾易用性,其页面风格清晰明朗,下面是其 WEB UI 界面:
|
||||
|
||||

|
||||
|
||||
## 二、Azkaban 和 Oozie
|
||||
|
||||
Azkaban 和 Oozie 都是目前使用最为广泛的工作流调度程序,其主要区别如下:
|
||||
|
||||
#### 功能对比
|
||||
|
||||
- 两者均可以调度 Linux 命令、MapReduce、Spark、Pig、Java、Hive 等工作流任务;
|
||||
- 两者均可以定时执行工作流任务。
|
||||
|
||||
#### 工作流定义
|
||||
|
||||
- Azkaban 使用 Properties(Flow 1.0) 和 YAML(Flow 2.0) 文件定义工作流;
|
||||
- Oozie 使用 Hadoop 流程定义语言(hadoop process defination language,HPDL)来描述工作流,HPDL 是一种 XML 流程定义语言。
|
||||
|
||||
#### 资源管理
|
||||
|
||||
- Azkaban 有较严格的权限控制,如用户对工作流进行读/写/执行等操作;
|
||||
- Oozie 暂无严格的权限控制。
|
||||
|
||||
#### 运行模式
|
||||
|
||||
+ Azkaban 3.x 提供了两种运行模式:
|
||||
+ **solo server model(单服务模式)** :元数据默认存放在内置的 H2 数据库(可以修改为 MySQL),该模式中 `webServer`(管理服务器) 和 `executorServer`(执行服务器) 运行在同一个进程中,进程名是 `AzkabanSingleServer`。该模式适用于小规模工作流的调度。
|
||||
+ **multiple-executor(分布式多服务模式)** :存放元数据的数据库为 MySQL,MySQL 应采用主从模式进行备份和容错。这种模式下 `webServer` 和 `executorServer` 在不同进程中运行,彼此之间互不影响,适合用于生产环境。
|
||||
|
||||
+ Oozie 使用 Tomcat 等 Web 容器来展示 Web 页面,默认使用 derby 存储工作流的元数据,由于 derby 过于轻量,实际使用中通常用 MySQL 代替。
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
## 三、总结
|
||||
|
||||
如果你的工作流不是特别复杂,推荐使用轻量级的 Azkaban,主要有以下原因:
|
||||
|
||||
+ **安装方面**:Azkaban 3.0 之前都是提供安装包的,直接解压部署即可。Azkaban 3.0 之后的版本需要编译,这个编译是基于 gradle 的,自动化程度比较高;
|
||||
+ **页面设计**:所有任务的依赖关系、执行结果、执行日志都可以从界面上直观查看到;
|
||||
+ **配置方面**:Azkaban Flow 1.0 基于 Properties 文件来定义工作流,这个时候的限制可能会多一点。但是在 Flow 2.0 就支持了 YARM。YARM 语法更加灵活简单,著名的微服务框架 Spring Boot 就采用的 YAML 代替了繁重的 XML。
|
||||
|
||||
|
@ -1,268 +0,0 @@
|
||||
# Flink Sink
|
||||
<nav>
|
||||
<a href="#一Data-Sinks">一、Data Sinks</a><br/>
|
||||
<a href="#11-writeAsText">1.1 writeAsText</a><br/>
|
||||
<a href="#12-writeAsCsv">1.2 writeAsCsv</a><br/>
|
||||
<a href="#13-print--printToErr">1.3 print printToErr</a><br/>
|
||||
<a href="#14-writeUsingOutputFormat">1.4 writeUsingOutputFormat</a><br/>
|
||||
<a href="#15-writeToSocket">1.5 writeToSocket</a><br/>
|
||||
<a href="#二Streaming-Connectors">二、Streaming Connectors</a><br/>
|
||||
<a href="#三整合-Kafka-Sink">三、整合 Kafka Sink</a><br/>
|
||||
<a href="#31-addSink">3.1 addSink</a><br/>
|
||||
<a href="#32-创建输出主题">3.2 创建输出主题</a><br/>
|
||||
<a href="#33-启动消费者">3.3 启动消费者</a><br/>
|
||||
<a href="#34-测试结果">3.4 测试结果</a><br/>
|
||||
<a href="#四自定义-Sink">四、自定义 Sink</a><br/>
|
||||
<a href="#41-导入依赖">4.1 导入依赖</a><br/>
|
||||
<a href="#42-自定义-Sink">4.2 自定义 Sink</a><br/>
|
||||
<a href="#43-使用自定义-Sink">4.3 使用自定义 Sink</a><br/>
|
||||
<a href="#44-测试结果">4.4 测试结果</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
## 一、Data Sinks
|
||||
|
||||
在使用 Flink 进行数据处理时,数据经 Data Source 流入,然后通过系列 Transformations 的转化,最终可以通过 Sink 将计算结果进行输出,Flink Data Sinks 就是用于定义数据流最终的输出位置。Flink 提供了几个较为简单的 Sink API 用于日常的开发,具体如下:
|
||||
|
||||
### 1.1 writeAsText
|
||||
|
||||
`writeAsText` 用于将计算结果以文本的方式并行地写入到指定文件夹下,除了路径参数是必选外,该方法还可以通过指定第二个参数来定义输出模式,它有以下两个可选值:
|
||||
|
||||
+ **WriteMode.NO_OVERWRITE**:当指定路径上不存在任何文件时,才执行写出操作;
|
||||
+ **WriteMode.OVERWRITE**:不论指定路径上是否存在文件,都执行写出操作;如果原来已有文件,则进行覆盖。
|
||||
|
||||
使用示例如下:
|
||||
|
||||
```java
|
||||
streamSource.writeAsText("D:\\out", FileSystem.WriteMode.OVERWRITE);
|
||||
```
|
||||
|
||||
以上写出是以并行的方式写出到多个文件,如果想要将输出结果全部写出到一个文件,需要设置其并行度为 1:
|
||||
|
||||
```java
|
||||
streamSource.writeAsText("D:\\out", FileSystem.WriteMode.OVERWRITE).setParallelism(1);
|
||||
```
|
||||
|
||||
### 1.2 writeAsCsv
|
||||
|
||||
`writeAsCsv` 用于将计算结果以 CSV 的文件格式写出到指定目录,除了路径参数是必选外,该方法还支持传入输出模式,行分隔符,和字段分隔符三个额外的参数,其方法定义如下:
|
||||
|
||||
```java
|
||||
writeAsCsv(String path, WriteMode writeMode, String rowDelimiter, String fieldDelimiter)
|
||||
```
|
||||
|
||||
### 1.3 print \ printToErr
|
||||
|
||||
`print \ printToErr` 是测试当中最常用的方式,用于将计算结果以标准输出流或错误输出流的方式打印到控制台上。
|
||||
|
||||
### 1.4 writeUsingOutputFormat
|
||||
|
||||
采用自定义的输出格式将计算结果写出,上面介绍的 `writeAsText` 和 `writeAsCsv` 其底层调用的都是该方法,源码如下:
|
||||
|
||||
```java
|
||||
public DataStreamSink<T> writeAsText(String path, WriteMode writeMode) {
|
||||
TextOutputFormat<T> tof = new TextOutputFormat<>(new Path(path));
|
||||
tof.setWriteMode(writeMode);
|
||||
return writeUsingOutputFormat(tof);
|
||||
}
|
||||
```
|
||||
|
||||
### 1.5 writeToSocket
|
||||
|
||||
`writeToSocket` 用于将计算结果以指定的格式写出到 Socket 中,使用示例如下:
|
||||
|
||||
```shell
|
||||
streamSource.writeToSocket("192.168.0.226", 9999, new SimpleStringSchema());
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 二、Streaming Connectors
|
||||
|
||||
除了上述 API 外,Flink 中还内置了系列的 Connectors 连接器,用于将计算结果输入到常用的存储系统或者消息中间件中,具体如下:
|
||||
|
||||
- Apache Kafka (支持 source 和 sink)
|
||||
- Apache Cassandra (sink)
|
||||
- Amazon Kinesis Streams (source/sink)
|
||||
- Elasticsearch (sink)
|
||||
- Hadoop FileSystem (sink)
|
||||
- RabbitMQ (source/sink)
|
||||
- Apache NiFi (source/sink)
|
||||
- Google PubSub (source/sink)
|
||||
|
||||
除了内置的连接器外,你还可以通过 Apache Bahir 的连接器扩展 Flink。Apache Bahir 旨在为分布式数据分析系统 (如 Spark,Flink) 等提供功能上的扩展,当前其支持的与 Flink Sink 相关的连接器如下:
|
||||
|
||||
- Apache ActiveMQ (source/sink)
|
||||
- Apache Flume (sink)
|
||||
- Redis (sink)
|
||||
- Akka (sink)
|
||||
|
||||
这里接着在 Data Sources 章节介绍的整合 Kafka Source 的基础上,将 Kafka Sink 也一并进行整合,具体步骤如下。
|
||||
|
||||
|
||||
|
||||
## 三、整合 Kafka Sink
|
||||
|
||||
### 3.1 addSink
|
||||
|
||||
Flink 提供了 addSink 方法用来调用自定义的 Sink 或者第三方的连接器,想要将计算结果写出到 Kafka,需要使用该方法来调用 Kafka 的生产者 FlinkKafkaProducer,具体代码如下:
|
||||
|
||||
```java
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
|
||||
// 1.指定Kafka的相关配置属性
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("bootstrap.servers", "192.168.200.0:9092");
|
||||
|
||||
// 2.接收Kafka上的数据
|
||||
DataStream<String> stream = env
|
||||
.addSource(new FlinkKafkaConsumer<>("flink-stream-in-topic", new SimpleStringSchema(), properties));
|
||||
|
||||
// 3.定义计算结果到 Kafka ProducerRecord 的转换
|
||||
KafkaSerializationSchema<String> kafkaSerializationSchema = new KafkaSerializationSchema<String>() {
|
||||
@Override
|
||||
public ProducerRecord<byte[], byte[]> serialize(String element, @Nullable Long timestamp) {
|
||||
return new ProducerRecord<>("flink-stream-out-topic", element.getBytes());
|
||||
}
|
||||
};
|
||||
// 4. 定义Flink Kafka生产者
|
||||
FlinkKafkaProducer<String> kafkaProducer = new FlinkKafkaProducer<>("flink-stream-out-topic",
|
||||
kafkaSerializationSchema,
|
||||
properties,
|
||||
FlinkKafkaProducer.Semantic.AT_LEAST_ONCE, 5);
|
||||
// 5. 将接收到输入元素*2后写出到Kafka
|
||||
stream.map((MapFunction<String, String>) value -> value + value).addSink(kafkaProducer);
|
||||
env.execute("Flink Streaming");
|
||||
```
|
||||
|
||||
### 3.2 创建输出主题
|
||||
|
||||
创建用于输出测试的主题:
|
||||
|
||||
```shell
|
||||
bin/kafka-topics.sh --create \
|
||||
--bootstrap-server hadoop001:9092 \
|
||||
--replication-factor 1 \
|
||||
--partitions 1 \
|
||||
--topic flink-stream-out-topic
|
||||
|
||||
# 查看所有主题
|
||||
bin/kafka-topics.sh --list --bootstrap-server hadoop001:9092
|
||||
```
|
||||
|
||||
### 3.3 启动消费者
|
||||
|
||||
启动一个 Kafka 消费者,用于查看 Flink 程序的输出情况:
|
||||
|
||||
```java
|
||||
bin/kafka-console-consumer.sh --bootstrap-server hadoop001:9092 --topic flink-stream-out-topic
|
||||
```
|
||||
|
||||
### 3.4 测试结果
|
||||
|
||||
在 Kafka 生产者上发送消息到 Flink 程序,观察 Flink 程序转换后的输出情况,具体如下:
|
||||
|
||||

|
||||
|
||||
|
||||
可以看到 Kafka 生成者发出的数据已经被 Flink 程序正常接收到,并经过转换后又输出到 Kafka 对应的 Topic 上。
|
||||
|
||||
## 四、自定义 Sink
|
||||
|
||||
除了使用内置的第三方连接器外,Flink 还支持使用自定义的 Sink 来满足多样化的输出需求。想要实现自定义的 Sink ,需要直接或者间接实现 SinkFunction 接口。通常情况下,我们都是实现其抽象类 RichSinkFunction,相比于 SinkFunction ,其提供了更多的与生命周期相关的方法。两者间的关系如下:
|
||||
|
||||

|
||||
|
||||
|
||||
这里我们以自定义一个 FlinkToMySQLSink 为例,将计算结果写出到 MySQL 数据库中,具体步骤如下:
|
||||
|
||||
### 4.1 导入依赖
|
||||
|
||||
首先需要导入 MySQL 相关的依赖:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.16</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
### 4.2 自定义 Sink
|
||||
|
||||
继承自 RichSinkFunction,实现自定义的 Sink :
|
||||
|
||||
```java
|
||||
public class FlinkToMySQLSink extends RichSinkFunction<Employee> {
|
||||
|
||||
private PreparedStatement stmt;
|
||||
private Connection conn;
|
||||
|
||||
@Override
|
||||
public void open(Configuration parameters) throws Exception {
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
conn = DriverManager.getConnection("jdbc:mysql://192.168.0.229:3306/employees" +
|
||||
"?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false",
|
||||
"root",
|
||||
"123456");
|
||||
String sql = "insert into emp(name, age, birthday) values(?, ?, ?)";
|
||||
stmt = conn.prepareStatement(sql);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invoke(Employee value, Context context) throws Exception {
|
||||
stmt.setString(1, value.getName());
|
||||
stmt.setInt(2, value.getAge());
|
||||
stmt.setDate(3, value.getBirthday());
|
||||
stmt.executeUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
super.close();
|
||||
if (stmt != null) {
|
||||
stmt.close();
|
||||
}
|
||||
if (conn != null) {
|
||||
conn.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
### 4.3 使用自定义 Sink
|
||||
|
||||
想要使用自定义的 Sink,同样是需要调用 addSink 方法,具体如下:
|
||||
|
||||
```java
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
Date date = new Date(System.currentTimeMillis());
|
||||
DataStreamSource<Employee> streamSource = env.fromElements(
|
||||
new Employee("hei", 10, date),
|
||||
new Employee("bai", 20, date),
|
||||
new Employee("ying", 30, date));
|
||||
streamSource.addSink(new FlinkToMySQLSink());
|
||||
env.execute();
|
||||
```
|
||||
|
||||
### 4.4 测试结果
|
||||
|
||||
启动程序,观察数据库写入情况:
|
||||
|
||||

|
||||
|
||||
|
||||
数据库成功写入,代表自定义 Sink 整合成功。
|
||||
|
||||
> 以上所有用例的源码见本仓库:[flink-kafka-integration]( https://github.com/heibaiying/BigData-Notes/tree/master/code/Flink/flink-kafka-integration)
|
||||
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
1. data-sinks: https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/datastream_api.html#data-sinks
|
||||
2. Streaming Connectors:https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/connectors/index.html
|
||||
3. Apache Kafka Connector: https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/connectors/kafka.html
|
||||
|
@ -1,284 +0,0 @@
|
||||
# Flink Data Source
|
||||
<nav>
|
||||
<a href="#一内置-Data-Source">一、内置 Data Source</a><br/>
|
||||
<a href="#11-基于文件构建">1.1 基于文件构建</a><br/>
|
||||
<a href="#12-基于集合构建">1.2 基于集合构建</a><br/>
|
||||
<a href="#13--基于-Socket-构建">1.3 基于 Socket 构建</a><br/>
|
||||
<a href="#二自定义-Data-Source">二、自定义 Data Source</a><br/>
|
||||
<a href="#21-SourceFunction">2.1 SourceFunction</a><br/>
|
||||
<a href="#22-ParallelSourceFunction-和-RichParallelSourceFunction">2.2 ParallelSourceFunction 和 RichParallelSourceFunction</a><br/>
|
||||
<a href="#三Streaming-Connectors">三、Streaming Connectors</a><br/>
|
||||
<a href="#31-内置连接器">3.1 内置连接器</a><br/>
|
||||
<a href="#32-整合-Kakfa">3.2 整合 Kakfa</a><br/>
|
||||
<a href="#33-整合测试">3.3 整合测试</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
## 一、内置 Data Source
|
||||
|
||||
Flink Data Source 用于定义 Flink 程序的数据来源,Flink 官方提供了多种数据获取方法,用于帮助开发者简单快速地构建输入流,具体如下:
|
||||
|
||||
### 1.1 基于文件构建
|
||||
|
||||
**1. readTextFile(path)**:按照 TextInputFormat 格式读取文本文件,并将其内容以字符串的形式返回。示例如下:
|
||||
|
||||
```java
|
||||
env.readTextFile(filePath).print();
|
||||
```
|
||||
|
||||
**2. readFile(fileInputFormat, path)** :按照指定格式读取文件。
|
||||
|
||||
**3. readFile(inputFormat, filePath, watchType, interval, typeInformation)**:按照指定格式周期性的读取文件。其中各个参数的含义如下:
|
||||
|
||||
+ **inputFormat**:数据流的输入格式。
|
||||
+ **filePath**:文件路径,可以是本地文件系统上的路径,也可以是 HDFS 上的文件路径。
|
||||
+ **watchType**:读取方式,它有两个可选值,分别是 `FileProcessingMode.PROCESS_ONCE` 和 `FileProcessingMode.PROCESS_CONTINUOUSLY`:前者表示对指定路径上的数据只读取一次,然后退出;后者表示对路径进行定期地扫描和读取。需要注意的是如果 watchType 被设置为 `PROCESS_CONTINUOUSLY`,那么当文件被修改时,其所有的内容 (包含原有的内容和新增的内容) 都将被重新处理,因此这会打破 Flink 的 *exactly-once* 语义。
|
||||
+ **interval**:定期扫描的时间间隔。
|
||||
+ **typeInformation**:输入流中元素的类型。
|
||||
|
||||
使用示例如下:
|
||||
|
||||
```java
|
||||
final String filePath = "D:\\log4j.properties";
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
env.readFile(new TextInputFormat(new Path(filePath)),
|
||||
filePath,
|
||||
FileProcessingMode.PROCESS_ONCE,
|
||||
1,
|
||||
BasicTypeInfo.STRING_TYPE_INFO).print();
|
||||
env.execute();
|
||||
```
|
||||
|
||||
### 1.2 基于集合构建
|
||||
|
||||
**1. fromCollection(Collection)**:基于集合构建,集合中的所有元素必须是同一类型。示例如下:
|
||||
|
||||
```java
|
||||
env.fromCollection(Arrays.asList(1,2,3,4,5)).print();
|
||||
```
|
||||
|
||||
**2. fromElements(T ...)**: 基于元素构建,所有元素必须是同一类型。示例如下:
|
||||
|
||||
```java
|
||||
env.fromElements(1,2,3,4,5).print();
|
||||
```
|
||||
**3. generateSequence(from, to)**:基于给定的序列区间进行构建。示例如下:
|
||||
|
||||
```java
|
||||
env.generateSequence(0,100);
|
||||
```
|
||||
|
||||
**4. fromCollection(Iterator, Class)**:基于迭代器进行构建。第一个参数用于定义迭代器,第二个参数用于定义输出元素的类型。使用示例如下:
|
||||
|
||||
```java
|
||||
env.fromCollection(new CustomIterator(), BasicTypeInfo.INT_TYPE_INFO).print();
|
||||
```
|
||||
|
||||
其中 CustomIterator 为自定义的迭代器,这里以产生 1 到 100 区间内的数据为例,源码如下。需要注意的是自定义迭代器除了要实现 Iterator 接口外,还必须要实现序列化接口 Serializable ,否则会抛出序列化失败的异常:
|
||||
|
||||
```java
|
||||
import java.io.Serializable;
|
||||
import java.util.Iterator;
|
||||
|
||||
public class CustomIterator implements Iterator<Integer>, Serializable {
|
||||
private Integer i = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext() {
|
||||
return i < 100;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer next() {
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**5. fromParallelCollection(SplittableIterator, Class)**:方法接收两个参数,第二个参数用于定义输出元素的类型,第一个参数 SplittableIterator 是迭代器的抽象基类,它用于将原始迭代器的值拆分到多个不相交的迭代器中。
|
||||
|
||||
### 1.3 基于 Socket 构建
|
||||
|
||||
Flink 提供了 socketTextStream 方法用于构建基于 Socket 的数据流,socketTextStream 方法有以下四个主要参数:
|
||||
|
||||
- **hostname**:主机名;
|
||||
- **port**:端口号,设置为 0 时,表示端口号自动分配;
|
||||
- **delimiter**:用于分隔每条记录的分隔符;
|
||||
- **maxRetry**:当 Socket 临时关闭时,程序的最大重试间隔,单位为秒。设置为 0 时表示不进行重试;设置为负值则表示一直重试。示例如下:
|
||||
|
||||
```shell
|
||||
env.socketTextStream("192.168.0.229", 9999, "\n", 3).print();
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 二、自定义 Data Source
|
||||
|
||||
### 2.1 SourceFunction
|
||||
|
||||
除了内置的数据源外,用户还可以使用 `addSource` 方法来添加自定义的数据源。自定义的数据源必须要实现 SourceFunction 接口,这里以产生 [0 , 1000) 区间内的数据为例,代码如下:
|
||||
|
||||
```java
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
|
||||
env.addSource(new SourceFunction<Long>() {
|
||||
|
||||
private long count = 0L;
|
||||
private volatile boolean isRunning = true;
|
||||
|
||||
public void run(SourceContext<Long> ctx) {
|
||||
while (isRunning && count < 1000) {
|
||||
// 通过collect将输入发送出去
|
||||
ctx.collect(count);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
isRunning = false;
|
||||
}
|
||||
|
||||
}).print();
|
||||
env.execute();
|
||||
```
|
||||
|
||||
### 2.2 ParallelSourceFunction 和 RichParallelSourceFunction
|
||||
|
||||
上面通过 SourceFunction 实现的数据源是不具有并行度的,即不支持在得到的 DataStream 上调用 `setParallelism(n)` 方法,此时会抛出如下的异常:
|
||||
|
||||
```shell
|
||||
Exception in thread "main" java.lang.IllegalArgumentException: Source: 1 is not a parallel source
|
||||
```
|
||||
|
||||
如果你想要实现具有并行度的输入流,则需要实现 ParallelSourceFunction 或 RichParallelSourceFunction 接口,其与 SourceFunction 的关系如下图:
|
||||
|
||||

|
||||
ParallelSourceFunction 直接继承自 ParallelSourceFunction,具有并行度的功能。RichParallelSourceFunction 则继承自 AbstractRichFunction,同时实现了 ParallelSourceFunction 接口,所以其除了具有并行度的功能外,还提供了额外的与生命周期相关的方法,如 open() ,closen() 。
|
||||
|
||||
## 三、Streaming Connectors
|
||||
|
||||
### 3.1 内置连接器
|
||||
|
||||
除了自定义数据源外, Flink 还内置了多种连接器,用于满足大多数的数据收集场景。当前内置连接器的支持情况如下:
|
||||
|
||||
- Apache Kafka (支持 source 和 sink)
|
||||
- Apache Cassandra (sink)
|
||||
- Amazon Kinesis Streams (source/sink)
|
||||
- Elasticsearch (sink)
|
||||
- Hadoop FileSystem (sink)
|
||||
- RabbitMQ (source/sink)
|
||||
- Apache NiFi (source/sink)
|
||||
- Twitter Streaming API (source)
|
||||
- Google PubSub (source/sink)
|
||||
|
||||
除了上述的连接器外,你还可以通过 Apache Bahir 的连接器扩展 Flink。Apache Bahir 旨在为分布式数据分析系统 (如 Spark,Flink) 等提供功能上的扩展,当前其支持的与 Flink 相关的连接器如下:
|
||||
|
||||
- Apache ActiveMQ (source/sink)
|
||||
- Apache Flume (sink)
|
||||
- Redis (sink)
|
||||
- Akka (sink)
|
||||
- Netty (source)
|
||||
|
||||
随着 Flink 的不断发展,可以预见到其会支持越来越多类型的连接器,关于连接器的后续发展情况,可以查看其官方文档:[Streaming Connectors]( https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/connectors/index.html) 。在所有 DataSource 连接器中,使用的广泛的就是 Kafka,所以这里我们以其为例,来介绍 Connectors 的整合步骤。
|
||||
|
||||
### 3.2 整合 Kakfa
|
||||
|
||||
#### 1. 导入依赖
|
||||
|
||||
整合 Kafka 时,一定要注意所使用的 Kafka 的版本,不同版本间所需的 Maven 依赖和开发时所调用的类均不相同,具体如下:
|
||||
|
||||
| Maven 依赖 | Flink 版本 | Consumer and Producer 类的名称 | Kafka 版本 |
|
||||
| :------------------------------ | :--------- | :----------------------------------------------- | :--------- |
|
||||
| flink-connector-kafka-0.8_2.11 | 1.0.0 + | FlinkKafkaConsumer08 <br/>FlinkKafkaProducer08 | 0.8.x |
|
||||
| flink-connector-kafka-0.9_2.11 | 1.0.0 + | FlinkKafkaConsumer09<br/> FlinkKafkaProducer09 | 0.9.x |
|
||||
| flink-connector-kafka-0.10_2.11 | 1.2.0 + | FlinkKafkaConsumer010 <br/>FlinkKafkaProducer010 | 0.10.x |
|
||||
| flink-connector-kafka-0.11_2.11 | 1.4.0 + | FlinkKafkaConsumer011 <br/>FlinkKafkaProducer011 | 0.11.x |
|
||||
| flink-connector-kafka_2.11 | 1.7.0 + | FlinkKafkaConsumer <br/>FlinkKafkaProducer | >= 1.0.0 |
|
||||
|
||||
这里我使用的 Kafka 版本为 kafka_2.12-2.2.0,添加的依赖如下:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-connector-kafka_2.11</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
#### 2. 代码开发
|
||||
|
||||
这里以最简单的场景为例,接收 Kafka 上的数据并打印,代码如下:
|
||||
|
||||
```java
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
Properties properties = new Properties();
|
||||
// 指定Kafka的连接位置
|
||||
properties.setProperty("bootstrap.servers", "hadoop001:9092");
|
||||
// 指定监听的主题,并定义Kafka字节消息到Flink对象之间的转换规则
|
||||
DataStream<String> stream = env
|
||||
.addSource(new FlinkKafkaConsumer<>("flink-stream-in-topic", new SimpleStringSchema(), properties));
|
||||
stream.print();
|
||||
env.execute("Flink Streaming");
|
||||
```
|
||||
|
||||
### 3.3 整合测试
|
||||
|
||||
#### 1. 启动 Kakfa
|
||||
|
||||
Kafka 的运行依赖于 zookeeper,需要预先启动,可以启动 Kafka 内置的 zookeeper,也可以启动自己安装的:
|
||||
|
||||
```shell
|
||||
# zookeeper启动命令
|
||||
bin/zkServer.sh start
|
||||
|
||||
# 内置zookeeper启动命令
|
||||
bin/zookeeper-server-start.sh config/zookeeper.properties
|
||||
```
|
||||
|
||||
启动单节点 kafka 用于测试:
|
||||
|
||||
```shell
|
||||
# bin/kafka-server-start.sh config/server.properties
|
||||
```
|
||||
|
||||
#### 2. 创建 Topic
|
||||
|
||||
```shell
|
||||
# 创建用于测试主题
|
||||
bin/kafka-topics.sh --create \
|
||||
--bootstrap-server hadoop001:9092 \
|
||||
--replication-factor 1 \
|
||||
--partitions 1 \
|
||||
--topic flink-stream-in-topic
|
||||
|
||||
# 查看所有主题
|
||||
bin/kafka-topics.sh --list --bootstrap-server hadoop001:9092
|
||||
```
|
||||
|
||||
#### 3. 启动 Producer
|
||||
|
||||
这里 启动一个 Kafka 生产者,用于发送测试数据:
|
||||
|
||||
```shell
|
||||
bin/kafka-console-producer.sh --broker-list hadoop001:9092 --topic flink-stream-in-topic
|
||||
```
|
||||
|
||||
#### 4. 测试结果
|
||||
|
||||
在 Producer 上输入任意测试数据,之后观察程序控制台的输出:
|
||||
|
||||

|
||||
程序控制台的输出如下:
|
||||
|
||||

|
||||
可以看到已经成功接收并打印出相关的数据。
|
||||
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
1. data-sources:https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/datastream_api.html#data-sources
|
||||
2. Streaming Connectors:https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/connectors/index.html
|
||||
3. Apache Kafka Connector: https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/connectors/kafka.html
|
@ -1,311 +0,0 @@
|
||||
# Flink Transformation
|
||||
<nav>
|
||||
<a href="#一Transformations-分类">一、Transformations 分类</a><br/>
|
||||
<a href="#二DataStream-Transformations">二、DataStream Transformations</a><br/>
|
||||
<a href="#21-Map-[DataStream-→-DataStream]">2.1 Map [DataStream → DataStream] </a><br/>
|
||||
<a href="#22-FlatMap-[DataStream-→-DataStream]">2.2 FlatMap [DataStream → DataStream]</a><br/>
|
||||
<a href="#23-Filter-[DataStream-→-DataStream]">2.3 Filter [DataStream → DataStream]</a><br/>
|
||||
<a href="#24-KeyBy-和-Reduce">2.4 KeyBy 和 Reduce</a><br/>
|
||||
<a href="#25-Aggregations-[KeyedStream-→-DataStream]">2.5 Aggregations [KeyedStream → DataStream]</a><br/>
|
||||
<a href="#26-Union-[DataStream*-→-DataStream]">2.6 Union [DataStream* → DataStream]</a><br/>
|
||||
<a href="#27-Connect-[DataStreamDataStream-→-ConnectedStreams]">2.7 Connect [DataStream,DataStream → ConnectedStreams]</a><br/>
|
||||
<a href="#28-Split-和-Select">2.8 Split 和 Select</a><br/>
|
||||
<a href="#29-project-[DataStream-→-DataStream]">2.9 project [DataStream → DataStream]</a><br/>
|
||||
<a href="#三物理分区">三、物理分区</a><br/>
|
||||
<a href="#31-Random-partitioning-[DataStream-→-DataStream]">3.1 Random partitioning [DataStream → DataStream]</a><br/>
|
||||
<a href="#32-Rebalancing-[DataStream-→-DataStream]">3.2 Rebalancing [DataStream → DataStream]</a><br/>
|
||||
<a href="#33-Rescaling-[DataStream-→-DataStream]">3.3 Rescaling [DataStream → DataStream]</a><br/>
|
||||
<a href="#34-Broadcasting-[DataStream-→-DataStream]">3.4 Broadcasting [DataStream → DataStream]</a><br/>
|
||||
<a href="#35-Custom-partitioning-[DataStream-→-DataStream]">3.5 Custom partitioning [DataStream → DataStream]</a><br/>
|
||||
<a href="#四任务链和资源组">四、任务链和资源组</a><br/>
|
||||
<a href="#41-startNewChain">4.1 startNewChain</a><br/>
|
||||
<a href="#42-disableChaining">4.2 disableChaining</a><br/>
|
||||
<a href="#43-slotSharingGroup">4.3 slotSharingGroup</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
## 一、Transformations 分类
|
||||
|
||||
Flink 的 Transformations 操作主要用于将一个和多个 DataStream 按需转换成新的 DataStream。它主要分为以下三类:
|
||||
|
||||
- **DataStream Transformations**:进行数据流相关转换操作;
|
||||
- **Physical partitioning**:物理分区。Flink 提供的底层 API ,允许用户定义数据的分区规则;
|
||||
- **Task chaining and resource groups**:任务链和资源组。允许用户进行任务链和资源组的细粒度的控制。
|
||||
|
||||
以下分别对其主要 API 进行介绍:
|
||||
|
||||
## 二、DataStream Transformations
|
||||
|
||||
### 2.1 Map [DataStream → DataStream]
|
||||
|
||||
对一个 DataStream 中的每个元素都执行特定的转换操作:
|
||||
|
||||
```java
|
||||
DataStream<Integer> integerDataStream = env.fromElements(1, 2, 3, 4, 5);
|
||||
integerDataStream.map((MapFunction<Integer, Object>) value -> value * 2).print();
|
||||
// 输出 2,4,6,8,10
|
||||
```
|
||||
|
||||
### 2.2 FlatMap [DataStream → DataStream]
|
||||
|
||||
FlatMap 与 Map 类似,但是 FlatMap 中的一个输入元素可以被映射成一个或者多个输出元素,示例如下:
|
||||
|
||||
```java
|
||||
String string01 = "one one one two two";
|
||||
String string02 = "third third third four";
|
||||
DataStream<String> stringDataStream = env.fromElements(string01, string02);
|
||||
stringDataStream.flatMap(new FlatMapFunction<String, String>() {
|
||||
@Override
|
||||
public void flatMap(String value, Collector<String> out) throws Exception {
|
||||
for (String s : value.split(" ")) {
|
||||
out.collect(s);
|
||||
}
|
||||
}
|
||||
}).print();
|
||||
// 输出每一个独立的单词,为节省排版,这里去掉换行,后文亦同
|
||||
one one one two two third third third four
|
||||
```
|
||||
|
||||
### 2.3 Filter [DataStream → DataStream]
|
||||
|
||||
用于过滤符合条件的数据:
|
||||
|
||||
```java
|
||||
env.fromElements(1, 2, 3, 4, 5).filter(x -> x > 3).print();
|
||||
```
|
||||
|
||||
### 2.4 KeyBy 和 Reduce
|
||||
|
||||
- **KeyBy [DataStream → KeyedStream]** :用于将相同 Key 值的数据分到相同的分区中;
|
||||
- **Reduce [KeyedStream → DataStream]** :用于对数据执行归约计算。
|
||||
|
||||
如下例子将数据按照 key 值分区后,滚动进行求和计算:
|
||||
|
||||
```java
|
||||
DataStream<Tuple2<String, Integer>> tuple2DataStream = env.fromElements(new Tuple2<>("a", 1),
|
||||
new Tuple2<>("a", 2),
|
||||
new Tuple2<>("b", 3),
|
||||
new Tuple2<>("b", 5));
|
||||
KeyedStream<Tuple2<String, Integer>, Tuple> keyedStream = tuple2DataStream.keyBy(0);
|
||||
keyedStream.reduce((ReduceFunction<Tuple2<String, Integer>>) (value1, value2) ->
|
||||
new Tuple2<>(value1.f0, value1.f1 + value2.f1)).print();
|
||||
|
||||
// 持续进行求和计算,输出:
|
||||
(a,1)
|
||||
(a,3)
|
||||
(b,3)
|
||||
(b,8)
|
||||
```
|
||||
|
||||
KeyBy 操作存在以下两个限制:
|
||||
|
||||
- KeyBy 操作用于用户自定义的 POJOs 类型时,该自定义类型必须重写 hashCode 方法;
|
||||
- KeyBy 操作不能用于数组类型。
|
||||
|
||||
### 2.5 Aggregations [KeyedStream → DataStream]
|
||||
|
||||
Aggregations 是官方提供的聚合算子,封装了常用的聚合操作,如上利用 Reduce 进行求和的操作也可以利用 Aggregations 中的 sum 算子重写为下面的形式:
|
||||
|
||||
```java
|
||||
tuple2DataStream.keyBy(0).sum(1).print();
|
||||
```
|
||||
|
||||
除了 sum 外,Flink 还提供了 min , max , minBy,maxBy 等常用聚合算子:
|
||||
|
||||
```java
|
||||
// 滚动计算指定key的最小值,可以通过index或者fieldName来指定key
|
||||
keyedStream.min(0);
|
||||
keyedStream.min("key");
|
||||
// 滚动计算指定key的最大值
|
||||
keyedStream.max(0);
|
||||
keyedStream.max("key");
|
||||
// 滚动计算指定key的最小值,并返回其对应的元素
|
||||
keyedStream.minBy(0);
|
||||
keyedStream.minBy("key");
|
||||
// 滚动计算指定key的最大值,并返回其对应的元素
|
||||
keyedStream.maxBy(0);
|
||||
keyedStream.maxBy("key");
|
||||
|
||||
```
|
||||
|
||||
### 2.6 Union [DataStream* → DataStream]
|
||||
|
||||
用于连接两个或者多个元素类型相同的 DataStream 。当然一个 DataStream 也可以与其本生进行连接,此时该 DataStream 中的每个元素都会被获取两次:
|
||||
|
||||
```shell
|
||||
DataStreamSource<Tuple2<String, Integer>> streamSource01 = env.fromElements(new Tuple2<>("a", 1),
|
||||
new Tuple2<>("a", 2));
|
||||
DataStreamSource<Tuple2<String, Integer>> streamSource02 = env.fromElements(new Tuple2<>("b", 1),
|
||||
new Tuple2<>("b", 2));
|
||||
streamSource01.union(streamSource02);
|
||||
streamSource01.union(streamSource01,streamSource02);
|
||||
```
|
||||
|
||||
### 2.7 Connect [DataStream,DataStream → ConnectedStreams]
|
||||
|
||||
Connect 操作用于连接两个或者多个类型不同的 DataStream ,其返回的类型是 ConnectedStreams ,此时被连接的多个 DataStreams 可以共享彼此之间的数据状态。但是需要注意的是由于不同 DataStream 之间的数据类型是不同的,如果想要进行后续的计算操作,还需要通过 CoMap 或 CoFlatMap 将 ConnectedStreams 转换回 DataStream:
|
||||
|
||||
```java
|
||||
DataStreamSource<Tuple2<String, Integer>> streamSource01 = env.fromElements(new Tuple2<>("a", 3),
|
||||
new Tuple2<>("b", 5));
|
||||
DataStreamSource<Integer> streamSource02 = env.fromElements(2, 3, 9);
|
||||
// 使用connect进行连接
|
||||
ConnectedStreams<Tuple2<String, Integer>, Integer> connect = streamSource01.connect(streamSource02);
|
||||
connect.map(new CoMapFunction<Tuple2<String, Integer>, Integer, Integer>() {
|
||||
@Override
|
||||
public Integer map1(Tuple2<String, Integer> value) throws Exception {
|
||||
return value.f1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer map2(Integer value) throws Exception {
|
||||
return value;
|
||||
}
|
||||
}).map(x -> x * 100).print();
|
||||
|
||||
// 输出:
|
||||
300 500 200 900 300
|
||||
```
|
||||
|
||||
### 2.8 Split 和 Select
|
||||
|
||||
- **Split [DataStream → SplitStream]**:用于将一个 DataStream 按照指定规则进行拆分为多个 DataStream,需要注意的是这里进行的是逻辑拆分,即 Split 只是将数据贴上不同的类型标签,但最终返回的仍然只是一个 SplitStream;
|
||||
- **Select [SplitStream → DataStream]**:想要从逻辑拆分的 SplitStream 中获取真实的不同类型的 DataStream,需要使用 Select 算子,示例如下:
|
||||
|
||||
```java
|
||||
DataStreamSource<Integer> streamSource = env.fromElements(1, 2, 3, 4, 5, 6, 7, 8);
|
||||
// 标记
|
||||
SplitStream<Integer> split = streamSource.split(new OutputSelector<Integer>() {
|
||||
@Override
|
||||
public Iterable<String> select(Integer value) {
|
||||
List<String> output = new ArrayList<String>();
|
||||
output.add(value % 2 == 0 ? "even" : "odd");
|
||||
return output;
|
||||
}
|
||||
});
|
||||
// 获取偶数数据集
|
||||
split.select("even").print();
|
||||
// 输出 2,4,6,8
|
||||
```
|
||||
|
||||
### 2.9 project [DataStream → DataStream]
|
||||
|
||||
project 主要用于获取 tuples 中的指定字段集,示例如下:
|
||||
|
||||
```java
|
||||
DataStreamSource<Tuple3<String, Integer, String>> streamSource = env.fromElements(
|
||||
new Tuple3<>("li", 22, "2018-09-23"),
|
||||
new Tuple3<>("ming", 33, "2020-09-23"));
|
||||
streamSource.project(0,2).print();
|
||||
|
||||
// 输出
|
||||
(li,2018-09-23)
|
||||
(ming,2020-09-23)
|
||||
```
|
||||
|
||||
## 三、物理分区
|
||||
|
||||
物理分区 (Physical partitioning) 是 Flink 提供的底层的 API,允许用户采用内置的分区规则或者自定义的分区规则来对数据进行分区,从而避免数据在某些分区上过于倾斜,常用的分区规则如下:
|
||||
|
||||
### 3.1 Random partitioning [DataStream → DataStream]
|
||||
|
||||
随机分区 (Random partitioning) 用于随机的将数据分布到所有下游分区中,通过 shuffle 方法来进行实现:
|
||||
|
||||
```java
|
||||
dataStream.shuffle();
|
||||
```
|
||||
|
||||
### 3.2 Rebalancing [DataStream → DataStream]
|
||||
|
||||
Rebalancing 采用轮询的方式将数据进行分区,其适合于存在数据倾斜的场景下,通过 rebalance 方法进行实现:
|
||||
|
||||
```java
|
||||
dataStream.rebalance();
|
||||
```
|
||||
|
||||
### 3.3 Rescaling [DataStream → DataStream]
|
||||
|
||||
当采用 Rebalancing 进行分区平衡时,其实现的是全局性的负载均衡,数据会通过网络传输到其他节点上并完成分区数据的均衡。 而 Rescaling 则是低配版本的 rebalance,它不需要额外的网络开销,它只会对上下游的算子之间进行重新均衡,通过 rescale 方法进行实现:
|
||||
|
||||
```java
|
||||
dataStream.rescale();
|
||||
```
|
||||
|
||||
ReScale 这个单词具有重新缩放的意义,其对应的操作也是如此,具体如下:如果上游 operation 并行度为 2,而下游的 operation 并行度为 6,则其中 1 个上游的 operation 会将元素分发到 3 个下游 operation,另 1 个上游 operation 则会将元素分发到另外 3 个下游 operation。反之亦然,如果上游的 operation 并行度为 6,而下游 operation 并行度为 2,则其中 3 个上游 operation 会将元素分发到 1 个下游 operation,另 3 个上游 operation 会将元素分发到另外 1 个下游operation:
|
||||
|
||||

|
||||
|
||||
|
||||
### 3.4 Broadcasting [DataStream → DataStream]
|
||||
|
||||
将数据分发到所有分区上。通常用于小数据集与大数据集进行关联的情况下,此时可以将小数据集广播到所有分区上,避免频繁的跨分区关联,通过 broadcast 方法进行实现:
|
||||
|
||||
```java
|
||||
dataStream.broadcast();
|
||||
```
|
||||
|
||||
### 3.5 Custom partitioning [DataStream → DataStream]
|
||||
|
||||
Flink 运行用户采用自定义的分区规则来实现分区,此时需要通过实现 Partitioner 接口来自定义分区规则,并指定对应的分区键,示例如下:
|
||||
|
||||
```java
|
||||
DataStreamSource<Tuple2<String, Integer>> streamSource = env.fromElements(new Tuple2<>("Hadoop", 1),
|
||||
new Tuple2<>("Spark", 1),
|
||||
new Tuple2<>("Flink-streaming", 2),
|
||||
new Tuple2<>("Flink-batch", 4),
|
||||
new Tuple2<>("Storm", 4),
|
||||
new Tuple2<>("HBase", 3));
|
||||
streamSource.partitionCustom(new Partitioner<String>() {
|
||||
@Override
|
||||
public int partition(String key, int numPartitions) {
|
||||
// 将第一个字段包含flink的Tuple2分配到同一个分区
|
||||
return key.toLowerCase().contains("flink") ? 0 : 1;
|
||||
}
|
||||
}, 0).print();
|
||||
|
||||
|
||||
// 输出如下:
|
||||
1> (Flink-streaming,2)
|
||||
1> (Flink-batch,4)
|
||||
2> (Hadoop,1)
|
||||
2> (Spark,1)
|
||||
2> (Storm,4)
|
||||
2> (HBase,3)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 四、任务链和资源组
|
||||
|
||||
任务链和资源组 ( Task chaining and resource groups ) 也是 Flink 提供的底层 API,用于控制任务链和资源分配。默认情况下,如果操作允许 (例如相邻的两次 map 操作) ,则 Flink 会尝试将它们在同一个线程内进行,从而可以获取更好的性能。但是 Flink 也允许用户自己来控制这些行为,这就是任务链和资源组 API:
|
||||
|
||||
### 4.1 startNewChain
|
||||
|
||||
startNewChain 用于基于当前 operation 开启一个新的任务链。如下所示,基于第一个 map 开启一个新的任务链,此时前一个 map 和 后一个 map 将处于同一个新的任务链中,但它们与 filter 操作则分别处于不同的任务链中:
|
||||
|
||||
```java
|
||||
someStream.filter(...).map(...).startNewChain().map(...);
|
||||
```
|
||||
|
||||
### 4.2 disableChaining
|
||||
|
||||
disableChaining 操作用于禁止将其他操作与当前操作放置于同一个任务链中,示例如下:
|
||||
|
||||
```java
|
||||
someStream.map(...).disableChaining();
|
||||
```
|
||||
|
||||
### 4.3 slotSharingGroup
|
||||
|
||||
slot 是任务管理器 (TaskManager) 所拥有资源的固定子集,每个操作 (operation) 的子任务 (sub task) 都需要获取 slot 来执行计算,但每个操作所需要资源的大小都是不相同的,为了更好地利用资源,Flink 允许不同操作的子任务被部署到同一 slot 中。slotSharingGroup 用于设置操作的 slot 共享组 (slot sharing group) ,Flink 会将具有相同 slot 共享组的操作放到同一个 slot 中 。示例如下:
|
||||
|
||||
```java
|
||||
someStream.filter(...).slotSharingGroup("slotSharingGroupName");
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
Flink Operators: https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/stream/operators/
|
@ -1,128 +0,0 @@
|
||||
# Flink Windows
|
||||
<nav>
|
||||
<a href="#一窗口概念">一、窗口概念</a><br/>
|
||||
<a href="#二Time-Windows">二、Time Windows</a><br/>
|
||||
<a href="#21-Tumbling-Windows">2.1 Tumbling Windows</a><br/>
|
||||
<a href="#22-Sliding-Windows">2.2 Sliding Windows</a><br/>
|
||||
<a href="#23-Session-Windows">2.3 Session Windows</a><br/>
|
||||
<a href="#24-Global-Windows">2.4 Global Windows</a><br/>
|
||||
<a href="#三Count-Windows">三、Count Windows</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
## 一、窗口概念
|
||||
|
||||
在大多数场景下,我们需要统计的数据流都是无界的,因此我们无法等待整个数据流终止后才进行统计。通常情况下,我们只需要对某个时间范围或者数量范围内的数据进行统计分析:如每隔五分钟统计一次过去一小时内所有商品的点击量;或者每发生1000次点击后,都去统计一下每个商品点击率的占比。在 Flink 中,我们使用窗口 (Window) 来实现这类功能。按照统计维度的不同,Flink 中的窗口可以分为 时间窗口 (Time Windows) 和 计数窗口 (Count Windows) 。
|
||||
|
||||
## 二、Time Windows
|
||||
|
||||
Time Windows 用于以时间为维度来进行数据聚合,具体分为以下四类:
|
||||
|
||||
### 2.1 Tumbling Windows
|
||||
|
||||
滚动窗口 (Tumbling Windows) 是指彼此之间没有重叠的窗口。例如:每隔1小时统计过去1小时内的商品点击量,那么 1 天就只能分为 24 个窗口,每个窗口彼此之间是不存在重叠的,具体如下:
|
||||
|
||||

|
||||
|
||||
|
||||
这里我们以词频统计为例,给出一个具体的用例,代码如下:
|
||||
|
||||
```java
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
// 接收socket上的数据输入
|
||||
DataStreamSource<String> streamSource = env.socketTextStream("hadoop001", 9999, "\n", 3);
|
||||
streamSource.flatMap(new FlatMapFunction<String, Tuple2<String, Long>>() {
|
||||
@Override
|
||||
public void flatMap(String value, Collector<Tuple2<String, Long>> out) throws Exception {
|
||||
String[] words = value.split("\t");
|
||||
for (String word : words) {
|
||||
out.collect(new Tuple2<>(word, 1L));
|
||||
}
|
||||
}
|
||||
}).keyBy(0).timeWindow(Time.seconds(3)).sum(1).print(); //每隔3秒统计一次每个单词出现的数量
|
||||
env.execute("Flink Streaming");
|
||||
```
|
||||
|
||||
测试结果如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
### 2.2 Sliding Windows
|
||||
|
||||
滑动窗口用于滚动进行聚合分析,例如:每隔 6 分钟统计一次过去一小时内所有商品的点击量,那么统计窗口彼此之间就是存在重叠的,即 1天可以分为 240 个窗口。图示如下:
|
||||
|
||||

|
||||
|
||||
|
||||
可以看到 window 1 - 4 这四个窗口彼此之间都存在着时间相等的重叠部分。想要实现滑动窗口,只需要在使用 timeWindow 方法时额外传递第二个参数作为滚动时间即可,具体如下:
|
||||
|
||||
```java
|
||||
// 每隔3秒统计一次过去1分钟内的数据
|
||||
timeWindow(Time.minutes(1),Time.seconds(3))
|
||||
```
|
||||
|
||||
### 2.3 Session Windows
|
||||
|
||||
当用户在进行持续浏览时,可能每时每刻都会有点击数据,例如在活动区间内,用户可能频繁的将某类商品加入和移除购物车,而你只想知道用户本次浏览最终的购物车情况,此时就可以在用户持有的会话结束后再进行统计。想要实现这类统计,可以通过 Session Windows 来进行实现。
|
||||
|
||||

|
||||
|
||||
|
||||
具体的实现代码如下:
|
||||
|
||||
```java
|
||||
// 以处理时间为衡量标准,如果10秒内没有任何数据输入,就认为会话已经关闭,此时触发统计
|
||||
window(ProcessingTimeSessionWindows.withGap(Time.seconds(10)))
|
||||
// 以事件时间为衡量标准
|
||||
window(EventTimeSessionWindows.withGap(Time.seconds(10)))
|
||||
```
|
||||
|
||||
### 2.4 Global Windows
|
||||
|
||||
最后一个窗口是全局窗口, 全局窗口会将所有 key 相同的元素分配到同一个窗口中,其通常配合触发器 (trigger) 进行使用。如果没有相应触发器,则计算将不会被执行。
|
||||
|
||||

|
||||
|
||||
|
||||
这里继续以上面词频统计的案例为例,示例代码如下:
|
||||
|
||||
```java
|
||||
// 当单词累计出现的次数每达到10次时,则触发计算,计算整个窗口内该单词出现的总数
|
||||
window(GlobalWindows.create()).trigger(CountTrigger.of(10)).sum(1).print();
|
||||
```
|
||||
|
||||
## 三、Count Windows
|
||||
|
||||
Count Windows 用于以数量为维度来进行数据聚合,同样也分为滚动窗口和滑动窗口,实现方式也和时间窗口完全一致,只是调用的 API 不同,具体如下:
|
||||
|
||||
```java
|
||||
// 滚动计数窗口,每1000次点击则计算一次
|
||||
countWindow(1000)
|
||||
// 滑动计数窗口,每10次点击发生后,则计算过去1000次点击的情况
|
||||
countWindow(1000,10)
|
||||
```
|
||||
|
||||
实际上计数窗口内部就是调用的我们上一部分介绍的全局窗口来实现的,其源码如下:
|
||||
|
||||
```java
|
||||
public WindowedStream<T, KEY, GlobalWindow> countWindow(long size) {
|
||||
return window(GlobalWindows.create()).trigger(PurgingTrigger.of(CountTrigger.of(size)));
|
||||
}
|
||||
|
||||
|
||||
public WindowedStream<T, KEY, GlobalWindow> countWindow(long size, long slide) {
|
||||
return window(GlobalWindows.create())
|
||||
.evictor(CountEvictor.of(size))
|
||||
.trigger(CountTrigger.of(slide));
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
Flink Windows: https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/stream/operators/windows.html
|
@ -1,304 +0,0 @@
|
||||
# Flink 开发环境搭建
|
||||
|
||||
<nav>
|
||||
<a href="#一安装-Scala-插件">一、安装 Scala 插件</a><br/>
|
||||
<a href="#二Flink-项目初始化">二、Flink 项目初始化</a><br/>
|
||||
<a href="#21-使用官方脚本构建">2.1 使用官方脚本构建</a><br/>
|
||||
<a href="#22-使用-IDEA-构建">2.2 使用 IDEA 构建</a><br/>
|
||||
<a href="#三项目结构">三、项目结构</a><br/>
|
||||
<a href="#31-项目结构">3.1 项目结构</a><br/>
|
||||
<a href="#32-主要依赖">3.2 主要依赖</a><br/>
|
||||
<a href="#四词频统计案例">四、词频统计案例</a><br/>
|
||||
<a href="#41-批处理示例">4.1 批处理示例</a><br/>
|
||||
<a href="#42-流处理示例">4.2 流处理示例</a><br/>
|
||||
<a href="#五使用-Scala-Shell">五、使用 Scala Shell</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
|
||||
## 一、安装 Scala 插件
|
||||
|
||||
Flink 分别提供了基于 Java 语言和 Scala 语言的 API ,如果想要使用 Scala 语言来开发 Flink 程序,可以通过在 IDEA 中安装 Scala 插件来提供语法提示,代码高亮等功能。打开 IDEA , 依次点击 `File => settings => plugins` 打开插件安装页面,搜索 Scala 插件并进行安装,安装完成后,重启 IDEA 即可生效。
|
||||
|
||||

|
||||
|
||||
## 二、Flink 项目初始化
|
||||
|
||||
### 2.1 使用官方脚本构建
|
||||
|
||||
Flink 官方支持使用 Maven 和 Gradle 两种构建工具来构建基于 Java 语言的 Flink 项目;支持使用 SBT 和 Maven 两种构建工具来构建基于 Scala 语言的 Flink 项目。 这里以 Maven 为例进行说明,因为其可以同时支持 Java 语言和 Scala 语言项目的构建。需要注意的是 Flink 1.9 只支持 Maven 3.0.4 以上的版本,Maven 安装完成后,可以通过以下两种方式来构建项目:
|
||||
|
||||
**1. 直接基于 Maven Archetype 构建**
|
||||
|
||||
直接使用下面的 mvn 语句来进行构建,然后根据交互信息的提示,依次输入 groupId , artifactId 以及包名等信息后等待初始化的完成:
|
||||
|
||||
```bash
|
||||
$ mvn archetype:generate \
|
||||
-DarchetypeGroupId=org.apache.flink \
|
||||
-DarchetypeArtifactId=flink-quickstart-java \
|
||||
-DarchetypeVersion=1.9.0
|
||||
```
|
||||
|
||||
> 注:如果想要创建基于 Scala 语言的项目,只需要将 flink-quickstart-java 换成 flink-quickstart-scala 即可,后文亦同。
|
||||
|
||||
**2. 使用官方脚本快速构建**
|
||||
|
||||
为了更方便的初始化项目,官方提供了快速构建脚本,可以直接通过以下命令来进行调用:
|
||||
|
||||
```shell
|
||||
$ curl https://flink.apache.org/q/quickstart.sh | bash -s 1.9.0
|
||||
```
|
||||
|
||||
该方式其实也是通过执行 maven archetype 命令来进行初始化,其脚本内容如下:
|
||||
|
||||
```shell
|
||||
PACKAGE=quickstart
|
||||
|
||||
mvn archetype:generate \
|
||||
-DarchetypeGroupId=org.apache.flink \
|
||||
-DarchetypeArtifactId=flink-quickstart-java \
|
||||
-DarchetypeVersion=${1:-1.8.0} \
|
||||
-DgroupId=org.myorg.quickstart \
|
||||
-DartifactId=$PACKAGE \
|
||||
-Dversion=0.1 \
|
||||
-Dpackage=org.myorg.quickstart \
|
||||
-DinteractiveMode=false
|
||||
```
|
||||
|
||||
可以看到相比于第一种方式,该种方式只是直接指定好了 groupId ,artifactId ,version 等信息而已。
|
||||
|
||||
### 2.2 使用 IDEA 构建
|
||||
|
||||
如果你使用的是开发工具是 IDEA ,可以直接在项目创建页面选择 Maven Flink Archetype 进行项目初始化:
|
||||
|
||||

|
||||
|
||||
如果你的 IDEA 没有上述 Archetype, 可以通过点击右上角的 `ADD ARCHETYPE` ,来进行添加,依次填入所需信息,这些信息都可以从上述的 `archetype:generate ` 语句中获取。点击 `OK` 保存后,该 Archetype 就会一直存在于你的 IDEA 中,之后每次创建项目时,只需要直接选择该 Archetype 即可:
|
||||
|
||||

|
||||
|
||||
选中 Flink Archetype ,然后点击 `NEXT` 按钮,之后的所有步骤都和正常的 Maven 工程相同。
|
||||
|
||||
## 三、项目结构
|
||||
|
||||
### 3.1 项目结构
|
||||
|
||||
创建完成后的自动生成的项目结构如下:
|
||||
|
||||

|
||||
|
||||
其中 BatchJob 为批处理的样例代码,源码如下:
|
||||
|
||||
```scala
|
||||
import org.apache.flink.api.scala._
|
||||
|
||||
object BatchJob {
|
||||
def main(args: Array[String]) {
|
||||
val env = ExecutionEnvironment.getExecutionEnvironment
|
||||
....
|
||||
env.execute("Flink Batch Scala API Skeleton")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
getExecutionEnvironment 代表获取批处理的执行环境,如果是本地运行则获取到的就是本地的执行环境;如果在集群上运行,得到的就是集群的执行环境。如果想要获取流处理的执行环境,则只需要将 `ExecutionEnvironment` 替换为 `StreamExecutionEnvironment`, 对应的代码样例在 StreamingJob 中:
|
||||
|
||||
```scala
|
||||
import org.apache.flink.streaming.api.scala._
|
||||
|
||||
object StreamingJob {
|
||||
def main(args: Array[String]) {
|
||||
val env = StreamExecutionEnvironment.getExecutionEnvironment
|
||||
...
|
||||
env.execute("Flink Streaming Scala API Skeleton")
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
需要注意的是对于流处理项目 `env.execute()` 这句代码是必须的,否则流处理程序就不会被执行,但是对于批处理项目则是可选的。
|
||||
|
||||
### 3.2 主要依赖
|
||||
|
||||
基于 Maven 骨架创建的项目主要提供了以下核心依赖:其中 `flink-scala` 用于支持开发批处理程序 ;`flink-streaming-scala` 用于支持开发流处理程序 ;`scala-library` 用于提供 Scala 语言所需要的类库。如果在使用 Maven 骨架创建时选择的是 Java 语言,则默认提供的则是 `flink-java` 和 `flink-streaming-java` 依赖。
|
||||
|
||||
```xml
|
||||
<!-- Apache Flink dependencies -->
|
||||
<!-- These dependencies are provided, because they should not be packaged into the JAR file. -->
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-scala_${scala.binary.version}</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Scala Library, provided by Flink as well. -->
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
需要特别注意的以上依赖的 `scope` 标签全部被标识为 provided ,这意味着这些依赖都不会被打入最终的 JAR 包。因为 Flink 的安装包中已经提供了这些依赖,位于其 lib 目录下,名为 `flink-dist_*.jar` ,它包含了 Flink 的所有核心类和依赖:
|
||||
|
||||

|
||||
|
||||
`scope` 标签被标识为 provided 会导致你在 IDEA 中启动项目时会抛出 ClassNotFoundException 异常。基于这个原因,在使用 IDEA 创建项目时还自动生成了以下 profile 配置:
|
||||
|
||||
```xml
|
||||
<!-- This profile helps to make things run out of the box in IntelliJ -->
|
||||
<!-- Its adds Flink's core classes to the runtime class path. -->
|
||||
<!-- Otherwise they are missing in IntelliJ, because the dependency is 'provided' -->
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>add-dependencies-for-IDEA</id>
|
||||
|
||||
<activation>
|
||||
<property>
|
||||
<name>idea.version</name>
|
||||
</property>
|
||||
</activation>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-scala_${scala.binary.version}</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-streaming-scala_${scala.binary.version}</artifactId>
|
||||
<version>${flink.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.scala-lang</groupId>
|
||||
<artifactId>scala-library</artifactId>
|
||||
<version>${scala.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
```
|
||||
|
||||
在 id 为 `add-dependencies-for-IDEA` 的 profile 中,所有的核心依赖都被标识为 compile,此时你可以无需改动任何代码,只需要在 IDEA 的 Maven 面板中勾选该 profile,即可直接在 IDEA 中运行 Flink 项目:
|
||||
|
||||

|
||||
|
||||
## 四、词频统计案例
|
||||
|
||||
项目创建完成后,可以先书写一个简单的词频统计的案例来尝试运行 Flink 项目,以下以 Scala 语言为例,分别介绍流处理程序和批处理程序的编程示例:
|
||||
|
||||
### 4.1 批处理示例
|
||||
|
||||
```scala
|
||||
import org.apache.flink.api.scala._
|
||||
|
||||
object WordCountBatch {
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
val benv = ExecutionEnvironment.getExecutionEnvironment
|
||||
val dataSet = benv.readTextFile("D:\\wordcount.txt")
|
||||
dataSet.flatMap { _.toLowerCase.split(",")}
|
||||
.filter (_.nonEmpty)
|
||||
.map { (_, 1) }
|
||||
.groupBy(0)
|
||||
.sum(1)
|
||||
.print()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
其中 `wordcount.txt` 中的内容如下:
|
||||
|
||||
```shell
|
||||
a,a,a,a,a
|
||||
b,b,b
|
||||
c,c
|
||||
d,d
|
||||
```
|
||||
|
||||
本机不需要配置其他任何的 Flink 环境,直接运行 Main 方法即可,结果如下:
|
||||
|
||||

|
||||
|
||||
### 4.2 流处理示例
|
||||
|
||||
```scala
|
||||
import org.apache.flink.streaming.api.scala._
|
||||
import org.apache.flink.streaming.api.windowing.time.Time
|
||||
|
||||
object WordCountStreaming {
|
||||
|
||||
def main(args: Array[String]): Unit = {
|
||||
|
||||
val senv = StreamExecutionEnvironment.getExecutionEnvironment
|
||||
|
||||
val dataStream: DataStream[String] = senv.socketTextStream("192.168.0.229", 9999, '\n')
|
||||
dataStream.flatMap { line => line.toLowerCase.split(",") }
|
||||
.filter(_.nonEmpty)
|
||||
.map { word => (word, 1) }
|
||||
.keyBy(0)
|
||||
.timeWindow(Time.seconds(3))
|
||||
.sum(1)
|
||||
.print()
|
||||
senv.execute("Streaming WordCount")
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
这里以监听指定端口号上的内容为例,使用以下命令来开启端口服务:
|
||||
|
||||
```shell
|
||||
nc -lk 9999
|
||||
```
|
||||
|
||||
之后输入测试数据即可观察到流处理程序的处理情况。
|
||||
|
||||
## 五、使用 Scala Shell
|
||||
|
||||
对于日常的 Demo 项目,如果你不想频繁地启动 IDEA 来观察测试结果,可以像 Spark 一样,直接使用 Scala Shell 来运行程序,这对于日常的学习来说,效果更加直观,也更省时。Flink 安装包的下载地址如下:
|
||||
|
||||
```shell
|
||||
https://flink.apache.org/downloads.html
|
||||
```
|
||||
|
||||
Flink 大多数版本都提供有 Scala 2.11 和 Scala 2.12 两个版本的安装包可供下载:
|
||||
|
||||

|
||||
|
||||
下载完成后进行解压即可,Scala Shell 位于安装目录的 bin 目录下,直接使用以下命令即可以本地模式启动:
|
||||
|
||||
```shell
|
||||
./start-scala-shell.sh local
|
||||
```
|
||||
|
||||
命令行启动完成后,其已经提供了批处理 (benv 和 btenv)和流处理(senv 和 stenv)的运行环境,可以直接运行 Scala Flink 程序,示例如下:
|
||||
|
||||

|
||||
|
||||
最后解释一个常见的异常:这里我使用的 Flink 版本为 1.9.1,启动时会抛出如下异常。这里因为按照官方的说明,目前所有 Scala 2.12 版本的安装包暂时都不支持 Scala Shell,所以如果想要使用 Scala Shell,只能选择 Scala 2.11 版本的安装包。
|
||||
|
||||
```shell
|
||||
[root@hadoop001 bin]# ./start-scala-shell.sh local
|
||||
错误: 找不到或无法加载主类 org.apache.flink.api.scala.FlinkShell
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,173 +0,0 @@
|
||||
# Flink 核心概念综述
|
||||
<nav>
|
||||
<a href="#一Flink-简介">一、Flink 简介</a><br/>
|
||||
<a href="#二Flink-核心架构">二、Flink 核心架构</a><br/>
|
||||
<a href="#21-API--Libraries-层">2.1 API & Libraries 层</a><br/>
|
||||
<a href="#22-Runtime-核心层">2.2 Runtime 核心层</a><br/>
|
||||
<a href="#23-物理部署层">2.3 物理部署层</a><br/>
|
||||
<a href="#三Flink-分层-API">三、Flink 分层 API</a><br/>
|
||||
<a href="#31-SQL--Table-API">3.1 SQL & Table API</a><br/>
|
||||
<a href="#32-DataStream--DataSet-API">3.2 DataStream & DataSet API</a><br/>
|
||||
<a href="#33-Stateful-Stream-Processing">3.3 Stateful Stream Processing</a><br/>
|
||||
<a href="#四Flink-集群架构">四、Flink 集群架构</a><br/>
|
||||
<a href="#41--核心组件">4.1 核心组件</a><br/>
|
||||
<a href="#42--Task--SubTask">4.2 Task & SubTask</a><br/>
|
||||
<a href="#43--资源管理">4.3 资源管理</a><br/>
|
||||
<a href="#44-组件通讯">4.4 组件通讯</a><br/>
|
||||
<a href="#五Flink-的优点">五、Flink 的优点</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
## 一、Flink 简介
|
||||
|
||||
Apache Flink 诞生于柏林工业大学的一个研究性项目,原名 StratoSphere 。2014 年,由 StratoSphere 项目孵化出 Flink,并于同年捐赠 Apache,之后成为 Apache 的顶级项目。2019 年 1 年,阿里巴巴收购了 Flink 的母公司 Data Artisans,并宣布开源内部的 Blink,Blink 是阿里巴巴基于 Flink 优化后的版本,增加了大量的新功能,并在性能和稳定性上进行了各种优化,经历过阿里内部多种复杂业务的挑战和检验。同时阿里巴巴也表示会逐步将这些新功能和特性 Merge 回社区版本的 Flink 中,因此 Flink 成为目前最为火热的大数据处理框架。
|
||||
|
||||
简单来说,Flink 是一个分布式的流处理框架,它能够对有界和无界的数据流进行高效的处理。Flink 的核心是流处理,当然它也能支持批处理,Flink 将批处理看成是流处理的一种特殊情况,即数据流是有明确界限的。这和 Spark Streaming 的思想是完全相反的,Spark Streaming 的核心是批处理,它将流处理看成是批处理的一种特殊情况, 即把数据流进行极小粒度的拆分,拆分为多个微批处理。
|
||||
|
||||
Flink 有界数据流和无界数据流:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
Spark Streaming 数据流的拆分:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
## 二、Flink 核心架构
|
||||
|
||||
Flink 采用分层的架构设计,从而保证各层在功能和职责上的清晰。如下图所示,由上而下分别是 API & Libraries 层、Runtime 核心层以及物理部署层:
|
||||
|
||||
<div align="center"> <img width="600px" src="../pictures/flink-stack.png"/> </div>
|
||||
|
||||
|
||||
|
||||
|
||||
### 2.1 API & Libraries 层
|
||||
|
||||
这一层主要提供了编程 API 和 顶层类库:
|
||||
|
||||
+ 编程 API : 用于进行流处理的 DataStream API 和用于进行批处理的 DataSet API;
|
||||
+ 顶层类库:包括用于复杂事件处理的 CEP 库;用于结构化数据查询的 SQL & Table 库,以及基于批处理的机器学习库 FlinkML 和 图形处理库 Gelly。
|
||||
|
||||
### 2.2 Runtime 核心层
|
||||
|
||||
这一层是 Flink 分布式计算框架的核心实现层,包括作业转换,任务调度,资源分配,任务执行等功能,基于这一层的实现,可以在流式引擎下同时运行流处理程序和批处理程序。
|
||||
|
||||
### 2.3 物理部署层
|
||||
|
||||
Flink 的物理部署层,用于支持在不同平台上部署运行 Flink 应用。
|
||||
|
||||
## 三、Flink 分层 API
|
||||
|
||||
在上面介绍的 API & Libraries 这一层,Flink 又进行了更为具体的划分。具体如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
按照如上的层次结构,API 的一致性由下至上依次递增,接口的表现能力由下至上依次递减,各层的核心功能如下:
|
||||
|
||||
### 3.1 SQL & Table API
|
||||
|
||||
SQL & Table API 同时适用于批处理和流处理,这意味着你可以对有界数据流和无界数据流以相同的语义进行查询,并产生相同的结果。除了基本查询外, 它还支持自定义的标量函数,聚合函数以及表值函数,可以满足多样化的查询需求。
|
||||
|
||||
### 3.2 DataStream & DataSet API
|
||||
|
||||
DataStream & DataSet API 是 Flink 数据处理的核心 API,支持使用 Java 语言或 Scala 语言进行调用,提供了数据读取,数据转换和数据输出等一系列常用操作的封装。
|
||||
|
||||
### 3.3 Stateful Stream Processing
|
||||
|
||||
Stateful Stream Processing 是最低级别的抽象,它通过 Process Function 函数内嵌到 DataStream API 中。 Process Function 是 Flink 提供的最底层 API,具有最大的灵活性,允许开发者对于时间和状态进行细粒度的控制。
|
||||
|
||||
## 四、Flink 集群架构
|
||||
|
||||
### 4.1 核心组件
|
||||
|
||||
按照上面的介绍,Flink 核心架构的第二层是 Runtime 层, 该层采用标准的 Master - Slave 结构, 其中,Master 部分又包含了三个核心组件:Dispatcher、ResourceManager 和 JobManager,而 Slave 则主要是 TaskManager 进程。它们的功能分别如下:
|
||||
|
||||
- **JobManagers** (也称为 *masters*) :JobManagers 接收由 Dispatcher 传递过来的执行程序,该执行程序包含了作业图 (JobGraph),逻辑数据流图 (logical dataflow graph) 及其所有的 classes 文件以及第三方类库 (libraries) 等等 。紧接着 JobManagers 会将 JobGraph 转换为执行图 (ExecutionGraph),然后向 ResourceManager 申请资源来执行该任务,一旦申请到资源,就将执行图分发给对应的 TaskManagers 。因此每个作业 (Job) 至少有一个 JobManager;高可用部署下可以有多个 JobManagers,其中一个作为 *leader*,其余的则处于 *standby* 状态。
|
||||
- **TaskManagers** (也称为 *workers*) : TaskManagers 负责实际的子任务 (subtasks) 的执行,每个 TaskManagers 都拥有一定数量的 slots。Slot 是一组固定大小的资源的合集 (如计算能力,存储空间)。TaskManagers 启动后,会将其所拥有的 slots 注册到 ResourceManager 上,由 ResourceManager 进行统一管理。
|
||||
- **Dispatcher**:负责接收客户端提交的执行程序,并传递给 JobManager 。除此之外,它还提供了一个 WEB UI 界面,用于监控作业的执行情况。
|
||||
- **ResourceManager** :负责管理 slots 并协调集群资源。ResourceManager 接收来自 JobManager 的资源请求,并将存在空闲 slots 的 TaskManagers 分配给 JobManager 执行任务。Flink 基于不同的部署平台,如 YARN , Mesos,K8s 等提供了不同的资源管理器,当 TaskManagers 没有足够的 slots 来执行任务时,它会向第三方平台发起会话来请求额外的资源。
|
||||
|
||||

|
||||
|
||||
|
||||
### 4.2 Task & SubTask
|
||||
|
||||
上面我们提到:TaskManagers 实际执行的是 SubTask,而不是 Task,这里解释一下两者的区别:
|
||||
|
||||
在执行分布式计算时,Flink 将可以链接的操作 (operators) 链接到一起,这就是 Task。之所以这样做, 是为了减少线程间切换和缓冲而导致的开销,在降低延迟的同时可以提高整体的吞吐量。 但不是所有的 operator 都可以被链接,如下 keyBy 等操作会导致网络 shuffle 和重分区,因此其就不能被链接,只能被单独作为一个 Task。 简单来说,一个 Task 就是一个可以链接的最小的操作链 (Operator Chains) 。如下图,source 和 map 算子被链接到一块,因此整个作业就只有三个 Task:
|
||||
|
||||

|
||||
|
||||
|
||||
解释完 Task ,我们在解释一下什么是 SubTask,其准确的翻译是: *A subtask is one parallel slice of a task*,即一个 Task 可以按照其并行度拆分为多个 SubTask。如上图,source & map 具有两个并行度,KeyBy 具有两个并行度,Sink 具有一个并行度,因此整个虽然只有 3 个 Task,但是却有 5 个 SubTask。Jobmanager 负责定义和拆分这些 SubTask,并将其交给 Taskmanagers 来执行,每个 SubTask 都是一个单独的线程。
|
||||
|
||||
### 4.3 资源管理
|
||||
|
||||
理解了 SubTasks ,我们再来看看其与 Slots 的对应情况。一种可能的分配情况如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
这时每个 SubTask 线程运行在一个独立的 TaskSlot, 它们共享所属的 TaskManager 进程的TCP 连接(通过多路复用技术)和心跳信息 (heartbeat messages),从而可以降低整体的性能开销。此时看似是最好的情况,但是每个操作需要的资源都是不尽相同的,这里假设该作业 keyBy 操作所需资源的数量比 Sink 多很多 ,那么此时 Sink 所在 Slot 的资源就没有得到有效的利用。
|
||||
|
||||
基于这个原因,Flink 允许多个 subtasks 共享 slots,即使它们是不同 tasks 的 subtasks,但只要它们来自同一个 Job 就可以。假设上面 souce & map 和 keyBy 的并行度调整为 6,而 Slot 的数量不变,此时情况如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
可以看到一个 Task Slot 中运行了多个 SubTask 子任务,此时每个子任务仍然在一个独立的线程中执行,只不过共享一组 Sot 资源而已。那么 Flink 到底如何确定一个 Job 至少需要多少个 Slot 呢?Flink 对于这个问题的处理很简单,默认情况一个 Job 所需要的 Slot 的数量就等于其 Operation 操作的最高并行度。如下, A,B,D 操作的并行度为 4,而 C,E 操作的并行度为 2,那么此时整个 Job 就需要至少四个 Slots 来完成。通过这个机制,Flink 就可以不必去关心一个 Job 到底会被拆分为多少个 Tasks 和 SubTasks。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 4.4 组件通讯
|
||||
|
||||
Flink 的所有组件都基于 Actor System 来进行通讯。Actor system是多种角色的 actor 的容器,它提供调度,配置,日志记录等多种服务,并包含一个可以启动所有 actor 的线程池,如果 actor 是本地的,则消息通过共享内存进行共享,但如果 actor 是远程的,则通过 RPC 的调用来传递消息。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
## 五、Flink 的优点
|
||||
|
||||
最后基于上面的介绍,来总结一下 Flink 的优点:
|
||||
|
||||
+ Flink 是基于事件驱动 (Event-driven) 的应用,能够同时支持流处理和批处理;
|
||||
+ 基于内存的计算,能够保证高吞吐和低延迟,具有优越的性能表现;
|
||||
+ 支持精确一次 (Exactly-once) 语意,能够完美地保证一致性和正确性;
|
||||
+ 分层 API ,能够满足各个层次的开发需求;
|
||||
+ 支持高可用配置,支持保存点机制,能够提供安全性和稳定性上的保证;
|
||||
+ 多样化的部署方式,支持本地,远端,云端等多种部署方案;
|
||||
+ 具有横向扩展架构,能够按照用户的需求进行动态扩容;
|
||||
+ 活跃度极高的社区和完善的生态圈的支持。
|
||||
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
+ [Dataflow Programming Model](https://ci.apache.org/projects/flink/flink-docs-release-1.9/concepts/programming-model.html)
|
||||
+ [Distributed Runtime Environment](https://ci.apache.org/projects/flink/flink-docs-release-1.9/concepts/runtime.html)
|
||||
+ [Component Stack](https://ci.apache.org/projects/flink/flink-docs-release-1.9/internals/components.html)
|
||||
+ Fabian Hueske , Vasiliki Kalavri . 《Stream Processing with Apache Flink》. O'Reilly Media . 2019-4-30
|
||||
|
||||
|
||||
|
||||
|
@ -1,370 +0,0 @@
|
||||
# Flink 状态管理
|
||||
<nav>
|
||||
<a href="#一状态分类">一、状态分类</a><br/>
|
||||
<a href="#21-算子状态">2.1 算子状态</a><br/>
|
||||
<a href="#22-键控状态">2.2 键控状态</a><br/>
|
||||
<a href="#二状态编程">二、状态编程</a><br/>
|
||||
<a href="#21-键控状态">2.1 键控状态</a><br/>
|
||||
<a href="#22-状态有效期">2.2 状态有效期</a><br/>
|
||||
<a href="#23-算子状态">2.3 算子状态</a><br/>
|
||||
<a href="#三检查点机制">三、检查点机制</a><br/>
|
||||
<a href="#31-CheckPoints">3.1 CheckPoints</a><br/>
|
||||
<a href="#32-开启检查点">3.2 开启检查点</a><br/>
|
||||
<a href="#33-保存点机制">3.3 保存点机制</a><br/>
|
||||
<a href="#四状态后端">四、状态后端</a><br/>
|
||||
<a href="#41-状态管理器分类">4.1 状态管理器分类</a><br/>
|
||||
<a href="#42-配置方式">4.2 配置方式</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
## 一、状态分类
|
||||
|
||||
相对于其他流计算框架,Flink 一个比较重要的特性就是其支持有状态计算。即你可以将中间的计算结果进行保存,并提供给后续的计算使用:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
具体而言,Flink 又将状态 (State) 分为 Keyed State 与 Operator State:
|
||||
|
||||
### 2.1 算子状态
|
||||
|
||||
算子状态 (Operator State):顾名思义,状态是和算子进行绑定的,一个算子的状态不能被其他算子所访问到。官方文档上对 Operator State 的解释是:*each operator state is bound to one parallel operator instance*,所以更为确切的说一个算子状态是与一个并发的算子实例所绑定的,即假设算子的并行度是 2,那么其应有两个对应的算子状态:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 2.2 键控状态
|
||||
|
||||
键控状态 (Keyed State) :是一种特殊的算子状态,即状态是根据 key 值进行区分的,Flink 会为每类键值维护一个状态实例。如下图所示,每个颜色代表不同 key 值,对应四个不同的状态实例。需要注意的是键控状态只能在 `KeyedStream` 上进行使用,我们可以通过 `stream.keyBy(...)` 来得到 `KeyedStream` 。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 二、状态编程
|
||||
|
||||
### 2.1 键控状态
|
||||
|
||||
Flink 提供了以下数据格式来管理和存储键控状态 (Keyed State):
|
||||
|
||||
- **ValueState**:存储单值类型的状态。可以使用 `update(T)` 进行更新,并通过 `T value()` 进行检索。
|
||||
- **ListState**:存储列表类型的状态。可以使用 `add(T)` 或 `addAll(List)` 添加元素;并通过 `get()` 获得整个列表。
|
||||
- **ReducingState**:用于存储经过 ReduceFunction 计算后的结果,使用 `add(T)` 增加元素。
|
||||
- **AggregatingState**:用于存储经过 AggregatingState 计算后的结果,使用 `add(IN)` 添加元素。
|
||||
- **FoldingState**:已被标识为废弃,会在未来版本中移除,官方推荐使用 `AggregatingState` 代替。
|
||||
- **MapState**:维护 Map 类型的状态。
|
||||
|
||||
以上所有增删改查方法不必硬记,在使用时通过语法提示来调用即可。这里给出一个具体的使用示例:假设我们正在开发一个监控系统,当监控数据超过阈值一定次数后,需要发出报警信息。这里之所以要达到一定次数,是因为由于偶发原因,偶尔一次超过阈值并不能代表什么,故需要达到一定次数后才触发报警,这就需要使用到 Flink 的状态编程。相关代码如下:
|
||||
|
||||
```java
|
||||
public class ThresholdWarning extends
|
||||
RichFlatMapFunction<Tuple2<String, Long>, Tuple2<String, List<Long>>> {
|
||||
|
||||
// 通过ListState来存储非正常数据的状态
|
||||
private transient ListState<Long> abnormalData;
|
||||
// 需要监控的阈值
|
||||
private Long threshold;
|
||||
// 触发报警的次数
|
||||
private Integer numberOfTimes;
|
||||
|
||||
ThresholdWarning(Long threshold, Integer numberOfTimes) {
|
||||
this.threshold = threshold;
|
||||
this.numberOfTimes = numberOfTimes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void open(Configuration parameters) {
|
||||
// 通过状态名称(句柄)获取状态实例,如果不存在则会自动创建
|
||||
abnormalData = getRuntimeContext().getListState(
|
||||
new ListStateDescriptor<>("abnormalData", Long.class));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flatMap(Tuple2<String, Long> value, Collector<Tuple2<String, List<Long>>> out)
|
||||
throws Exception {
|
||||
Long inputValue = value.f1;
|
||||
// 如果输入值超过阈值,则记录该次不正常的数据信息
|
||||
if (inputValue >= threshold) {
|
||||
abnormalData.add(inputValue);
|
||||
}
|
||||
ArrayList<Long> list = Lists.newArrayList(abnormalData.get().iterator());
|
||||
// 如果不正常的数据出现达到一定次数,则输出报警信息
|
||||
if (list.size() >= numberOfTimes) {
|
||||
out.collect(Tuple2.of(value.f0 + " 超过指定阈值 ", list));
|
||||
// 报警信息输出后,清空状态
|
||||
abnormalData.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
调用自定义的状态监控,这里我们使用 a,b 来代表不同类型的监控数据,分别对其数据进行监控:
|
||||
|
||||
```java
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
DataStreamSource<Tuple2<String, Long>> tuple2DataStreamSource = env.fromElements(
|
||||
Tuple2.of("a", 50L), Tuple2.of("a", 80L), Tuple2.of("a", 400L),
|
||||
Tuple2.of("a", 100L), Tuple2.of("a", 200L), Tuple2.of("a", 200L),
|
||||
Tuple2.of("b", 100L), Tuple2.of("b", 200L), Tuple2.of("b", 200L),
|
||||
Tuple2.of("b", 500L), Tuple2.of("b", 600L), Tuple2.of("b", 700L));
|
||||
tuple2DataStreamSource
|
||||
.keyBy(0)
|
||||
.flatMap(new ThresholdWarning(100L, 3)) // 超过100的阈值3次后就进行报警
|
||||
.printToErr();
|
||||
env.execute("Managed Keyed State");
|
||||
```
|
||||
|
||||
输出如下结果如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 2.2 状态有效期
|
||||
|
||||
以上任何类型的 keyed state 都支持配置有效期 (TTL) ,示例如下:
|
||||
|
||||
```java
|
||||
StateTtlConfig ttlConfig = StateTtlConfig
|
||||
// 设置有效期为 10 秒
|
||||
.newBuilder(Time.seconds(10))
|
||||
// 设置有效期更新规则,这里设置为当创建和写入时,都重置其有效期到规定的10秒
|
||||
.setUpdateType(StateTtlConfig.UpdateType.OnCreateAndWrite)
|
||||
/*设置只要值过期就不可见,另外一个可选值是ReturnExpiredIfNotCleanedUp,
|
||||
代表即使值过期了,但如果还没有被物理删除,就是可见的*/
|
||||
.setStateVisibility(StateTtlConfig.StateVisibility.NeverReturnExpired)
|
||||
.build();
|
||||
ListStateDescriptor<Long> descriptor = new ListStateDescriptor<>("abnormalData", Long.class);
|
||||
descriptor.enableTimeToLive(ttlConfig);
|
||||
```
|
||||
|
||||
### 2.3 算子状态
|
||||
|
||||
相比于键控状态,算子状态目前支持的存储类型只有以下三种:
|
||||
|
||||
- **ListState**:存储列表类型的状态。
|
||||
- **UnionListState**:存储列表类型的状态,与 ListState 的区别在于:如果并行度发生变化,ListState 会将该算子的所有并发的状态实例进行汇总,然后均分给新的 Task;而 UnionListState 只是将所有并发的状态实例汇总起来,具体的划分行为则由用户进行定义。
|
||||
- **BroadcastState**:用于广播的算子状态。
|
||||
|
||||
这里我们继续沿用上面的例子,假设此时我们不需要区分监控数据的类型,只要有监控数据超过阈值并达到指定的次数后,就进行报警,代码如下:
|
||||
|
||||
```java
|
||||
public class ThresholdWarning extends RichFlatMapFunction<Tuple2<String, Long>,
|
||||
Tuple2<String, List<Tuple2<String, Long>>>> implements CheckpointedFunction {
|
||||
|
||||
// 非正常数据
|
||||
private List<Tuple2<String, Long>> bufferedData;
|
||||
// checkPointedState
|
||||
private transient ListState<Tuple2<String, Long>> checkPointedState;
|
||||
// 需要监控的阈值
|
||||
private Long threshold;
|
||||
// 次数
|
||||
private Integer numberOfTimes;
|
||||
|
||||
ThresholdWarning(Long threshold, Integer numberOfTimes) {
|
||||
this.threshold = threshold;
|
||||
this.numberOfTimes = numberOfTimes;
|
||||
this.bufferedData = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeState(FunctionInitializationContext context) throws Exception {
|
||||
// 注意这里获取的是OperatorStateStore
|
||||
checkPointedState = context.getOperatorStateStore().
|
||||
getListState(new ListStateDescriptor<>("abnormalData",
|
||||
TypeInformation.of(new TypeHint<Tuple2<String, Long>>() {
|
||||
})));
|
||||
// 如果发生重启,则需要从快照中将状态进行恢复
|
||||
if (context.isRestored()) {
|
||||
for (Tuple2<String, Long> element : checkPointedState.get()) {
|
||||
bufferedData.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flatMap(Tuple2<String, Long> value,
|
||||
Collector<Tuple2<String, List<Tuple2<String, Long>>>> out) {
|
||||
Long inputValue = value.f1;
|
||||
// 超过阈值则进行记录
|
||||
if (inputValue >= threshold) {
|
||||
bufferedData.add(value);
|
||||
}
|
||||
// 超过指定次数则输出报警信息
|
||||
if (bufferedData.size() >= numberOfTimes) {
|
||||
// 顺便输出状态实例的hashcode
|
||||
out.collect(Tuple2.of(checkPointedState.hashCode() + "阈值警报!", bufferedData));
|
||||
bufferedData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void snapshotState(FunctionSnapshotContext context) throws Exception {
|
||||
// 在进行快照时,将数据存储到checkPointedState
|
||||
checkPointedState.clear();
|
||||
for (Tuple2<String, Long> element : bufferedData) {
|
||||
checkPointedState.add(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
调用自定义算子状态,这里需要将并行度设置为 1:
|
||||
|
||||
```java
|
||||
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
|
||||
// 开启检查点机制
|
||||
env.enableCheckpointing(1000);
|
||||
// 设置并行度为1
|
||||
DataStreamSource<Tuple2<String, Long>> tuple2DataStreamSource = env.setParallelism(1).fromElements(
|
||||
Tuple2.of("a", 50L), Tuple2.of("a", 80L), Tuple2.of("a", 400L),
|
||||
Tuple2.of("a", 100L), Tuple2.of("a", 200L), Tuple2.of("a", 200L),
|
||||
Tuple2.of("b", 100L), Tuple2.of("b", 200L), Tuple2.of("b", 200L),
|
||||
Tuple2.of("b", 500L), Tuple2.of("b", 600L), Tuple2.of("b", 700L));
|
||||
tuple2DataStreamSource
|
||||
.flatMap(new ThresholdWarning(100L, 3))
|
||||
.printToErr();
|
||||
env.execute("Managed Keyed State");
|
||||
}
|
||||
```
|
||||
|
||||
此时输出如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
在上面的调用代码中,我们将程序的并行度设置为 1,可以看到三次输出中状态实例的 hashcode 全是一致的,证明它们都同一个状态实例。假设将并行度设置为 2,此时输出如下:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
可以看到此时两次输出中状态实例的 hashcode 是不一致的,代表它们不是同一个状态实例,这也就是上文提到的,一个算子状态是与一个并发的算子实例所绑定的。同时这里只输出两次,是因为在并发处理的情况下,线程 1 可能拿到 5 个非正常值,线程 2 可能拿到 4 个非正常值,因为要大于 3 次才能输出,所以在这种情况下就会出现只输出两条记录的情况,所以需要将程序的并行度设置为 1。
|
||||
|
||||
## 三、检查点机制
|
||||
|
||||
### 3.1 CheckPoints
|
||||
|
||||
为了使 Flink 的状态具有良好的容错性,Flink 提供了检查点机制 (CheckPoints) 。通过检查点机制,Flink 定期在数据流上生成 checkpoint barrier ,当某个算子收到 barrier 时,即会基于当前状态生成一份快照,然后再将该 barrier 传递到下游算子,下游算子接收到该 barrier 后,也基于当前状态生成一份快照,依次传递直至到最后的 Sink 算子上。当出现异常后,Flink 就可以根据最近的一次的快照数据将所有算子恢复到先前的状态。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
### 3.2 开启检查点
|
||||
|
||||
默认情况下,检查点机制是关闭的,需要在程序中进行开启:
|
||||
|
||||
```java
|
||||
// 开启检查点机制,并指定状态检查点之间的时间间隔
|
||||
env.enableCheckpointing(1000);
|
||||
|
||||
// 其他可选配置如下:
|
||||
// 设置语义
|
||||
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
|
||||
// 设置两个检查点之间的最小时间间隔
|
||||
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
|
||||
// 设置执行Checkpoint操作时的超时时间
|
||||
env.getCheckpointConfig().setCheckpointTimeout(60000);
|
||||
// 设置最大并发执行的检查点的数量
|
||||
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
|
||||
// 将检查点持久化到外部存储
|
||||
env.getCheckpointConfig().enableExternalizedCheckpoints(
|
||||
ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
|
||||
// 如果有更近的保存点时,是否将作业回退到该检查点
|
||||
env.getCheckpointConfig().setPreferCheckpointForRecovery(true);
|
||||
```
|
||||
|
||||
### 3.3 保存点机制
|
||||
|
||||
保存点机制 (Savepoints) 是检查点机制的一种特殊的实现,它允许你通过手工的方式来触发 Checkpoint,并将结果持久化存储到指定路径中,主要用于避免 Flink 集群在重启或升级时导致状态丢失。示例如下:
|
||||
|
||||
```shell
|
||||
# 触发指定id的作业的Savepoint,并将结果存储到指定目录下
|
||||
bin/flink savepoint :jobId [:targetDirectory]
|
||||
```
|
||||
|
||||
更多命令和配置可以参考官方文档:[savepoints]( https://ci.apache.org/projects/flink/flink-docs-release-1.9/zh/ops/state/savepoints.html )
|
||||
|
||||
## 四、状态后端
|
||||
|
||||
### 4.1 状态管理器分类
|
||||
|
||||
默认情况下,所有的状态都存储在 JVM 的堆内存中,在状态数据过多的情况下,这种方式很有可能导致内存溢出,因此 Flink 该提供了其它方式来存储状态数据,这些存储方式统一称为状态后端 (或状态管理器):
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
主要有以下三种:
|
||||
|
||||
#### 1. MemoryStateBackend
|
||||
|
||||
默认的方式,即基于 JVM 的堆内存进行存储,主要适用于本地开发和调试。
|
||||
|
||||
#### 2. FsStateBackend
|
||||
|
||||
基于文件系统进行存储,可以是本地文件系统,也可以是 HDFS 等分布式文件系统。 需要注意而是虽然选择使用了 FsStateBackend ,但正在进行的数据仍然是存储在 TaskManager 的内存中的,只有在 checkpoint 时,才会将状态快照写入到指定文件系统上。
|
||||
|
||||
#### 3. RocksDBStateBackend
|
||||
|
||||
RocksDBStateBackend 是 Flink 内置的第三方状态管理器,采用嵌入式的 key-value 型数据库 RocksDB 来存储正在进行的数据。等到 checkpoint 时,再将其中的数据持久化到指定的文件系统中,所以采用 RocksDBStateBackend 时也需要配置持久化存储的文件系统。之所以这样做是因为 RocksDB 作为嵌入式数据库安全性比较低,但比起全文件系统的方式,其读取速率更快;比起全内存的方式,其存储空间更大,因此它是一种比较均衡的方案。
|
||||
|
||||
### 4.2 配置方式
|
||||
|
||||
Flink 支持使用两种方式来配置后端管理器:
|
||||
|
||||
**第一种方式**:基于代码方式进行配置,只对当前作业生效:
|
||||
|
||||
```java
|
||||
// 配置 FsStateBackend
|
||||
env.setStateBackend(new FsStateBackend("hdfs://namenode:40010/flink/checkpoints"));
|
||||
// 配置 RocksDBStateBackend
|
||||
env.setStateBackend(new RocksDBStateBackend("hdfs://namenode:40010/flink/checkpoints"));
|
||||
```
|
||||
|
||||
配置 RocksDBStateBackend 时,需要额外导入下面的依赖:
|
||||
|
||||
```xml
|
||||
<dependency>
|
||||
<groupId>org.apache.flink</groupId>
|
||||
<artifactId>flink-statebackend-rocksdb_2.11</artifactId>
|
||||
<version>1.9.0</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
**第二种方式**:基于 `flink-conf.yaml` 配置文件的方式进行配置,对所有部署在该集群上的作业都生效:
|
||||
|
||||
```yaml
|
||||
state.backend: filesystem
|
||||
state.checkpoints.dir: hdfs://namenode:40010/flink/checkpoints
|
||||
```
|
||||
|
||||
|
||||
|
||||
> 注:本篇文章所有示例代码下载地址:[flink-state-management]( https://github.com/heibaiying/BigData-Notes/tree/master/code/Flink/flink-state-management)
|
||||
|
||||
|
||||
|
||||
## 参考资料
|
||||
|
||||
+ [Working with State](https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/stream/state/state.html)
|
||||
+ [Checkpointing](https://ci.apache.org/projects/flink/flink-docs-release-1.9/dev/stream/state/checkpointing.html)
|
||||
+ [Savepoints](https://ci.apache.org/projects/flink/flink-docs-release-1.9/ops/state/savepoints.html#savepoints)
|
||||
+ [State Backends](https://ci.apache.org/projects/flink/flink-docs-release-1.9/ops/state/state_backends.html)
|
||||
+ Fabian Hueske , Vasiliki Kalavri . 《Stream Processing with Apache Flink》. O'Reilly Media . 2019-4-30
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,116 +0,0 @@
|
||||
# Flume 整合 Kafka
|
||||
|
||||
<nav>
|
||||
<a href="#一背景">一、背景</a><br/>
|
||||
<a href="#二整合流程">二、整合流程</a><br/>
|
||||
<a href="#1-启动Zookeeper和Kafka">1. 启动Zookeeper和Kafka</a><br/>
|
||||
<a href="#2-创建主题">2. 创建主题</a><br/>
|
||||
<a href="#3-启动kafka消费者">3. 启动kafka消费者</a><br/>
|
||||
<a href="#4-配置Flume">4. 配置Flume</a><br/>
|
||||
<a href="#5-启动Flume">5. 启动Flume</a><br/>
|
||||
<a href="#6-测试">6. 测试</a><br/>
|
||||
</nav>
|
||||
|
||||
## 一、背景
|
||||
|
||||
先说一下,为什么要使用 Flume + Kafka?
|
||||
|
||||
以实时流处理项目为例,由于采集的数据量可能存在峰值和峰谷,假设是一个电商项目,那么峰值通常出现在秒杀时,这时如果直接将 Flume 聚合后的数据输入到 Storm 等分布式计算框架中,可能就会超过集群的处理能力,这时采用 Kafka 就可以起到削峰的作用。Kafka 天生为大数据场景而设计,具有高吞吐的特性,能很好地抗住峰值数据的冲击。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
## 二、整合流程
|
||||
|
||||
Flume 发送数据到 Kafka 上主要是通过 `KafkaSink` 来实现的,主要步骤如下:
|
||||
|
||||
### 1. 启动Zookeeper和Kafka
|
||||
|
||||
这里启动一个单节点的 Kafka 作为测试:
|
||||
|
||||
```shell
|
||||
# 启动Zookeeper
|
||||
zkServer.sh start
|
||||
|
||||
# 启动kafka
|
||||
bin/kafka-server-start.sh config/server.properties
|
||||
```
|
||||
|
||||
### 2. 创建主题
|
||||
|
||||
创建一个主题 `flume-kafka`,之后 Flume 收集到的数据都会发到这个主题上:
|
||||
|
||||
```shell
|
||||
# 创建主题
|
||||
bin/kafka-topics.sh --create \
|
||||
--zookeeper hadoop001:2181 \
|
||||
--replication-factor 1 \
|
||||
--partitions 1 --topic flume-kafka
|
||||
|
||||
# 查看创建的主题
|
||||
bin/kafka-topics.sh --zookeeper hadoop001:2181 --list
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 3. 启动kafka消费者
|
||||
|
||||
启动一个消费者,监听我们刚才创建的 `flume-kafka` 主题:
|
||||
|
||||
```shell
|
||||
# bin/kafka-console-consumer.sh --bootstrap-server hadoop001:9092 --topic flume-kafka
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 4. 配置Flume
|
||||
|
||||
新建配置文件 `exec-memory-kafka.properties`,文件内容如下。这里我们监听一个名为 `kafka.log` 的文件,当文件内容有变化时,将新增加的内容发送到 Kafka 的 `flume-kafka` 主题上。
|
||||
|
||||
```properties
|
||||
a1.sources = s1
|
||||
a1.channels = c1
|
||||
a1.sinks = k1
|
||||
|
||||
a1.sources.s1.type=exec
|
||||
a1.sources.s1.command=tail -F /tmp/kafka.log
|
||||
a1.sources.s1.channels=c1
|
||||
|
||||
#设置Kafka接收器
|
||||
a1.sinks.k1.type= org.apache.flume.sink.kafka.KafkaSink
|
||||
#设置Kafka地址
|
||||
a1.sinks.k1.brokerList=hadoop001:9092
|
||||
#设置发送到Kafka上的主题
|
||||
a1.sinks.k1.topic=flume-kafka
|
||||
#设置序列化方式
|
||||
a1.sinks.k1.serializer.class=kafka.serializer.StringEncoder
|
||||
a1.sinks.k1.channel=c1
|
||||
|
||||
a1.channels.c1.type=memory
|
||||
a1.channels.c1.capacity=10000
|
||||
a1.channels.c1.transactionCapacity=100
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 5. 启动Flume
|
||||
|
||||
```shell
|
||||
flume-ng agent \
|
||||
--conf conf \
|
||||
--conf-file /usr/app/apache-flume-1.6.0-cdh5.15.2-bin/examples/exec-memory-kafka.properties \
|
||||
--name a1 -Dflume.root.logger=INFO,console
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 6. 测试
|
||||
|
||||
向监听的 `/tmp/kafka.log ` 文件中追加内容,查看 Kafka 消费者的输出:
|
||||
|
||||

|
||||
|
||||
可以看到 `flume-kafka` 主题的消费端已经收到了对应的消息:
|
||||
|
||||

|
@ -1,375 +0,0 @@
|
||||
# Flume 简介及基本使用
|
||||
|
||||
<nav>
|
||||
<a href="#一Flume简介">一、Flume简介</a><br/>
|
||||
<a href="#二Flume架构和基本概念">二、Flume架构和基本概念</a><br/>
|
||||
<a href="#21-基本架构">2.1 基本架构</a><br/>
|
||||
<a href="#22-基本概念">2.2 基本概念</a><br/>
|
||||
<a href="#23-组件种类">2.3 组件种类</a><br/>
|
||||
<a href="#三Flume架构模式">三、Flume架构模式</a><br/>
|
||||
<a href="#四Flume配置格式">四、Flume配置格式</a><br/>
|
||||
<a href="#五Flume的安装部署">五、Flume安装部署</a><br/>
|
||||
<a href="#六Flume使用案例">六、Flume使用案例</a><br/>
|
||||
</nav>
|
||||
|
||||
|
||||
## 一、Flume简介
|
||||
|
||||
Apache Flume 是一个分布式,高可用的数据收集系统。它可以从不同的数据源收集数据,经过聚合后发送到存储系统中,通常用于日志数据的收集。Flume 分为 NG 和 OG (1.0 之前) 两个版本,NG 在 OG 的基础上进行了完全的重构,是目前使用最为广泛的版本。下面的介绍均以 NG 为基础。
|
||||
|
||||
## 二、Flume架构和基本概念
|
||||
|
||||
下图为 Flume 的基本架构图:
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
### 2.1 基本架构
|
||||
|
||||
外部数据源以特定格式向 Flume 发送 `events` (事件),当 `source` 接收到 `events` 时,它将其存储到一个或多个 `channel`,`channe` 会一直保存 `events` 直到它被 `sink` 所消费。`sink` 的主要功能从 `channel` 中读取 `events`,并将其存入外部存储系统或转发到下一个 `source`,成功后再从 `channel` 中移除 `events`。
|
||||
|
||||
|
||||
|
||||
### 2.2 基本概念
|
||||
|
||||
**1. Event**
|
||||
|
||||
`Event` 是 Flume NG 数据传输的基本单元。类似于 JMS 和消息系统中的消息。一个 `Event` 由标题和正文组成:前者是键/值映射,后者是任意字节数组。
|
||||
|
||||
**2. Source**
|
||||
|
||||
数据收集组件,从外部数据源收集数据,并存储到 Channel 中。
|
||||
|
||||
**3. Channel**
|
||||
|
||||
`Channel` 是源和接收器之间的管道,用于临时存储数据。可以是内存或持久化的文件系统:
|
||||
|
||||
+ `Memory Channel` : 使用内存,优点是速度快,但数据可能会丢失 (如突然宕机);
|
||||
+ `File Channel` : 使用持久化的文件系统,优点是能保证数据不丢失,但是速度慢。
|
||||
|
||||
**4. Sink**
|
||||
|
||||
`Sink` 的主要功能从 `Channel` 中读取 `Event`,并将其存入外部存储系统或将其转发到下一个 `Source`,成功后再从 `Channel` 中移除 `Event`。
|
||||
|
||||
**5. Agent**
|
||||
|
||||
是一个独立的 (JVM) 进程,包含 `Source`、 `Channel`、 `Sink` 等组件。
|
||||
|
||||
|
||||
|
||||
### 2.3 组件种类
|
||||
|
||||
Flume 中的每一个组件都提供了丰富的类型,适用于不同场景:
|
||||
|
||||
- Source 类型 :内置了几十种类型,如 `Avro Source`,`Thrift Source`,`Kafka Source`,`JMS Source`;
|
||||
|
||||
- Sink 类型 :`HDFS Sink`,`Hive Sink`,`HBaseSinks`,`Avro Sink` 等;
|
||||
|
||||
- Channel 类型 :`Memory Channel`,`JDBC Channel`,`Kafka Channel`,`File Channel` 等。
|
||||
|
||||
对于 Flume 的使用,除非有特别的需求,否则通过组合内置的各种类型的 Source,Sink 和 Channel 就能满足大多数的需求。在 [Flume 官网](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html) 上对所有类型组件的配置参数均以表格的方式做了详尽的介绍,并附有配置样例;同时不同版本的参数可能略有所不同,所以使用时建议选取官网对应版本的 User Guide 作为主要参考资料。
|
||||
|
||||
|
||||
|
||||
## 三、Flume架构模式
|
||||
|
||||
Flume 支持多种架构模式,分别介绍如下
|
||||
|
||||
### 3.1 multi-agent flow
|
||||
|
||||
|
||||
|
||||

|
||||
|
||||
<br/>
|
||||
|
||||
Flume 支持跨越多个 Agent 的数据传递,这要求前一个 Agent 的 Sink 和下一个 Agent 的 Source 都必须是 `Avro` 类型,Sink 指向 Source 所在主机名 (或 IP 地址) 和端口(详细配置见下文案例三)。
|
||||
|
||||
### 3.2 Consolidation
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
<br/>
|
||||
|
||||
日志收集中常常存在大量的客户端(比如分布式 web 服务),Flume 支持使用多个 Agent 分别收集日志,然后通过一个或者多个 Agent 聚合后再存储到文件系统中。
|
||||
|
||||
### 3.3 Multiplexing the flow
|
||||
|
||||

|
||||
|
||||
Flume 支持从一个 Source 向多个 Channel,也就是向多个 Sink 传递事件,这个操作称之为 `Fan Out`(扇出)。默认情况下 `Fan Out` 是向所有的 Channel 复制 `Event`,即所有 Channel 收到的数据都是相同的。同时 Flume 也支持在 `Source` 上自定义一个复用选择器 (multiplexing selector) 来实现自定义的路由规则。
|
||||
|
||||
|
||||
|
||||
## 四、Flume配置格式
|
||||
|
||||
Flume 配置通常需要以下两个步骤:
|
||||
|
||||
1. 分别定义好 Agent 的 Sources,Sinks,Channels,然后将 Sources 和 Sinks 与通道进行绑定。需要注意的是一个 Source 可以配置多个 Channel,但一个 Sink 只能配置一个 Channel。基本格式如下:
|
||||
|
||||
```shell
|
||||
<Agent>.sources = <Source>
|
||||
<Agent>.sinks = <Sink>
|
||||
<Agent>.channels = <Channel1> <Channel2>
|
||||
|
||||
# set channel for source
|
||||
<Agent>.sources.<Source>.channels = <Channel1> <Channel2> ...
|
||||
|
||||
# set channel for sink
|
||||
<Agent>.sinks.<Sink>.channel = <Channel1>
|
||||
```
|
||||
|
||||
2. 分别定义 Source,Sink,Channel 的具体属性。基本格式如下:
|
||||
|
||||
```shell
|
||||
|
||||
<Agent>.sources.<Source>.<someProperty> = <someValue>
|
||||
|
||||
# properties for channels
|
||||
<Agent>.channel.<Channel>.<someProperty> = <someValue>
|
||||
|
||||
# properties for sinks
|
||||
<Agent>.sources.<Sink>.<someProperty> = <someValue>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 五、Flume的安装部署
|
||||
|
||||
为方便大家后期查阅,本仓库中所有软件的安装均单独成篇,Flume 的安装见:
|
||||
|
||||
[Linux 环境下 Flume 的安装部署](https://github.com/heibaiying/BigData-Notes/blob/master/notes/installation/Linux%E4%B8%8BFlume%E7%9A%84%E5%AE%89%E8%A3%85.md)
|
||||
|
||||
|
||||
|
||||
## 六、Flume使用案例
|
||||
|
||||
介绍几个 Flume 的使用案例:
|
||||
|
||||
+ 案例一:使用 Flume 监听文件内容变动,将新增加的内容输出到控制台。
|
||||
+ 案例二:使用 Flume 监听指定目录,将目录下新增加的文件存储到 HDFS。
|
||||
+ 案例三:使用 Avro 将本服务器收集到的日志数据发送到另外一台服务器。
|
||||
|
||||
### 6.1 案例一
|
||||
|
||||
需求: 监听文件内容变动,将新增加的内容输出到控制台。
|
||||
|
||||
实现: 主要使用 `Exec Source` 配合 `tail` 命令实现。
|
||||
|
||||
#### 1. 配置
|
||||
|
||||
新建配置文件 `exec-memory-logger.properties`,其内容如下:
|
||||
|
||||
```properties
|
||||
#指定agent的sources,sinks,channels
|
||||
a1.sources = s1
|
||||
a1.sinks = k1
|
||||
a1.channels = c1
|
||||
|
||||
#配置sources属性
|
||||
a1.sources.s1.type = exec
|
||||
a1.sources.s1.command = tail -F /tmp/log.txt
|
||||
a1.sources.s1.shell = /bin/bash -c
|
||||
|
||||
#将sources与channels进行绑定
|
||||
a1.sources.s1.channels = c1
|
||||
|
||||
#配置sink
|
||||
a1.sinks.k1.type = logger
|
||||
|
||||
#将sinks与channels进行绑定
|
||||
a1.sinks.k1.channel = c1
|
||||
|
||||
#配置channel类型
|
||||
a1.channels.c1.type = memory
|
||||
```
|
||||
|
||||
#### 2. 启动
|
||||
|
||||
```shell
|
||||
flume-ng agent \
|
||||
--conf conf \
|
||||
--conf-file /usr/app/apache-flume-1.6.0-cdh5.15.2-bin/examples/exec-memory-logger.properties \
|
||||
--name a1 \
|
||||
-Dflume.root.logger=INFO,console
|
||||
```
|
||||
|
||||
#### 3. 测试
|
||||
|
||||
向文件中追加数据:
|
||||
|
||||

|
||||
|
||||
控制台的显示:
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 6.2 案例二
|
||||
|
||||
需求: 监听指定目录,将目录下新增加的文件存储到 HDFS。
|
||||
|
||||
实现:使用 `Spooling Directory Source` 和 `HDFS Sink`。
|
||||
|
||||
#### 1. 配置
|
||||
|
||||
```properties
|
||||
#指定agent的sources,sinks,channels
|
||||
a1.sources = s1
|
||||
a1.sinks = k1
|
||||
a1.channels = c1
|
||||
|
||||
#配置sources属性
|
||||
a1.sources.s1.type =spooldir
|
||||
a1.sources.s1.spoolDir =/tmp/logs
|
||||
a1.sources.s1.basenameHeader = true
|
||||
a1.sources.s1.basenameHeaderKey = fileName
|
||||
#将sources与channels进行绑定
|
||||
a1.sources.s1.channels =c1
|
||||
|
||||
|
||||
#配置sink
|
||||
a1.sinks.k1.type = hdfs
|
||||
a1.sinks.k1.hdfs.path = /flume/events/%y-%m-%d/%H/
|
||||
a1.sinks.k1.hdfs.filePrefix = %{fileName}
|
||||
#生成的文件类型,默认是Sequencefile,可用DataStream,则为普通文本
|
||||
a1.sinks.k1.hdfs.fileType = DataStream
|
||||
a1.sinks.k1.hdfs.useLocalTimeStamp = true
|
||||
#将sinks与channels进行绑定
|
||||
a1.sinks.k1.channel = c1
|
||||
|
||||
#配置channel类型
|
||||
a1.channels.c1.type = memory
|
||||
```
|
||||
|
||||
#### 2. 启动
|
||||
|
||||
```shell
|
||||
flume-ng agent \
|
||||
--conf conf \
|
||||
--conf-file /usr/app/apache-flume-1.6.0-cdh5.15.2-bin/examples/spooling-memory-hdfs.properties \
|
||||
--name a1 -Dflume.root.logger=INFO,console
|
||||
```
|
||||
|
||||
#### 3. 测试
|
||||
|
||||
拷贝任意文件到监听目录下,可以从日志看到文件上传到 HDFS 的路径:
|
||||
|
||||
```shell
|
||||
# cp log.txt logs/
|
||||
```
|
||||
|
||||

|
||||
|
||||
查看上传到 HDFS 上的文件内容与本地是否一致:
|
||||
|
||||
```shell
|
||||
# hdfs dfs -cat /flume/events/19-04-09/13/log.txt.1554788567801
|
||||
```
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 6.3 案例三
|
||||
|
||||
需求: 将本服务器收集到的数据发送到另外一台服务器。
|
||||
|
||||
实现:使用 `avro sources` 和 `avro Sink` 实现。
|
||||
|
||||
#### 1. 配置日志收集Flume
|
||||
|
||||
新建配置 `netcat-memory-avro.properties`,监听文件内容变化,然后将新的文件内容通过 `avro sink` 发送到 hadoop001 这台服务器的 8888 端口:
|
||||
|
||||
```properties
|
||||
#指定agent的sources,sinks,channels
|
||||
a1.sources = s1
|
||||
a1.sinks = k1
|
||||
a1.channels = c1
|
||||
|
||||
#配置sources属性
|
||||
a1.sources.s1.type = exec
|
||||
a1.sources.s1.command = tail -F /tmp/log.txt
|
||||
a1.sources.s1.shell = /bin/bash -c
|
||||
a1.sources.s1.channels = c1
|
||||
|
||||
#配置sink
|
||||
a1.sinks.k1.type = avro
|
||||
a1.sinks.k1.hostname = hadoop001
|
||||
a1.sinks.k1.port = 8888
|
||||
a1.sinks.k1.batch-size = 1
|
||||
a1.sinks.k1.channel = c1
|
||||
|
||||
#配置channel类型
|
||||
a1.channels.c1.type = memory
|
||||
a1.channels.c1.capacity = 1000
|
||||
a1.channels.c1.transactionCapacity = 100
|
||||
```
|
||||
|
||||
#### 2. 配置日志聚合Flume
|
||||
|
||||
使用 `avro source` 监听 hadoop001 服务器的 8888 端口,将获取到内容输出到控制台:
|
||||
|
||||
```properties
|
||||
#指定agent的sources,sinks,channels
|
||||
a2.sources = s2
|
||||
a2.sinks = k2
|
||||
a2.channels = c2
|
||||
|
||||
#配置sources属性
|
||||
a2.sources.s2.type = avro
|
||||
a2.sources.s2.bind = hadoop001
|
||||
a2.sources.s2.port = 8888
|
||||
|
||||
#将sources与channels进行绑定
|
||||
a2.sources.s2.channels = c2
|
||||
|
||||
#配置sink
|
||||
a2.sinks.k2.type = logger
|
||||
|
||||
#将sinks与channels进行绑定
|
||||
a2.sinks.k2.channel = c2
|
||||
|
||||
#配置channel类型
|
||||
a2.channels.c2.type = memory
|
||||
a2.channels.c2.capacity = 1000
|
||||
a2.channels.c2.transactionCapacity = 100
|
||||
```
|
||||
|
||||
#### 3. 启动
|
||||
|
||||
启动日志聚集 Flume:
|
||||
|
||||
```shell
|
||||
flume-ng agent \
|
||||
--conf conf \
|
||||
--conf-file /usr/app/apache-flume-1.6.0-cdh5.15.2-bin/examples/avro-memory-logger.properties \
|
||||
--name a2 -Dflume.root.logger=INFO,console
|
||||
```
|
||||
|
||||
在启动日志收集 Flume:
|
||||
|
||||
```shell
|
||||
flume-ng agent \
|
||||
--conf conf \
|
||||
--conf-file /usr/app/apache-flume-1.6.0-cdh5.15.2-bin/examples/netcat-memory-avro.properties \
|
||||
--name a1 -Dflume.root.logger=INFO,console
|
||||
```
|
||||
|
||||
这里建议按以上顺序启动,原因是 `avro.source` 会先与端口进行绑定,这样 `avro sink` 连接时才不会报无法连接的异常。但是即使不按顺序启动也是没关系的,`sink` 会一直重试,直至建立好连接。
|
||||
|
||||

|
||||
|
||||
#### 4.测试
|
||||
|
||||
向文件 `tmp/log.txt` 中追加内容:
|
||||
|
||||

|
||||
|
||||
可以看到已经从 8888 端口监听到内容,并成功输出到控制台:
|
||||
|
||||

|
@ -1,388 +0,0 @@
|
||||
# HDFS Java API
|
||||
|
||||
<nav>
|
||||
<a href="#一-简介">一、 简介</a><br/>
|
||||
<a href="#二API的使用">二、API的使用</a><br/>
|
||||
<a href="#21-FileSystem">2.1 FileSystem</a><br/>
|
||||
<a href="#22-创建目录">2.2 创建目录</a><br/>
|
||||
<a href="#23-创建指定权限的目录">2.3 创建指定权限的目录</a><br/>
|
||||
<a href="#24-创建文件并写入内容">2.4 创建文件,并写入内容</a><br/>
|
||||
<a href="#25-判断文件是否存在">2.5 判断文件是否存在</a><br/>
|
||||
<a href="#26-查看文件内容">2.6 查看文件内容</a><br/>
|
||||
<a href="#27-文件重命名">2.7 文件重命名</a><br/>
|
||||
<a href="#28-删除目录或文件">2.8 删除目录或文件</a><br/>
|
||||
<a href="#29-上传文件到HDFS">2.9 上传文件到HDFS</a><br/>
|
||||
<a href="#210-上传大文件并显示上传进度">2.10 上传大文件并显示上传进度</a><br/>
|
||||
<a href="#211-从HDFS上下载文件">2.11 从HDFS上下载文件</a><br/>
|
||||
<a href="#212-查看指定目录下所有文件的信息">2.12 查看指定目录下所有文件的信息</a><br/>
|
||||
<a href="#213-递归查看指定目录下所有文件的信息">2.13 递归查看指定目录下所有文件的信息</a><br/>
|
||||
<a href="#214-查看文件的块信息">2.14 查看文件的块信息</a><br/>
|
||||
</nav>
|
||||
|
||||
## 一、 简介
|
||||
|
||||
想要使用 HDFS API,需要导入依赖 `hadoop-client`。如果是 CDH 版本的 Hadoop,还需要额外指明其仓库地址:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
|
||||
http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>com.heibaiying</groupId>
|
||||
<artifactId>hdfs-java-api</artifactId>
|
||||
<version>1.0</version>
|
||||
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<hadoop.version>2.6.0-cdh5.15.2</hadoop.version>
|
||||
</properties>
|
||||
|
||||
|
||||
<!---配置 CDH 仓库地址-->
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>cloudera</id>
|
||||
<url>https://repository.cloudera.com/artifactory/cloudera-repos/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<!--Hadoop-client-->
|
||||
<dependency>
|
||||
<groupId>org.apache.hadoop</groupId>
|
||||
<artifactId>hadoop-client</artifactId>
|
||||
<version>${hadoop.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>4.12</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 二、API的使用
|
||||
|
||||
### 2.1 FileSystem
|
||||
|
||||
FileSystem 是所有 HDFS 操作的主入口。由于之后的每个单元测试都需要用到它,这里使用 `@Before` 注解进行标注。
|
||||
|
||||
```java
|
||||
private static final String HDFS_PATH = "hdfs://192.168.0.106:8020";
|
||||
private static final String HDFS_USER = "root";
|
||||
private static FileSystem fileSystem;
|
||||
|
||||
@Before
|
||||
public void prepare() {
|
||||
try {
|
||||
Configuration configuration = new Configuration();
|
||||
// 这里我启动的是单节点的 Hadoop,所以副本系数设置为 1,默认值为 3
|
||||
configuration.set("dfs.replication", "1");
|
||||
fileSystem = FileSystem.get(new URI(HDFS_PATH), configuration, HDFS_USER);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
} catch (URISyntaxException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@After
|
||||
public void destroy() {
|
||||
fileSystem = null;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.2 创建目录
|
||||
|
||||
支持递归创建目录:
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void mkDir() throws Exception {
|
||||
fileSystem.mkdirs(new Path("/hdfs-api/test0/"));
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.3 创建指定权限的目录
|
||||
|
||||
`FsPermission(FsAction u, FsAction g, FsAction o)` 的三个参数分别对应:创建者权限,同组其他用户权限,其他用户权限,权限值定义在 `FsAction` 枚举类中。
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void mkDirWithPermission() throws Exception {
|
||||
fileSystem.mkdirs(new Path("/hdfs-api/test1/"),
|
||||
new FsPermission(FsAction.READ_WRITE, FsAction.READ, FsAction.READ));
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.4 创建文件,并写入内容
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void create() throws Exception {
|
||||
// 如果文件存在,默认会覆盖, 可以通过第二个参数进行控制。第三个参数可以控制使用缓冲区的大小
|
||||
FSDataOutputStream out = fileSystem.create(new Path("/hdfs-api/test/a.txt"),
|
||||
true, 4096);
|
||||
out.write("hello hadoop!".getBytes());
|
||||
out.write("hello spark!".getBytes());
|
||||
out.write("hello flink!".getBytes());
|
||||
// 强制将缓冲区中内容刷出
|
||||
out.flush();
|
||||
out.close();
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.5 判断文件是否存在
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void exist() throws Exception {
|
||||
boolean exists = fileSystem.exists(new Path("/hdfs-api/test/a.txt"));
|
||||
System.out.println(exists);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.6 查看文件内容
|
||||
|
||||
查看小文本文件的内容,直接转换成字符串后输出:
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void readToString() throws Exception {
|
||||
FSDataInputStream inputStream = fileSystem.open(new Path("/hdfs-api/test/a.txt"));
|
||||
String context = inputStreamToString(inputStream, "utf-8");
|
||||
System.out.println(context);
|
||||
}
|
||||
```
|
||||
|
||||
`inputStreamToString` 是一个自定义方法,代码如下:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 把输入流转换为指定编码的字符
|
||||
*
|
||||
* @param inputStream 输入流
|
||||
* @param encode 指定编码类型
|
||||
*/
|
||||
private static String inputStreamToString(InputStream inputStream, String encode) {
|
||||
try {
|
||||
if (encode == null || ("".equals(encode))) {
|
||||
encode = "utf-8";
|
||||
}
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, encode));
|
||||
StringBuilder builder = new StringBuilder();
|
||||
String str = "";
|
||||
while ((str = reader.readLine()) != null) {
|
||||
builder.append(str).append("\n");
|
||||
}
|
||||
return builder.toString();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.7 文件重命名
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void rename() throws Exception {
|
||||
Path oldPath = new Path("/hdfs-api/test/a.txt");
|
||||
Path newPath = new Path("/hdfs-api/test/b.txt");
|
||||
boolean result = fileSystem.rename(oldPath, newPath);
|
||||
System.out.println(result);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.8 删除目录或文件
|
||||
|
||||
```java
|
||||
public void delete() throws Exception {
|
||||
/*
|
||||
* 第二个参数代表是否递归删除
|
||||
* + 如果 path 是一个目录且递归删除为 true, 则删除该目录及其中所有文件;
|
||||
* + 如果 path 是一个目录但递归删除为 false,则会则抛出异常。
|
||||
*/
|
||||
boolean result = fileSystem.delete(new Path("/hdfs-api/test/b.txt"), true);
|
||||
System.out.println(result);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.9 上传文件到HDFS
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void copyFromLocalFile() throws Exception {
|
||||
// 如果指定的是目录,则会把目录及其中的文件都复制到指定目录下
|
||||
Path src = new Path("D:\\BigData-Notes\\notes\\installation");
|
||||
Path dst = new Path("/hdfs-api/test/");
|
||||
fileSystem.copyFromLocalFile(src, dst);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.10 上传大文件并显示上传进度
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void copyFromLocalBigFile() throws Exception {
|
||||
|
||||
File file = new File("D:\\kafka.tgz");
|
||||
final float fileSize = file.length();
|
||||
InputStream in = new BufferedInputStream(new FileInputStream(file));
|
||||
|
||||
FSDataOutputStream out = fileSystem.create(new Path("/hdfs-api/test/kafka5.tgz"),
|
||||
new Progressable() {
|
||||
long fileCount = 0;
|
||||
|
||||
public void progress() {
|
||||
fileCount++;
|
||||
// progress 方法每上传大约 64KB 的数据后就会被调用一次
|
||||
System.out.println("上传进度:" + (fileCount * 64 * 1024 / fileSize) * 100 + " %");
|
||||
}
|
||||
});
|
||||
|
||||
IOUtils.copyBytes(in, out, 4096);
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.11 从HDFS上下载文件
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void copyToLocalFile() throws Exception {
|
||||
Path src = new Path("/hdfs-api/test/kafka.tgz");
|
||||
Path dst = new Path("D:\\app\\");
|
||||
/*
|
||||
* 第一个参数控制下载完成后是否删除源文件,默认是 true,即删除;
|
||||
* 最后一个参数表示是否将 RawLocalFileSystem 用作本地文件系统;
|
||||
* RawLocalFileSystem 默认为 false,通常情况下可以不设置,
|
||||
* 但如果你在执行时候抛出 NullPointerException 异常,则代表你的文件系统与程序可能存在不兼容的情况 (window 下常见),
|
||||
* 此时可以将 RawLocalFileSystem 设置为 true
|
||||
*/
|
||||
fileSystem.copyToLocalFile(false, src, dst, true);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.12 查看指定目录下所有文件的信息
|
||||
|
||||
```java
|
||||
public void listFiles() throws Exception {
|
||||
FileStatus[] statuses = fileSystem.listStatus(new Path("/hdfs-api"));
|
||||
for (FileStatus fileStatus : statuses) {
|
||||
//fileStatus 的 toString 方法被重写过,直接打印可以看到所有信息
|
||||
System.out.println(fileStatus.toString());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`FileStatus` 中包含了文件的基本信息,比如文件路径,是否是文件夹,修改时间,访问时间,所有者,所属组,文件权限,是否是符号链接等,输出内容示例如下:
|
||||
|
||||
```properties
|
||||
FileStatus{
|
||||
path=hdfs://192.168.0.106:8020/hdfs-api/test;
|
||||
isDirectory=true;
|
||||
modification_time=1556680796191;
|
||||
access_time=0;
|
||||
owner=root;
|
||||
group=supergroup;
|
||||
permission=rwxr-xr-x;
|
||||
isSymlink=false
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.13 递归查看指定目录下所有文件的信息
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void listFilesRecursive() throws Exception {
|
||||
RemoteIterator<LocatedFileStatus> files = fileSystem.listFiles(new Path("/hbase"), true);
|
||||
while (files.hasNext()) {
|
||||
System.out.println(files.next());
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
和上面输出类似,只是多了文本大小,副本系数,块大小信息。
|
||||
|
||||
```properties
|
||||
LocatedFileStatus{
|
||||
path=hdfs://192.168.0.106:8020/hbase/hbase.version;
|
||||
isDirectory=false;
|
||||
length=7;
|
||||
replication=1;
|
||||
blocksize=134217728;
|
||||
modification_time=1554129052916;
|
||||
access_time=1554902661455;
|
||||
owner=root; group=supergroup;
|
||||
permission=rw-r--r--;
|
||||
isSymlink=false}
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 2.14 查看文件的块信息
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void getFileBlockLocations() throws Exception {
|
||||
|
||||
FileStatus fileStatus = fileSystem.getFileStatus(new Path("/hdfs-api/test/kafka.tgz"));
|
||||
BlockLocation[] blocks = fileSystem.getFileBlockLocations(fileStatus, 0, fileStatus.getLen());
|
||||
for (BlockLocation block : blocks) {
|
||||
System.out.println(block);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
块输出信息有三个值,分别是文件的起始偏移量 (offset),文件大小 (length),块所在的主机名 (hosts)。
|
||||
|
||||
```
|
||||
0,57028557,hadoop001
|
||||
```
|
||||
|
||||
这里我上传的文件只有 57M(小于 128M),且程序中设置了副本系数为 1,所有只有一个块信息。
|
||||
|
||||
<br/>
|
||||
|
||||
<br/>
|
||||
|
||||
**以上所有测试用例下载地址**:[HDFS Java API](https://github.com/heibaiying/BigData-Notes/tree/master/code/Hadoop/hdfs-java-api)
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user