6大数据技术栈

22 一步一步搭建一个Hadoop集群

经过前面的学习,了解了大数据的发展史、大数据在我们日常生活的应用。这一章我们着重讲解大数据的实践,本小结我们先学会搭建一个 Hadoop 集群。

Hadoop 集群运行模式

Hadoop 有以下三种运行模型。

  1. 本地模式 (Standalone): 不需要启用单独进程,直接可以运行,测试和开发时使用。

    伪分布式模式 (Pseudo-Distributed): 等同于完全分布式,只有一个节点。

    完全分布式模式 (Fully-Distributed Operation): 多个节点一起运行。

Hadoop 运行环境搭建

Hadoop 是一个支持跨平台运行的系统,既支持 Linux 系统(例如:Centos、Ubuntu ),也支持 Windows 系统。另外对于苹果的 Mac 系统也是支持的。

在实际的工业大数据生产中,大多数使用 Centos 版本的 Linux 系统来搭建 Hadoop 集群。我们下面的讲解也是基于 Linux 系统来说的。

Hadoop 是用 Java 语言编写的,所以 Hadoop 最基础的运行环境就是 Java 环境。不同的 Hadoop 版本需要匹配不同的 Java 版本。Hadoop 版本和 Java 版本的对应关系参考 Hadoop 官网(https://wiki.apache.org/hadoop/HadoopJavaVersions)。

以 Java8 为例说明 Java 环境搭建步骤。

  1. 下载 JDK Java SE 8 的官方网址是
    http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html

    解压文件 我们在 /home/software 文件夹下面解压缩刚才下载好的文件。

    tar -xvf jdk-8u65-linux-x64.tar.gz 添加 Java 环境变量 通过 vim 命令打开
    /etc/profile 文件:

    vim /etc/profile 如果权限不够请使用 sudo。

    sudo vim /etc/profile 将下面的环境变量信息拷贝到 /etc/profile 文件中,并保存。

    export JAVA_HOME=/home/software/jdk1.8.0_65 export
    JRE_HOME=/home/software/jdk1.8.0_65/jre export
    CLASSPATH=.: J A V A H O M E / l i b : JAVA_HOME/lib: JRE_HOME/lib: C L A S S P A T H e x p o r t P A T H = CLASSPATH export PATH= JAVA_HOME/bin: J R E H O M E / b i n : JRE_HOME/bin: PATH 让 Java 环境变量生效 source
    /etc/profile Hadoop 集群运行过程中,经常会有某一个节点的脚本去调用另外一个节点脚本的情况,脚本之间的调用需要使用
    ssh。

    安装 ssh 以下是 Ubuntu Linux 安装 ssh 环境的操作。其他版本的 liunx 系统安装 ssh,同学们可以自行
    Google 搜索安装方法。

    sudo apt-get install ssh sudo apt-get install pdsh 下载 Hadoop 文件 从
    Hadoop 下载地址:http://www.apache.org/dyn/closer.cgi/hadoop/common/
    选择你想安装的 Hadoop 版本下载,并解压缩。以下以 2.7.7 版本的 Hadoop 为例。

    tar -xvf hadoop-2.7.7.tar.gz 通过 vim 编辑解押后文件夹下面的
    etc/hadoop/hadoop-env.sh 文件。添加下面的内容并保存 hadoop-env.sh 文件。

    set to the root of your Java installation export

    JAVA_HOME=/home/software/jdk1.8.0_65 查看 Hadoop 环境是否搭建成功 运行以下命令,如果
    Hadoop 的版本能正常打印出来,说明 Hadoop 环境已经搭建好了。

    bin/hadoop 本地模式 (Standalone)

    通过本地模式运行 Word Count 例子,同学们先感受一下 Hadoop。

    在 hadoop-2.7.7 文件夹下面创建一个 wcInput 文件夹

    mkdir wcInput 在 wcInput 文件下创建一个 wc.input 文件,并输入以下内容

    hello hadoop hello mapreduce hello yarn 在 hadoop-2.7.7 文件夹下面创建一个
    wcOutput 文件夹

    mkdir wcOutput 回到 hadoop-2.7.7 文件夹下,执行程序

    hadoop jar
    share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount
    wcInput wcOutput Word count 程序的执行结果在 wcOutput 文件夹里面。

    伪分布式模式 (Pseudo-Distributed)

    Hadoop 也可以以伪分布模式的方式运行在单节点上,这个时候每一个 Hadoop 守护进程都是一个单独的 Java 进程.

    这种模式需要进行相应的分布式设置,但是又由于只有一个节点,所以我们称之为伪分布模式。

    由于 Hadoop2.x 增加了 Yarn, 所以有两个选择:可以把 MapReduce 程序直接运行在 HDFS 上,也可以选择运行在
    Yarn 上。

    在 HDFS 上运行 MapReduce 程序

    配置 core-site.xml (核心站点)
    fs.defaultFS

    hdfs://hadoop1_host:9000
    hadoop.tmp.dir
    /home/software/hadoop-2.7.7/data/tmp 配置 hdfs-site.xml (hdfs 站点)
    dfs.replication
    1 这里设置的副本的数量是指 HDFS 上存储的文件的副本。

    格式化 NameNode hdfs namenode -format 启动 namenode hadoop-daemon.sh
    start namenode 启动 datanode hadoop-daemon.sh start datanode 查看
    namenode 和 datanode 是否启动成功 jps 在本地创建一个文件 words.txt, 文件内容可以自己随意添加。
    hello word Big Data test 1 在 hdfs 系统的根目录下创建一个文件夹 /input。 hdfs dfs
    -mkdir /input 把 words.txt 上传到 hdfs 系统上的 /input 目录下 hdfs dfs -put words.txt /input 查看是否上传成功 hdfs dfs -ls /input 在集群上运行 wordcount 程序
    hadoop jar
    share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount
    /input /output 查看输出结果 hdfs dfs -cat /output/part-r-00000 在 Yarn 上运行
    MapReduce 程序

    Hadoop2.x 增加了组件 Yarn, 我们也可以把我们的 MapReduce 程序在 Yarn 上执行。 在前面配置的基础上,配置
    Yarn 就可以了。

    配置 yarn-site.xml
    yarn.nodemanager.aux-services
    mapreduce_shuffle
    yarn.resourcemanager.hostname

    hadoop1_host 配置 /etc/hadoop/mapred-site.xml 复制一份配置

    cp mapred-site.xml.template mapred-site.xml 配置
    /etc/hadoop/mapred-site.xml

    mapreduce.framework.name yarn

    启动 resourcemanager yarn-daemon.sh start resourcemanager
    启动 nodemanager yarn-daemon.sh start nodemanager 运行 MapReduce
    程序:wordcount hadoop jar
    share/hadoop/mapreduce/hadoop-mapreduce-examples-2.7.7.jar wordcount
    /input /output2 查看执行结果 hdfs dfs -cat /output2/part-r-00000 完全分布式模式
    (Fully-Distributed Operation)

    本地运行模式和伪分布运行模式,都是一种单节点运行模式。在实际的生产环境中需要处理的数据量会非常巨大,一个节点不可能完成超大规模数据的计算任务。所以实际生产环境都是使用安全分布式模式部署的。

    为了更真实的模拟实际生产环境中分布式模式的部署情况,我们以三个节点的 Hadoop 分布式模式集群部署为例进行讲解。

    虚拟机准备

    准备 3 个虚拟机,虚拟机的 host 和 ip 地址如下:

    host1 192.168.124.1 host2 192.168.124.2 host3 192.168.124.3
    关闭防火墙,配置好三个机器 Java 环境。

    配置好 SSH 无秘钥登录

    生成秘钥 输入命令 ssh-keygen, 然后连敲 3 次回车。过程不要输入任何信息。

    生成秘钥都存储在:~/.ssh 目录下

    copy 公钥到其他设备 ssh-copy-id 其他主机host 测试能否免密登录 ssh 其他主机host
    需要重复以上操作,将三台机器都配置好。

    规划集群部署和配置

    Yarn 和 Hdfs 需要分散部署到三个虚拟机上。我们按照以下集群部署规划,配置 Hadoop 配置文件。

    host1 host2 host3 HDFS NameNode DateNode DateNode SecondaryNameNode
    DateNode YARN NodeManager ResourceManager NodeManager NodeManager 修改
    hadoop-2.7.7/etc/hadoop 文件夹下面的配置。


core-site.xml
<!-- 指定HDFS中NameNode的地址 -->
  <property>
        <name>fs.defaultFS</name>
        <value>hdfs://host1:9000</value>
   </property>

<!-- 指定hadoop运行时产生文件的存储目录 -->
    <property>
        <name>hadoop.tmp.dir</name>
        <value>/home/software/hadoop-2.7.7/data/tmp</value>
    </property>
hadoop-env.sh
export JAVA_HOME=/home/software/jdk1.8.0_65
hdfs-site.xml
<property>
  <name>dfs.replication</name>
  <value>3</value>
</property>
<property>
   <name>dfs.namenode.secondary.http-address</name>
   <value>host2:50090</value>
</property>
slaves
host1
host2
host3
yarn-env.sh
export JAVA_HOME=/home/software/jdk1.8.0_65
yarn-site.xml
<!-- reducer获取数据的方式 -->
<property>
         <name>yarn.nodemanager.aux-services</name>
         <value>mapreduce_shuffle</value>
</property>
<!-- 指定YARN的ResourceManager的地址 -->
<property>
     <name>yarn.resourcemanager.hostname</name>
     <value>host1</value>
</property>
mapred-env.sh
export JAVA_HOME=/home/software/jdk1.8.0_65
mapred-site.xml
<!-- 指定mr运行在yarn上 -->
<property>
        <name>mapreduce.framework.name</name>
        <value>yarn</value>
</property>
将主节点的 Hadoop 文件分发到另外两个机器
rsync /home/software host2:/opt/
rsync /home/software host3:/opt/

启动集群

  1. 第一次启动时需要格式化 namenode,在 namenode 上格式化

    /hdfs namenode -format 启动 hdfs,在 namenode 上启动 hdfs

    start-dfs.sh 启动 yarn,在 ResourceManager 所在的机器启动 yarn。

    start-yarn.sh 集群启动以后,就可以使用 Hadoop 集群处理你的数据了。

总结

这一节,我带着大家一起学习了三种 Hadoop 运行模式的搭建过程。本地模式 (Standalone)和伪分布式模式 (Pseudo-Distributed) 主要用与我们测试和学习,实际的工业数据生产中使用的是完全分布式模式 (Fully-Distributed Operation)。

以上是关于 Hadoop 的集群部署

23 Apache Hive实战

世上无难事,只要肯登攀。
—伟人
大家好,我是 RangeYan。

上一小节我带着大家一起搭建了一个 Hadoop 集群。这一小节我们一起学习一下 Apache Hive 实战。

在学习 Hive 的实战内容之间我们先简单了解一下 Hive。

Hive 是什么

Hive 是在 Hadoop 分布式文件系统 (HDFS) 之上开发的 ETL 和数据仓库工具,有 Facebook 实现并开源。

Hive 提供写 SQL 的方式对存储在 Hadoop 集群里面的数据进行清洗、加工,生成新的数据并存储到 Hadoop 集群当中。

对于大数据开发技术来说,SQL 是一等公民。

基于 SQL 的数据开发方式,让 Hive 成为了大数据处理领域最重要的一项技术。在 2020 年这个节点下,Hive 数据开发技术依然是数据开发工程师、数据产品经理、数据分析师、数据挖掘工程必备技能。

希望同学们务必认真学习 Hive 的内容,尽可能全部掌握。

Hive 架构

图片描述

Hive 主要由三个部分组成:Clients(客户端)、Serverices(服务)、Storage and compute(存储和计算)。

Clients(客户端):Hive 为与不同类型的应用程序的通信提供了不同的驱动程序。Hive clinets 可以支持 Thrift、JDBC、ODBC 协议与 Hive services 进行通信。

Serverices(服务):Clients 与 Hive 的交互通过 Hive Services 执行。CLI 是命令行界面,充当 DDL(数据定义语言)操作的 Hive 服务。Serverices 核心的模块是 Driver(驱动程序)。

Hive Services、CLI、Hive web Interface 都通过 Driver(驱动程序)对元数据、文件系统进行计算和处理。

Storage and compute(存储和计算):Hive 的元数据存储在元数据数据库中,元数据数据库支持 Mysql 等多种类型。Hive 的查询结果和数据存储在 Hadoop 中。

Hive 部署

依赖环境

Hive 需要 Hadoop 的存储、计算环境,需要数据库存储元数据信息,存储元数据的数据库推荐使用 Mysql 数据库。

所以在部署 Hive 之前需要部署好 Hadoop 和 Mysql。Hadoop 的集群部署步骤我们在上一节讲到了,Mysql 的部署方式请同学们自行 Google。

下载 Hive 安装包

推荐一个 Hive 的下载地址:http://mirrors.hust.edu.cn/apache/hive/

选择 2.3.6 版本的 Hive 并下载 apache-hive-2.3.6-bin.tar.gz 安装包。

解压安装包

tar -zxvf apache-hive-2.3.6-bin.tar.gz
修改配置文件

配置文件所在目录 apache-hive-2.3.6-bin/conf

使用 vi 新建配置文件 hive-site.xml,并添加配置内容

<configuration>
        <property>
                <name>javax.jdo.option.ConnectionURL</name>
                <value>jdbc:mysql://mysqlhost:3306/hivedb?createDatabaseIfNotExist=true</value>
                <description>JDBC connect string for a JDBC metastore</description>
                <!--  用mysql数据库的真实host替换“mysqlhost”  -->
        </property>
        <property>
                <name>javax.jdo.option.ConnectionDriverName</name>
                <value>com.mysql.jdbc.Driver</value>
                <description>Driver class name for a JDBC metastore</description>
        </property>
        <property>
                <name>javax.jdo.option.ConnectionUserName</name>
                <value>root</value>
                <description>username to use against metastore database</description>
        </property>
        <property>
                <name>javax.jdo.option.ConnectionPassword</name>
                <value>root</value>
        <description>password to use against metastore database</description>
        </property>
</configuration>
Mysql 驱动包拷贝

将 mysql-connector-java-5.1.40-bin.jar 拷贝到 apache-hive-2.3.6-bin/lib 下面

配置 Hive 环境变量

用 vi 打开.bashrc 文件

vi ~/.bashrc
在.bashrc 文件重保存以下内容

#Hive
export HIVE_HOME=/home/soft/apache-hive-2.3.6-bin #配置hive安装包目录
export PATH= P A T H : PATH: HIVE_HOME/bin
让配置生效

source ~/.bashrc
初始化 Mysql 数据库

schematool -dbType mysql -initSchema
启动 Hive 客户端

hive --service cli
Hive 数据结构

Hive 的存储结构包括数据库、表、视图、分区和表数据

database:在 HDFS 中表现为 ${hive.metastore.warehouse.dir} 目录下一个文件夹
table:在 HDFS 中表现所属 database 目录下一个文件夹
external table:与 table 类似,不过其数据存放位置可以指定任意 HDFS 目录路径
partition:在 HDFS 中表现为 table 目录下的子目录
bucket:在 HDFS 中表现为同一个表目录或者分区目录下根据某个字段的值进行 hash 散列之后的多个文件
view:与传统数据库类似,只读,基于基本表创建
Hive 中的表分为内部表、外部表、分区表和 Bucket 表。

内部表和外部表的区别:

删除内部表,删除表元数据和数据

删除外部表,删除元数据,不删除数据

分区表和分桶表的区别:

分区和分桶都是细化数据管理,但是分区表是手动添加区分。

由于 Hive 是读模式,所以对添加进分区的数据不做模式校验,分桶表中的数据是按照某些分桶字段进行 hash 散列形成的多个文件,所以数据的准确性也高很多。

Hive 支持的数据类型

类型 描述 示例
boolean true/false TRUE
tinyint 1 字节的有符号整数 -128~127 1Y
smallint 2 个字节的有符号整数,-32768~32767 1S
int 4 个字节的带符号整数 1
bigint 8 字节带符号整数 1L
float 4 字节单精度浮点数 1.0
double 8 字节双精度浮点数 1.0
deicimal 任意精度的带符号小数 1.0
String 字符串,变长 “a”,’b’
varchar 变长字符串 “a”,’b’
char 固定长度字符串 “a”,’b’
binary 字节数组 无法表示
timestamp 时间戳,纳秒精度 122327493795
date 日期 ‘2020-05-09’
array 有序的的同类型的集合 array(1,2)
map key-value,key 必须为原始类型,value 可以任意类型 map(‘a’,1,’b’,2)
struct 字段集合,类型可以不同 struct(‘1’,1,1.0), named_stract(‘col1’,’1’,’col2’,1,’clo3’,1.0)
Hive 默认的行和列分隔符如下表所示

分隔符 描述
\n 对于文本文件来说,每行是一条记录,所以 \n 来分割记录
^A (Ctrl+A) 分割字段,也可以用 \001 来表示
^B (Ctrl+B) 用于分割 Arrary 或者 Struct 中的元素,或者用于 map 中键值之间的分割,也可以用 \002 分割。
^C 用于 map 中键和值自己分割,也可以用 \003 表示。
Hive DDL

DDL 的英文全称是 data definition language,用来对数据库,表结构进行增、删、改操作。

  1. 创建库

创建普通的数据库

create database databaseName1;
创建库的时候检查存与否

create database if not exists databaseName1;
创建库的时候带注释

create database if not exists databaseName1 comment ‘hive learn’;
2. 查看库

查看有哪些数据库

show databases;
显示数据库的详细属性信息

desc database extended databaseName1;
查看创建库的详细语句

show create database databaseName1;
3. 删除库

删除不含表的数据库

drop database databaseName1;
删除含有表的数据库

drop database if exists databaseName1 cascade;
4. 切换库

use databaseName1;
5. 创建表

创建表语句相对比较复杂,下面是创建表的语法规则

CREATE [EXTERNAL] TABLE [IF NOT EXISTS] table_name

[(col_name data_type [COMMENT col_comment], …)]

[COMMENT table_comment]

[PARTITIONED BY (col_name data_type [COMMENT col_comment], …)]

[CLUSTERED BY (col_name, col_name, …)

[SORTED BY (col_name [ASC|DESC], …)] INTO num_buckets BUCKETS]

[ROW FORMAT row_format]

[STORED AS file_format]

[LOCATION hdfs_path]
上面创建表语句字段的解释如下

•CREATE TABLE 创建一个指定名字的表。如果相同名字的表已经存在,则抛出异常;用户可以用 IF NOT EXIST 选项来忽略这个异常
•EXTERNAL 关键字可以让用户创建一个外部表,在建表的同时指定一个指向实际数据的路径(LOCATION)
•LIKE 允许用户复制现有的表结构,但是不复制数据
•COMMENT可以为表与字段增加描述
•PARTITIONED BY 指定分区
•ROW FORMAT
  DELIMITED [FIELDS TERMINATED BY char] [COLLECTION ITEMS TERMINATED BY char]
    MAP KEYS TERMINATED BY char] [LINES TERMINATED BY char]
    | SERDE serde_name [WITH SERDEPROPERTIES
    (property_name=property_value, property_name=property_value, …)]
  用户在建表的时候可以自定义 SerDe 或者使用自带的 SerDe。如果没有指定 ROW FORMAT 或者 ROW FORMAT DELIMITED,将会使用自带的 SerDe。在建表的时候,
用户还需要为表指定列,用户在指定表的列的同时也会指定自定义的 SerDe,Hive 通过 SerDe 确定表的具体的列的数据。
•STORED AS
  SEQUENCEFILE //序列化文件
  | TEXTFILE //普通的文本文件格式
  | RCFILE  //行列存储相结合的文件
  | INPUTFORMAT input_format_classname OUTPUTFORMAT output_format_classname //自定义文件格式
  如果文件数据是纯文本,可以使用 STORED AS TEXTFILE。如果数据需要压缩,使用 STORED AS SEQUENCE 。

•LOCATION指定表在HDFS的存储路径
创建默认的内部表示例如下:

create table car(
id int,
name string,
price double)
row format delimited fields terminated by “,”;
创建外部表

create external table car_ext(
id int,
name string,
price double)
row format delimited fields terminated by “,”
location “/hive/student”;
6. 查看表

show tables;
7. 修改表

修改表名

alter table car rename to car_new;
增加一个字段

alter table car add columns (count int);
修改一个字段的定义

alter table car change name name_new string;
添加一个分区

alter table car add partition(name=“benchi”);
8. 删除表

drop table car;
9. 清空表

truncate table car;
Hive DML

DML 的英文全称是 data managed language,指的是对数据表里面的数据进行操作。

  1. 表数据插入

数据从本地导入

load data local inpath ‘/home/data/car.txt’ into table car;
数据从 HDFS 加载

load data local inpath ‘/home/data/car.txt’ into table car;
单条数据插入

insert into table car values(2,“dazhong”,1000);
多条数据插入

insert into table car2 select * from car where id>80;
2. 单模式导出

insert overwrite local directory ‘home/data/test_hive’ select * from car where id=1303;
3. 数据查询

– SELECT 列名称 FROM 表名称
select name from car;
4. 数据更新

– UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
update cat set name = dazhong2 where id = 1302;
5. 数据删除

– DELETE FROM 表名称 WHERE 列名称 = 值
delete from cat where id = 1302;
6. 数据表连接

内连接 [inner] join

两个表中关联键相同的记录才会查询出来。

select * from a inner join b on a.id=b.id;
外连接 —— 左外连接
以左表为主表,右表中有的就会关联上,右表中没有关联上的数据就用 null 补齐。

select * from a left outer join b on a.id=b.id;
外连接 —— 右外连接
以右表为主表,左表有的则关联,没有则 null 补齐

select * from a right outer join b on a.id=b.id;
外连接 —— 全外连接 full outer join
左表和右表中的并集,左表和右表中所有的数据都会关联上

select * from a full outer join b on a.id=b.id;
半连接 left semi join 左半连接

判断左表中的关联建是否在右表中存在 ,若存在,则返回左表的存在的数据的相关字段,若不存在,则不返回。

select * from a left semi join b on a.id=b.id;
7. 数据分组查询

当查询语句中有 group by 时 select 的字段后面只能跟两种形式的数据:聚合函数 和 group by 的字段。

select name,sum(price) from car group by name;
8. 数据排序

order by 排序字段 asc|desc

全局排序,针对所有的 reduecetask 进行全局排序

select * from car order by name desc limit 20;
sort by 局部排序

针对每一个 reducetask 的结果进行排序的,不保证全局排序, 只有一个 reducetask 的时候 sort by = order by

select * from car sort by name desc;
distribute by 分桶查询的时候的分桶

select * from car distribute by name;
cluster by
distribute by 和 sort by 的字段相同的时候 = cluster by

select * from car cluster by name;
Hive 实战之旅

经过上面的学习我们具备了使用 hive 的基本知识。下面我们通过一个经典的案例,将完成一次 hive 实战之旅。

首先启动 hive cli

hive --service cli
创建一个用户给电影打分的信息表

CREATE TABLE u_data (
  userid INT,
  movieid INT,
  rating INT,
  unixtime STRING)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '\t'
STORED AS TEXTFILE;

下载数据文件

curl --remote-name http://files.grouplens.org/datasets/movielens/ml-100k.zip
解压缩下载后的文件

unzip ml-100k.zip
将解压后的文件导入到 hive 中

‘/u.data’ 替换成你的数据文件实际路径。

LOAD DATA LOCAL INPATH ‘ /u.data’
OVERWRITE INTO TABLE u_data;
下面可以通过查询语句分析已经导入的数据。

例如:求所有电影的总分数

select sum(rating) from u_data;
例如:找出平均分数最高的 3 部电影

 select
 		movieid
 from
 (
 select movieid,avg(rating) over(partition by movieid)   as argv_rating  from u_data 
 ) data
 order by argv_rating desc
 limit 3

总结

这一小节我们学习了 Hive 的架构、部署步骤、数据结构以及 hive 开发需要掌握的 DDL、DML 语句。

最后我们通过一个用户对电影评分的例子,带着大家完成了一次 Hive 实战之旅。这次的内容比较多,也非常的重要,务必认真掌握。

24 Apache Spark RDD 实战

人的差异在于业余时间。
——爱因斯坦

上一个小节我们学习了 Hive 的部署、开发。这一小节我们一起来学习一下 Spark 的部署、Spark RDD 开发。

Spark 运行模式

Spark 运行模式较多,常见的有以下几种

Local:单机,jobs 都在这台机器上运行
Standalone:多台机器组成一个集群,然后 jobs 可以分在多台机器上运行
Spark on Yarn: Spark 程序运行在 Yarn 上
Spark on Mesos: 部署 Spark 集群在 Mesos 上
Spark on Kubernetes: 部署 Spark 集群在 Mesos 上
除了以上的部署模式外还有将 Spark 部署到云计算平台上,例如:Spark on Amazon EC2

Spark 单机模式部署

在实际工业数据生产环境中 Spark on Yarn 的模式应用最为广泛。我在这里以 Spark 单机模式部署为例,让大家具备一个 Spark 的学习环境,Spark on Yarn 的部署步骤也并不复杂,感兴趣的同学可以上 Spark 官网学习一下。

Java 环境搭建

参照本章第一小节部署好 Java 环境

下载 Spark 2.4.5 版本安装包

下载链接:https://www.apache.org/dyn/closer.lua/spark/spark-2.4.5/spark-2.4.5-bin-hadoop2.7.tgz

解压缩 Spark 安装包

tar -zxvf spark-2.4.5-bin-hadoop2.7.tgz
配置 Spark 环境

cp spark-2.4.5-bin-hadoop2.7/conf/spark-env.sh.template spark-env.sh
vim spark-2.4.5-bin-hadoop2.7/conf/spark-env.sh
在文件 spark-env.sh 增加如下内容:

PARK_LOCAL_IP=本机ip
本机 ip 需要替换成你机器的实际 ip 地址。

启动 Spark

在 spark-2.4.5-bin-hadoop2.7 的 bin 目录下执行如下命令:

sh spark-shell --master=local
或者

./spark-shell
Spark-shell 是一个交互式的 spark 运行环境,可以用来运行 Spark RDD、DataSet、DataFrame、Spark Streaming (DStreams)、Structured Streaming 程序。

Spark RDD、DataSet、DataFrame 用来处理批量数据,Spark Streaming (DStreams) 用来处理准实时数据。

Structured Streaming 将数据批处理和数据流式处理在 AIP 层面进行了统一。

Spark RDD 常见操作

RDD 支持两种操作:转化操作(Transformation)和行动操作(Action)。

转化操作时返回一个新的 RDD 的操作,比如 map () 和 filter ()。

行动操作则是向驱动器程序返回结果或把结果写入外部系统的操作,会触发实际的计算,比如 count () 和 first ()。

转换 (Transformations)

对一个数据为 {1, 2, 3, 3} 的 RDD 进行基本的 RDD 转化操作

函数名 目的 示例 结果
map() 将函数应用于 RDD 中的每个元素,将返回值构成新的 RDD rdd.map(x -> x+1) {2, 3, 4, 4}
flatMap() 将函数应用于 RDD 中的每个元素,将返回的迭代器的所有内容构成新的 RDD。通常用来切分单词 rdd.flatMap(x -> x.to(3)) {1, 2, 3, 2, 3, 3, 3}
filter() 返回一个由通过传给 filter () 的函数的元素组成的 RDD rdd.filter(x -> x != 1) {2, 3, 3}
distinct() 去重 rdd.distinct() {1, 2, 3}
sample(withReplacement, fraction, [seed]) 对 RDD 采样,以及是否替换 rdd.sample(false, 0.5) 非确定的
对数据分别为 {1, 2, 3} 和 {3, 4, 5} 的 RDD 进行针对两个 RDD 的转化操作

函数名 目的 示例 结果
union() 生成一个包含两个 RDD 中所有元素的 RDD rdd.union(other) {1, 2, 3, 3, 4, 5}
intersection() 求两个 RDD 共同的元素的 RDD rdd.intersection(other) {3}
subtract() 移除另一个 RDD 中的元素 rdd.subtract(other) {1, 2}
cartesian() 于另一个 RDD 的笛卡尔积 rdd.cartesian(other) {(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 3), (3, 4), (3, 5)}
Pair RDD 转化 (Transformations)

Pair RDD 的转化操作,以键值对 {(1, 2), (3, 4), (3, 6)} 为例

函数名 目的 示例 结果
reduceByKey(func) 合并具有相同键的值 rdd.reduceByKey((x, y) -> x + y) {(1, 2), (3, 10)}
groupByKey() 对具有相同键的值进行分组 rdd.groupByKey() {(1, [2]), (3, [4, 6])}
★ combineByKey(createCombiner, mergeValue, mergeCombiners, partitioner) 使用不同返回类型合并具有相同键的值 见例 4-12 到例 4-14
mapValues(func) 对 pair RDD 中的每个值应用一个函数而不改变键 rdd.mapValues(x -> x + 1) {(1, 3), (3, 5), (3, 7)}
flatMapValues(func) 对 pair RDD 中的每个值应用一个返回迭代器的函数,然后对返回的每个元素都生成一个对应原键值对记录。通常用于符号化 rdd.flatMapValues(x -> (x to 5)) {(1, 2), (1, 3), (1, 4), (1, 5), (3, 4), (3, 5)}
keys() 返回一个仅包含键的 RDD rdd.keys() {1, 3, 3}
values() 返回一个仅包含值的 RDD rdd.values() {2, 4, 6}
sortByKey() 返回一个根据键排序的 RDD rdd.sortByKey() {(1, 2), (3, 4), (3, 6)}
针对两个 Pair RDD 的转化操作,rdd = {(1, 2), (3, 4), (3, 6)} other = {(3, 9)}

函数名 目的 示例 结果
subtractByKey 删掉 RDD 中键与 other RDD 中的键相同的元素 rdd.substractByKey(other) {(1, 2)}
join 对两个 RDD 进行内连接 rdd.join(other) {(3, (4, 9)), (3, (6, 9))}
★ rightOuterJoin 对两个 RDD 进行连接操作,确保第一个 RDD 的键必须存在(右外连接) rdd.rightOuterJoin(other) {(3, (Some(4), 9)), (3, (Some(6), 9))}
★ leftOuterJoin 对两个 RDD 进行连接操作,确保第二个 RDD 的键必须存在(左外连接) rdd.leftOuterJoin(other) {(1, (2, None)), (3, (4, Some(9))), (3, (6, Some(9)))}
cogroup 将两个 RDD 中拥有相同键的数据分组到一起 rdd.cogroup(other) {(1, ([2], [])), (3, ([4, 6], [9]))}
行动 (Actions)

对一个数据为 {1, 2, 3, 3} 的 RDD 进行基本的 RDD 行动操作

函数名 目的 示例 结果
collect() 返回 RDD 中的所有元素 rdd.collect() {1, 2, 3, 3}
count() RDD 中的元素个数 rdd.count() 4
countByValue() 各元素再 RDD 中出现的次数 rdd.countByValue() {(1, 1), (2, 1), (3, 2)}
take(num) 从 RDD 中返回 num 个元素 rdd.take(2) {1, 2}
top(num) 从 RDD 中返回最前面的 num 个元素 rdd.top(2) {3, 3}
takeOrdered(num)(ordering) 从 RDD 中按照提供的顺序返回最前面的 num 个元素 rdd.takeOrdered(2)(myOrdering) {3, 3}
takeSample(withReplacement, num, [seed]) 从 RDD 中返回任意一些元素 rdd.takeSample(false, 1) 非确定的
reduce(func) 并行整合 RDD 中的数据(例如 sum) rdd.reduce((x, y) -> x + y) 9
fold(zeor)(func) 和 reduce () 一样,但是需要提供初始值 rdd.fold(0)((x, y) -> x + y) 9
★ aggregate(zeroValue)(seqOp, combOp) 和 reduce () 相似,但是通常返回不同类型的函数 rdd.aggergate((0, 0))((x, y) -> (x._1 + y, x._2 + 1), (x, y) -> (x._1 + y._1, x._2 + y._2)) (9, 4)
foreach(func) 对 RDD 中的每个元素使用给定的函数 rdd.foreach(func) 无
Pair RDD 行动操作 (Actions)

Pair RDD 的行动操作,以键值对集合 {(1, 2), (3, 4), (3, 6)} 为例

函数名 目的 示例 结果
countByKey() 对每个键对应的元素分别计数 rdd.countByKey() {(1, 1), (3, 2)}
collectAsMap() 将结果以映射表的形式返回,以便查询 rdd.collectAsMap() Map{(1, 2), (3, 6)}
lookup(key) 返回给定键对应的所有值 rdd.lookup(3) [4, 6]
Spark RDD 实战之旅

WorkCount 例子

我们使用一些转换来构建(字符串,整数)对的数据集,counts 然后将其保存到文件中。

avaRDD textFile = sc.textFile(“hdfs://…”);
JavaPairRDD<String, Integer> counts = textFile
.flatMap(s -> Arrays.asList(s.split(" ")).iterator())
.mapToPair(word -> new Tuple2<>(word, 1))
.reduceByKey((a, b) -> a + b);
counts.saveAsTextFile(“hdfs://…”);
Pi 估计

Spark 还可以用于计算密集型任务。此代码通过 “掷飞镖” 来估计 π。我们在单位正方形((0,0)至(1,1))中选择随机点,并查看有多少个落入单位圆。该分数应为 π/ 4,因此我们使用它来获取估计值。

List l = new ArrayList<>(NUM_SAMPLES);
for (int i = 0; i < NUM_SAMPLES; i++) {
l.add(i);
}

long count = sc.parallelize(l).filter(i -> {
double x = Math.random();
double y = Math.random();
return xx + yy < 1;
}).count();
System.out.println("Pi is roughly " + 4.0 * count / NUM_SAMPLES);
Java 状态追踪

我们在内存中初始化一个数组,并将数组里面的数据 collect 出来,在任务执行过程中打印任务信息。

SparkSession spark = SparkSession
.builder()
.appName(APP_NAME)
.getOrCreate();
JavaSparkContext jsc = new JavaSparkContext(spark.sparkContext());

// Example of implementing a progress reporter for a simple job.
 JavaRDD<Integer> rdd = jsc.parallelize(Arrays.asList(1, 2, 3, 4, 5), 5).map(
        new IdentityWithDelay<>());
    JavaFutureAction<List<Integer>> jobFuture = rdd.collectAsync();
    while (!jobFuture.isDone()) {
      Thread.sleep(1000);  // 1 second
      List<Integer> jobIds = jobFuture.jobIds();
      if (jobIds.isEmpty()) {
        continue;
      }
      int currentJobId = jobIds.get(jobIds.size() - 1);
      SparkJobInfo jobInfo = jsc.statusTracker().getJobInfo(currentJobId);
      SparkStageInfo stageInfo = jsc.statusTracker().getStageInfo(jobInfo.stageIds()[0]);
      System.out.println(stageInfo.numTasks() + " tasks total: " + stageInfo.numActiveTasks() +
          " active, " + stageInfo.numCompletedTasks() + " complete");
    }

System.out.println("Job results are: " + jobFuture.get());

总结
这一小节学习了 Spark 的运行模式、部署步骤、RDD 的常见操作方法,然后我们通过三个 Spark RDD 实际的例子让大家感受了 Spark 在数据批处理中的应用。Spark DataFrame、Dataset API 是基于 RDD 的高级 API。

发布了191 篇原创文章 · 获赞 66 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42403069/article/details/105263612