Ubuntu安装docker
参考资料:
https://blog.youkuaiyun.com/qq_33287871/article/details/113359411
更新软件源、安装依赖
sudo apt-get update
sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
添加软件仓库
-
官方仓库
# 添加 Docker 官方的 GPG 密钥(为了确认所下载软件包的合法性,需要添加软件源的 GPG 密钥) curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add - # 设置稳定版本的apt仓库地址 sudo add-apt-repository \ "deb [arch=amd64] https://download.docker.com/linux/ubuntu \ $(lsb_release -cs) \ stable"
-
阿里云仓库
curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg | sudo apt-key add - sudo add-apt-repository \ "deb [arch=amd64] https://mirrors.aliyun.com/docker-ce/linux/ubuntu \ $(lsb_release -cs) \ stable"
安装docker
sudo apt-get install -y docker-ce
查看docker 状态
systemctl status docker
测试:docker hello world
docker pull hello-world
docker images
docker run hello-world
docker下的hadoop集群部署
使用的github地址:big-data-europe/docker-hadoop
https://github.com/big-data-europe/docker-hadoop
使用docker swarm进行部署
docker stack deploy -c docker-compose-v3.yml hadoop
资料,理解swarm
Docker三剑客之Docker Swarm
https://www.cnblogs.com/zhujingzhi/p/9792432.html
docker swarm的常用操作
https://blog.youkuaiyun.com/woshizhangliang999/article/details/90452831
提示:
this node is not a swarm manager. Use "docker swarm init" or "docker swarm join" to connect this node to swarm and try again
解决方法:初始化swarm 环境
E:\programming\BI\docker-hadoop>docker swarm init
Swarm initialized: current node (o3w0067ni69qpejmmygu9slcl) is now a manager.
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-2k4hfth0va728s475gogn5zdv4sm6tj4ugi23m1hmqp7h5rpbp-2n6nw643uxzuzbyfxziw0kvxz 192.168.65.3:2377
To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
再次执行命令,提示:
network "hbase" is declared as external, but could not be found. You need to create a swarm-scoped network before the stack is deployed
原因及解决方法:缺少名为hbase的外部网络,创建一个overlay类型的docker network
E:\programming\BI\docker-hadoop>docker network create --driver overlay hbase
spwoigx80vds25vwf7n12ynqx
资料:
Docker容器跨主机通信–overlay网络
https://www.cnblogs.com/bigberg/p/8521542.html
再次执行命令:
E:\programming\BI\docker-hadoop>docker stack deploy -c docker-compose-v3.yml hadoop
Creating service hadoop_namenode
Creating service hadoop_datanode
Creating service hadoop_resourcemanager
Creating service hadoop_nodemanager
Creating service hadoop_historyserver
成功
通过以下地址访问对应的服务
Namenode: http://<dockerhadoop_IP_address>:9870/dfshealth.html#tab-overview
History server: http://<dockerhadoop_IP_address>:8188/applicationhistory
Datanode: http://<dockerhadoop_IP_address>:9864/
Nodemanager: http://<dockerhadoop_IP_address>:8042/node
Resource manager: http://<dockerhadoop_IP_address>:8088/
- 退出swarm
1.管理器节点离开Docker Swarm模式
docker swarm leave --force
2.普通节点离开Docker Swarm模式
docker swarm leave
3.重新开启Docker Swarm模式
docker swarm init
资料:
https://blog.youkuaiyun.com/weixx3/article/details/103970237
Hadoop+HBase+Spark+Hive环境搭建
资料:
Hadoop+HBase+Spark+Hive环境搭建
https://www.cnblogs.com/cheyunhua/p/10037162.html
.
Hadoop安装教程_单机/伪分布式配置_Hadoop2.6.0(2.7.1)/Ubuntu14.04(16.04)
http://dblab.xmu.edu.cn/blog/install-hadoop/
-
更新软件源:sudo apt-get update
-
(可选)安装vim:sudo apt-get install vim
sudo rm /var/cache/apt/archives/lock sudo rm /var/lib/dpkg/lock
安装screen :apt install screen
-
增加hadoop用户
useradd -m hadoop -s /bin/bash
设置密码
passwd hadoop
切换到hadoop用户
su hadoop
为 hadoop 用户增加管理员权限
:~# adduser hadoop sudo 正在添加用户"hadoop"到"sudo"组... 正在将用户“hadoop”加入到“sudo”组中 完成。
-
安装SSH-server
apt-get install openssh-server
安装后,修改sshd_config配置
vim /etc/ssh/sshd_config
在文件中设置如下属性:(按 / 可以进入搜索模式,按esc退出搜索模 式)
PubkeyAuthentication yes PermitRootLogin yes
重启ssh服务
sudo /etc/init.d/ssh restart
重启后,可以使用如下命令登陆本机,但此时需要密码才能登陆:
ssh localhost
使用 ssh-keygen 生成密钥,并将密钥加入到授权中:cd ~/.ssh/ # 若没有该目录,请先执行一次 ssh localhost ssh-keygen -t rsa # 会有提示,都按回车就可以 cat ./id_rsa.pub >> ./authorized_keys # 加入授权
-
配置java环境
oracle java:https://www.oracle.com/java/technologies/javase-downloads.html
Java SE8:https://download.oracle.com/otn/java/jdk/8u271-b09/61ae65e088624f5aaa0b1d2d801acb16/jdk-8u271-linux-aarch64.tar.gzJava环境推荐使用 Oracle 的 JDK,首先,准备好文件 jdk-8u162-linux-x64.tar.gz,然后将文件移到/usr/local目录下:
mv jdk-8u162-linux-x64.tar.gz /usr/local
解压文件
tar -zxvf jdk-8u162-linux-x64.tar.gz
重命名文件夹为java
mv jdk-1.8.0_162 java
用vim打开/etc/profile文件(Linux下配置系统环境变量的文件)
vim ~/.bashrc
按i进入编辑模式,在文件末尾添加如下JAVA环境变量
export JAVA_HOME=/usr/local/java export JRE_HOME=/usr/local/java/jre export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
添加环境变量后,结果如下图所示,按 esc 退出编辑模式,然后输入:+wq ,按回车保存(也可以按shift + zz 进行保存)。
检验JAVA是否安装成功
echo $JAVA_HOME # 检验变量值 java -version java javac
如果设置正确的话,java -version 会输出 java 的版本信息,java 和 javac 会输出命令的使用指导。
-
安装hadoop
Hadoop 2 可以通过 http://mirror.bit.edu.cn/apache/hadoop/common/ 或者 http://mirrors.cnnic.cn/apache/hadoop/common/ 下载
下载sudo wget http://mirror.bit.edu.cn/apache/hadoop/common/hadoop-2.10.1/hadoop-2.10.1.tar.gz
解压缩
sudo tar -zxvf hadoop-2.10.1.tar.gz
修改文件名
sudo mv ./hadoop-2.10.1 ./hadoop
修改文件权限
sudo chown -R hadoop ./hadoop
Hadoop 解压后即可使用。输入如下命令来检查 Hadoop 是否可用,成功则会显示 Hadoop 版本信息:
#./bin/hadoop version Hadoop 2.10.1 Subversion https://github.com/apache/hadoop -r 1827467c9a56f133025f28557bfc2c562d78e816 Compiled by centos on 2020-09-14T13:17Z Compiled with protoc 2.5.0 From source with checksum 3114edef868f1f3824e7d0f68be03650 This command was run using /usr/local/hadoop/share/hadoop/common/hadoop-common-2.10.1.jar
添加环境变量
export HADOOP_HOME=/usr/local/hadoop export PATH=$PATH:$HADOOP_HOME/bin
Hadoop单机配置(非分布式)
Hadoop 默认模式为非分布式模式(本地模式),无需进行其他配置即可运行。非分布式即单 Java 进程,方便进行调试。
查看hadoop示例
$ ./bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-2.10.1.jar
$ cd /usr/local/hadoop
$ mkdir ./input
$ cp ./etc/hadoop/*.xml ./input # 将配置文件作为输入文件
$./bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-$examples-*.jar grep ./input ./output 'dfs[a-z.]+'
$ cat ./output/* # 查看运行结果
$ ./bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar grep ./input ./output 'dfs[a-z.]+'
单机伪分布式配置
/usr/local/hadoop/etc/hadoop/
伪分布式需要修改2个配置文件 core-site.xml 和 hdfs-site.xml
修改配置文件 core-site.xml
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>file:/usr/local/hadoop/tmp</value>
<description>Abase for other temporary directories.</description>
</property>
<property>
<name>fs.defaultFS</name>
<value>hdfs://localhost:9000</value>
</property>
</configuration>
修改配置文件 hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/data</value>
</property>
</configuration>
配置完成后,执行 NameNode 的格式化:
cd /usr/local/hadoop
./bin/hdfs namenode -format
接着开启 NameNode 和 DataNode 守护进程(启动hadoop)
cd /usr/local/hadoop
./sbin/start-dfs.sh #start-dfs.sh是个完整的可执行文件,中间没有空格
关闭hadoop
sbin/stop-dfs.sh
启动完成后,可以通过命令 jps 来判断是否成功启动,若成功启动则会列出如下进程: “NameNode”、”DataNode” 和 “SecondaryNameNode”(如果 SecondaryNameNode 没有启动,请运行 sbin/stop-dfs.sh 关闭进程,然后再次尝试启动尝试)。如果没有 NameNode 或 DataNode ,那就是配置不成功,请仔细检查之前步骤,或通过查看启动日志排查原因。
/home/app# jps
18802 DataNode
18629 NameNode
19320 SecondaryNameNode
19512 Jps
单机模式,grep 例子读取的是本地数据,伪分布式读取的则是 HDFS 上的数据。要使用 HDFS,首先需要在 HDFS 中创建用户目录:
./bin/hdfs dfs -mkdir -p /user/hadoop
接着将 ./etc/hadoop 中的 xml 文件作为输入文件复制到分布式文件系统中,即将 /usr/local/hadoop/etc/hadoop 复制到分布式文件系统中的 /user/hadoop/input 中。我们使用的是 hadoop 用户,并且已创建相应的用户目录 /user/hadoop ,因此在命令中就可以使用相对路径如 input,其对应的绝对路径就是 /user/hadoop/input:
./bin/hdfs dfs -mkdir input
./bin/hdfs dfs -put ./etc/hadoop/*.xml input
复制完成后,可以通过如下命令查看文件列表:
./bin/hdfs dfs -ls input
伪分布式运行 MapReduce 作业的方式跟单机模式相同,区别在于伪分布式读取的是HDFS中的文件(可以将单机步骤中创建的本地 input 文件夹,输出结果 output 文件夹都删掉来验证这一点)。
./bin/hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar grep input output 'dfs[a-z.]+'
查看运行结果的命令(查看的是位于 HDFS 中的输出结果):
安装Hive
hive官网
下载地址:https://downloads.apache.org/hive/hive-2.3.8/
解压:
sudo tar -zxvf apache-hive-2.3.8-bin.tar.gz
移动并重命名
sudo mv ./apache-hive-2.3.8-bin /usr/local/hive
配置环境变量
sudo vim /root/.bashrc
export HIVE_HOME=/usr/local/hive
export PATH=$PATH:$HIVE_HOME/bin
使环境变量生效
source /root/.bashrc
使用mysql存储hive的元数据,而不是使用hive自带的derby
安装mysql
docker pull mysql:5.7
docker run -d -p 3306:3306 --name myMysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
docker cp myMysql:/etc/mysql /usr/local/docker/container/mysql/config/
docker stop myMysql
docker rm myMysql
docker run -d --name mysql5.7 -p 3306:3306 --restart always --privileged=true -v /usr/local/docker/container/mysql/config:/etc/mysql -v /usr/local/docker/container/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7
docker exec -it XXXXXX /bin/bash
mysql -u root -p
use mysql;
GRANT ALL PRIVILEGES ON . TO ‘root’@’%’ IDENTIFIED BY ‘123456’ WITH GRANT OPTION;
GRANT ALL PRIVILEGES ON . TO ‘root’@‘127.0.0.1’ IDENTIFIED BY ‘123456’ WITH GRANT OPTION;
配置hive
修改/usr/local/hive/conf下的hive-site.xml,执行如下命令:
cd /usr/local/hive/conf
mv hive-default.xml.template hive-default.xml
上面命令是将hive-default.xml.template重命名为hive-default.xml,然后,使用vim编辑器新建一个配置文件hive-site.xml,命令如下:
cd /usr/local/hive/conf
vim hive-site.xml
在hive-site.xml中添加如下配置信息,其中:USERNAME和PASSWORD是MySQL的用户名和密码。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
<property>
<name>javax.jdo.option.ConnectionURL</name>
<value>jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true</value>
<description>JDBC connect string for a JDBC metastore</description>
</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>USERNAME</value>
<description>username to use against metastore database</description>
</property>
<property>
<name>javax.jdo.option.ConnectionPassword</name>
<value>PASSWORD</value>
<description>password to use against metastore database</description>
</property>
</configuration>
下载mysql jdbc
https://dev.mysql.com/downloads/connector/j/
安装
dpkg -i /home/app/mysql-connector-java_8.0.23-1ubuntu20.04_all.deb
查看安装路径
dpkg -l mysql-connector-java
cp一份到hive/lib/路径
cp /usr/share/java/mysql-connector-java-8.0.23.jar /usr/local/hive/lib/
启动hive(启动hive之前,请先启动hadoop集群)。
./usr/local/hadoop/sbin/start-dfs.sh #启动hadoop,如果已经启动,则不用执行该命令
hive #启动hive
/usr/local/hive/conf# hive
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/local/hive/lib/log4j-slf4j-impl-2.6.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/usr/local/hadoop/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Logging initialized using configuration in jar:file:/usr/local/hive/lib/hive-common-2.3.8.jar!/hive-log4j2.properties Async: true
Hive-on-MR is deprecated in Hive 2 and may not be available in the future versions. Consider using a different execution engine (i.e. spark, tez) or using Hive 1.X releases.
执行sql语句报错hive> show databases; FAILED: SemanticException org.apache.hadoop.hive.ql.metadata.HiveException: java.lang.RuntimeException: Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient
解决方法:
schematool -dbType mysql -initSchema
/usr/local/hive/conf# schematool -dbType mysql -initSchema
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/usr/local/hive/lib/log4j-slf4j-impl-2.6.2.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/usr/local/hadoop/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory]
Metastore connection URL: jdbc:mysql://localhost:3306/hive?createDatabaseIfNotExist=true
Metastore Connection Driver : com.mysql.jdbc.Driver
Metastore connection User: root
Starting metastore schema initialization to 2.3.0
Initialization script hive-schema-2.3.0.mysql.sql
Initialization script completed
schemaTool completed
hive> show databases;
OK
default
Time taken: 9.17 seconds, Fetched: 1 row(s)
hive>
资料:
Hive操作异常总结https://blog.youkuaiyun.com/nengliweb/article/details/113100918
hive 配置远程连接
hadoop core-site.xml 中添加
<property>
<name>hadoop.proxyuser.root.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.root.groups</name>
<value>*</value>
</property>
配置中的root是使用beeline 登录hive的linux 账户,根据需要替换成别的账户
配置完毕后重启hadoop 服务:
/usr/local/hadoop/sbin/start-dfs.sh
在hive hive-site.xml中添加:
<name>hive.server2.thrift.port</name>
<value>10000</value>
</property>
<property>
<name>hive.server2.thrift.bind.host</name>
<value>192.168.140.130</value>
</property>
<property>
<name>hive.server2.thrift.client.user</name>
<value>hadoop</value>
<description>Username to use against thrift client</description>
</property>
<property>
<name>hive.server2.thrift.client.password</name>
<value>123456</value>
<description>Password to use against thrift client</description>
</property>
配置thrift ip、端口号、用户名、密码
启动hiveserver2服务
hive --service hiveserver2
在beeline中登录hive
> beeline
beeline> !connect jdbc:hive2://192.168.140.130:10000
Connecting to jdbc:hive2://192.168.140.130:10000
Enter username for jdbc:hive2://192.168.140.130:10000: hadoop
Enter password for jdbc:hive2://192.168.140.130:10000: ******
Connected to: Apache Hive (version 2.3.8)
Driver: Hive JDBC (version 2.3.8)
Transaction isolation: TRANSACTION_REPEATABLE_READ
0: jdbc:hive2://192.168.140.130:10000> show databases;
+----------------+
| database_name |
+----------------+
| default |
+----------------+
1 row selected (1.556 seconds)
0: jdbc:hive2://192.168.140.130:10000>
使用DataGrip连接hive
资料:
https://www.cnblogs.com/zuizui1204/p/9999652.html
基础知识
Hadoop
hadoop fs、hadoop dfs、hdfs dfs命令的区别
- hadoop fs
- hadoop dfs
- hdfs dfs
hadoop fs适用于任何不同的文件系统,比如本地文件系统和HDFS文件系统
hadoop dfs只能适用于HDFS文件系统
hdfs dfs跟hadoop dfs的命令作用一样,也只能适用于HDFS文件系统
Hadoop 运行程序时,输出目录不能存在
Hadoop 运行程序时,输出目录不能存在,否则会提示错误 “org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory hdfs://localhost:9000/user/hadoop/output already exists” ,因此若要再次执行,需要执行如下命令删除 output 文件夹:
./bin/hdfs dfs -rm -r output # 删除 output 文件夹
MapReduce
"Map(映射)“和"Reduce(归约)”
两大耗时操作
磁盘I/O、网络I/O
资料:
https://baike.baidu.com/item/MapReduce/133425?fr=aladdin
3. Spark API
3.1 RDD核心术语
title | content |
---|---|
Application | Spark的应用程序,包含一个Driver program和若干个Executor |
SparkContext | Spark应用程序的入口,负责调度个个运算资源,协调各个Worker Node上的Executor |
Driver Program | 运行Application的main()函数并且创建SparkContext |
Executor | 是Application运行在Work node上的一个进程,该进程负责运行Task,并且负责将数据存在内存或者磁盘上,每个Application都会申请各自的Executor来处理任务 |
Cluster Manager | 在集群上获取资源的外部服务(例如:Standalone,Mesos,Yarn) |
Worker Node | 集群中任何可以运行Application代码的节点,运行一个或者多个Executor进程 |
Task | 运行在Executor上的工作单元; |
Job | SparkContext提交具体的Action操作,场合Action对应 |
Stage | 每个Job会被拆分为很多组任务(Task),每组任务被称为Stage,也成为TaskSet |
RDD | Resilient Distributed Datasets,中文为弹性分布式数据集,是Spark最核心的模块和类 |
DAG Scheduler | 根据Job构建基于Stage的DAG,并提交Stage给TaskScheduler |
Task Scheduler | 将Taskset提交给Worker node,集群运行并返回结果 |
Transformations/Actions | Spark API的两种类型之一,Transformations返回值还是一个RDD,Actions返回值不是一个RDD,而是一个Scala集合,所有的Transformations都是采用的Lazy策略,如果只是将Transformation提交是不会执行计算的,计算只会在Action提交时才会被触发 |
3.2 理解RDD
- RDD:(Resilient Distributed Dataset)弹性分布数据集。指的是一个只读的,可分
区的分布式数据集,这个数据集的全部或部分可以缓存在内存中,在多次计算间重用。 - 数据集:RDD 是数据集合的抽象,是复杂物理介质上存在数据的一种逻辑视图。从外
部来看,RDD 的确可以被看待成经过封装,带扩展特性(如容错性)的数据集合。 - 分布式:RDD的数据可能在物理上存储在多个节点的磁盘或内存中,也就是所谓的多级
存储。 - 弹性:如果数据集的一部分数据丢失,则可以对它进行重建;具有自动容错,位置感知
调度和可伸缩性,而容错性是最难实现的。 § 大部分分布式数据集的容错性有两种:数据检查点(成本高)和记录数据的更新(依赖
关系)。
3.3 RDD分区
- RDD对象实质上是一个元数据结构,存储着
Block、Node等映射关系,以及其他元数据信
息。一个RDD就是一组分区(Partition),
RDD的每个分区Partition对应一个Block,
Block可以存储在内存,当内存不够时可以存
储到磁盘上。 - RDD的数据源也可以存储在HDFS上,数据按
照HDFS分布策略进行分区,HDFS中的一个
Block对应Spark RDD的一个Partition。
3.4 RDD依赖
窄依赖(Narrow Dependency):转换前后RDD分区进行的是一对一转换(父RDD对应一个子RDD)
宽依赖(Wide Dependency 或者是 Narrow Dependency):转换前后一个RDD分区对应多个RDD分区(父RDD对应多个子RDD)
也可依据是否存在shuffle操作进行判别,无shuffle为窄依赖,有shuffle为宽依赖。
窄依赖是指每个父RDD的一个Partition最多被子RDD的一个Partition所使用,例如map、filter、union等操作都会产生窄依赖;
宽依赖是指一个父RDD的Partition会被多个子RDD的Partition所使用,例如groupByKey、reduceByKey、sortByKey等操作都会产生宽依赖;资料来源:
https://www.cnblogs.com/zlslch/p/5942204.html
在每个RDD分区中都存在类别A、类别B、类别C三类数据,通过shuffle操作将各类数据进行归类。
stage dag
spark 运行态
- 静态视图static view :即RDD, transformation and action
- 动态视图dynamic view: 即life of a job,每一个job又分为多
个stage,每一个stage中可以包含多个rdd及其transformation,
这些stage又是如何映射成为task被distributed到cluster中
3.5 transformations、actioins操作
- Transformations: Spark API的两种类型之一,Transformations返回值还是一个RDD,
- Actions: Actions返回值不是一个RDD,而是一个Scala集合
- 所有的Transformations都是采用的Lazy策略,如果只是将Transformation提交是不会
执行计算的,计算只会在Action提交时才会被触发
Transformation | Meaning |
---|---|
map(func) | Return a new distributed dataset formed by passing each element of the source through a function func. 返回一个新的分布式数据集,该数据集是通过函数func传递源的每个元素而形成的。 |
filter(func) | Return a new dataset formed by selecting those elements of the source on which funcreturns true. 返回一个新的数据集,该数据集通过选择函数返回true的源元素而形成。 |
flatMap(func) | Similar to map, but each input item can be mapped to 0 or more output items (so funcshould return a Seq rather than a single item). 与map类似,但每个输入项都可以映射到0个或多个输出项(因此funcy应该返回Seq而不是单个项)。 |
mapPartitions(func) | Similar to map, but runs separately on each partition (block) of the RDD, so func must be of type Iterator => Iterator when running on an RDD of type T. |
mapPartitionsWithIndex(func) | Similar to mapPartitions, but also provides func with an integer value representing the index of the partition, so func must be of type (Int, Iterator) => Iterator when running on an RDD of type T. |
sample(withReplacement,fraction,seed) | Sample a fraction fraction of the data, with or without replacement, using a given random number generator seed. |
union(otherDataset) | Return a new dataset that contains the union of the elements in the source dataset and the argument. |
intersection(otherDataset) | Return a new RDD that contains the intersection of elements in the source dataset and the argument. |
distinct([numTasks])) | Return a new dataset that contains the distinct elements of the source dataset. |
groupByKey([numTasks]) | When called on a dataset of (K, V) pairs, returns a dataset of (K, Iterable) pairs. Note: If you are grouping in order to perform an aggregation (such as a sum or average) over each key, using reduceByKey or aggregateByKey will yield much better performance. Note: By default, the level of parallelism in the output depends on the number of partitions of the parent RDD. You can pass an optional numTasks argument to set a different number of tasks. |
reduceByKey(func, [numTasks]) | When called on a dataset of (K, V) pairs, returns a dataset of (K, V) pairs where the values for each key are aggregated using the given reduce function func, which must be of type (V,V) => V. Like in groupByKey, the number of reduce tasks is configurable through an optional second argument. |
aggregateByKey(zeroValue)(seqOp,combOp, [numTasks]) | When called on a dataset of (K, V) pairs, returns a dataset of (K, U) pairs where the values for each key are aggregated using the given combine functions and a neutral “zero” value. Allows an aggregated value type that is different than the input value type, while avoiding unnecessary allocations. Like in groupByKey, the number of reduce tasks is configurable through an optional second argument. |
sortByKey([ascending], [numTasks]) | When called on a dataset of (K, V) pairs where K implements Ordered, returns a dataset of (K, V) pairs sorted by keys in ascending or descending order, as specified in the boolean ascending argument. |
map、flatmap操作
object MapFilterStudy {
def main(args: Array[String]) {
Logger.getLogger("org").setLevel(Level.ERROR)
val sparkConf = new SparkConf().setAppName("spark api").setMaster("local")
val sparkContext = new SparkContext(sparkConf)
val data = Array(1, 2, 3, 4, 5)
val inputRdd = sparkContext.parallelize(data)
val dataArr = Array(Array(2, 3), Array(4, 5))
val inputRdd2 = sparkContext.parallelize(dataArr)
inputRdd.foreach(println(_))
System.out.println("-------------")
inputRdd.map(x => {
x * 2
})
.filter(x => {
if (x > 5) {
true
} else {
false
}
})
.foreach(println(_))
System.out.println("-------------")
inputRdd2.flatMap(x => {
x.map(y => {
y * 2
})
}).foreach(println(_))
}
}
join 操作
object UnionStudy {
def main(args: Array[String]) {
Logger.getLogger("org").setLevel(Level.ERROR)
val sparkConf = new SparkConf().setAppName("spark api").setMaster("local")
val sparkContext = new SparkContext(sparkConf)
val data = Array(1, 2, 3, 4, 5)
val inputRdd = sparkContext.parallelize(data)
val inputRdd2 = inputRdd.map(_ * 2)
val unionRdd = inputRdd.union(inputRdd2).foreach(println(_))
// 两个RDD中取交集
val joinLeft = inputRdd.map(x => {
(x, 1)
})
val joinRight = inputRdd2.map((_, 2))
joinLeft.join(joinRight).foreach(println(_))
}
}
partition操作(mapPartitions、rePartitions)
object PartitionStudy {
def main(args: Array[String]) {
Logger.getLogger("org").setLevel(Level.ERROR)
val sparkConf = new SparkConf().setAppName("spark api").setMaster("local")
val sparkContext = new SparkContext(sparkConf)
val data = Array(1, 2, 3, 4, 5, 100, 200, 300, 500, 23, 24, 25, 45, 23)
val inputRdd = sparkContext.parallelize(data, 5)
inputRdd.mapPartitions(x => {
// database connection
x.map(y => {
// database insert
y * 2
})
})
// .foreach(println(_))
inputRdd.mapPartitionsWithIndex((idx, iter) => {
iter.map(x => {
(idx, x)
})
})
// .foreach(println(_))
inputRdd.repartition(6).mapPartitionsWithIndex((idx, iter) => {
iter.map(x => {
(idx, x)
})
})
.foreach(println(_))
inputRdd.coalesce(2,false).mapPartitionsWithIndex((idx,iter)=>{
iter.map(x=>{
(idx,x)
})
})
.foreach(println(_))
}
}
group操作
object GroupStudy {
def main(args: Array[String]) {
Logger.getLogger("org").setLevel(Level.ERROR)
val sparkConf = new SparkConf().setAppName("spark api").setMaster("local")
val sparkContext = new SparkContext(sparkConf)
val data = Array(Tuple2(1, 2), Tuple2(1, 4), Tuple2(1, 3), Tuple2(2, 2), Tuple2(2, 4), Tuple2(3, 2))
val inputRdd = sparkContext.parallelize(data)
// inputRdd.groupBy(_._1).foreach(println(_))
// inputRdd.groupByKey().foreach(println(_))
// inputRdd.reduceByKey(_+_).foreach(println(_))
}
}
通过groupByKey实现reduceByKey操作
inputRdd.groupByKey().map(x => {
val key = x._1
var sum = 0
x._2.map(y => {
sum += y
})
(key,sum)
}).foreach(println(_))
4. Spark运行模式及原理
4.1 Spark计算细节
关于SparkContext
SparkContext是spark功能的主要入口。其代表与spark集群的连接,能够用来在集群上创建RDD、累加器、广播变量。每个JVM里只能存在一个处于激活状态的SparkContext,在创建新的SparkContext之前必须调用stop()来关闭之前的SparkContext,这种限制在以后可能会被取消
Main entry point for Spark functionality. A SparkContext represents the connection to a Spark cluster, and can be used to create RDDs, accumulators and broadcast variables on that cluster.
Only one SparkContext may be active per JVM. You must stop() the active SparkContext before creating a new one. This limitation may eventually be removed; see SPARK-2243 for more details.
.
http://spark.apache.org/docs/1.3.0/api/java/org/apache/spark/SparkContext.html
关于SparkContext.textFile()
获取文件内容
HadoopRDD经过flatMap变为FlatMappedRDD,经过map变为MappedRDD,经过reduceByKey变为ShuffiledRDD
reduceByKey:依据key对数据进行聚合
关于RDD
RDD的优点:
1.相比于传统的MapReduce框架,Spark在RDD中内置很多函数操作,group,map,filter等,方便处理结构化或非结构化数据。
2.面向对象编程,直接存储的java对象,类型转化也安全
RDD的缺点:
1.由于它基本和hadoop一样万能的,因此没有针对特殊场景的优化,比如对于结构化数据处理相对于sql来比非常麻烦
2.默认采用的是java序列号方式,序列化结果比较大,而且数据存储在java堆内存中,导致gc比较频繁
stage划分依据:是否有shuffle操作
一个Job中有多个stage(存在shuffle操作)
4.2 Spark运行模式列表
在实际应用中,Spark应用程序的运行模式取决于传递给SparkContext的MASTER环境变量的值,个别模式还需要依赖辅助的程序接口来配合使用,目前所支持的MASTER环境变量由特定的字符串或URL所组成,如下所示
Local[N]:本地模式,使用N个线程。
Spark://hostname:port:Standalone模式,需要部署Spark到相关节点,URL为Spark Master主机地址和端口。
Mesos://hostname:port:Mesos模式,需要部署Spark和Mesos到相关节点,URL为Mesos主机地址和端口。
YARN Yarn cluster:YARN模式一,主程序逻辑和任务都运行在YARN集群中。
YARN client:YARN模式二,主程序逻辑运行在本地,具体任务运行在YARN集群中
4.3 Spark基本工作流程
Spark应用分为任务调度和任务执行两部分
下图为分布式模式下,Spark的各个调度和执行模块的大致框架图。对于本地模式来说,其内部程序逻辑结构也是类似的,只是其中部分模块有所简化,例如集群管理模块简化为进程内部的线程池。
所有的Spark应用程序都离不开SparkContext和Executor两部分,Executor负责执行任务,运行Executor的机器称为Worker节点,SparkContext由用户程序启动,通过资源调度模块和Executor通信。
不同运行模式的区别主要体现在任务调度模块。不同的部署和运行模式,根据底层资源调度方式的不同,各自实现了自己特定的任务调度模块,用来将任务实际调度给对应的计算资源。
4.4 Spark调度
- RDD调度,根据数据流向建立DAG图
- DAG调度,拆分图到tasks的stage中去执行
- Task调度,通过cluster manager运行task
- Worker调度
以SparkContext为程序运行的总入口,在SparkContext的初始化过程中,Spark会分别创建DAGScheduler作业调度和TaskScheduler任务调度两级调度模块。
作业调度模块是基于任务阶段的高层调度模块,它为每个Spark作业计算具有依赖关系的多个调度阶段(通常根据shuffle来划分),然后为每个阶段构建出一组具体的任务(通常会考虑数据的本地性等),然后以TaskSets(任务组)的形式提交给任务调度模块来具体执行。
任务调度模块则负责具体启动任务、监控和汇报任务运行情况。
4.5 YARN cluster模式
-
部署及程序运行
YARN cluster模式,顾名思义就是通过Hadoop YARN框架来调度Spark应用所需的资源。YARN standalone这个名字是在0.9之前的版本使用的,在1.0以后改名为YARN cluster。 -
打包
对于Spark来说,需要做的准备工作包括通过sbt assembly命令将所有的依赖关系打包成一个大的JAR包供YARN调度框架使用
所获得的JAR包,可以上传到HDFS中,也可以放在本地。同样的,你的应用程序本身也需要打包成JAR包供YARN调度框架使用。 -
配置
对于YARN模式来说,还有一些特定的参数可以通过Conf文件或编程直接配置,用于调整运行时的行为,如下所示。
spark.yarn.applicationMaster.waitTries
:尝试等待Spark Master启动和初始化完成的次数,默认为10。
spark.yarn.submit.file.replication
:Spark应用程序的依赖文件上传到HDFS时,在HDFS中的备份的拷贝数量
spark.yarn.preserve.staging.files
:在应用程序结束后是否保留上述上传的文件。
spark.yarn.scheduler.heartbeat.interval-ms
:Spark Application Master向YARN ResourceManager 发送心跳(Heartbeat)的时间间隔,默认为5秒。
spark.yarn.max.worker.failures
:在认为一个应用程序运行失败之前,允许运行失败的Worker的最大数量。
在YARN cluster模式下,需要通过额外的辅助程序来启动应用:
以SparkPi为例:
$ SPARK_JAR=./assembly/target/scala-2.10/spark-assembly-0.9.1-hadoop2.2.0.jar \
./bin/spark-class org.apache.spark.deploy.yarn.Client \
--jar examples/target/scala-2.10/spark-examples-assembly-0.9.1.jar \
--class org.apache.spark.examples.SparkPi \
--args yarn-standalone \
--num-workers 3 \
--master-memory 4g \
--worker-memory 2g \
--worker-cores 1
--jar
:指定jar包路径
--class
:
--args yarn-standalone
:运行模式
--num-workers
:工作节点数量
--master-memory
:master节点内存大小
--worker-memory
:worker节点内存大小
--worker-cores
:worker节点使用的内核数量
用户提交spark程序(脚本、命令行)
创建ClientEndPoint对象,负责与master进行通信交互
4.6 spark shuffle
- 原始的hash-based shuffle
以hash的形式进行映射
Spark HashShuffle 是它以前的版本,现在1.6x 版本默应是 Sort-Based Shuffle,那为什么要讲 HashShuffle 呢,因为有分布式就一定会有 Shuffle,而且 HashShuffle 是 Spark以前的版本,亦即是 Sort-Based Shuffle 的前身,因为有 HashShuffle 的不足,才会有后续的 Sorted-Based Shuffle
上图每1个 Task 输出3份本地文件,这里有4个 Mapper Tasks,所以总共输出了4个 Tasks x 3个分类文件 = 12个本地小文件。
HashShuffle 也有它的弱点:
Shuffle前在磁盘上会产生海量的小文件,此时会产生大量耗时低效的 IO 操作 (因為产生过多的小文件)
内存不够用,由于内存中需要保存海量文件操作句柄和临时信息,如果数据处理的规模比较庞大的话,内存不可承受,会出现 OOM 等问题。
-
Consolidated Hash-Based Shuffle
-
Sorted-based shuffle
Sorted-Based Shuffle 的核心是借助于 ExternalSorter 把每个 ShuffleMapTask 的输出,排序到一个文件中 (FileSegmentGroup),为了区分下一个阶段 Reducer Task 不同的内容,它还需要有一个索引文件 (Index) 来告诉下游 Stage 的并行任务,那一部份是属于你的。
FileSegment根据PartionID排序
总结
减少临时文件个数
5.Spark集群应用与监控
Spark监控管理
- Spark UI
网页形式,方便肉眼观察 - Spark Metrics
Metrics形式,可定制,功能强大 - Spark REST API
可基于API开发监控应用程序定制化监控 - 外部工具
Ganglia、Zabbix等,方便纳入统一监控体系
Spark UI监控
实时UI监控
默认启用
即时刷新查看
作业结束后无法访问
历史UI监控
需手动启用
作业结束后也能访问