文章目錄
一 Spark的運行模式
- Local本地模式用於測試環境, 在eclipse或IDEA中
- Standalone是spark自帶的一個調度系統,它支持完全分佈式
- YARN 將spark使用YARN的資源調度來進行執行
- Mesos 也是一種資源調度, 用的人較少
二 spark2.2.0 僞分佈式搭建
-
基本設置:時間同步, 免密登錄, 安裝JDK1.8
-
上傳spark2.2.0 的壓縮包到指定的集羣位置
-
解壓spark2.2.0 的壓縮包
tar -zxvf spark-2.2.0-bin-hadoop2.7.tgz -C /opt/app/
-
進入到spark安裝目錄下 cd spark-2.2.0-bin-hadoop2.7/ 看一下目錄結構
-
修改配置文件 spark-env.sh
-
在文件最後添加環境變量
vi spark-env.sh
JDK安裝路徑, MasterIP地址, Master端口號
export JAVA_HOME=/opt/app/jdk1.8.0_181 export SPARK_MASTER_IP=hadoop export SPARK_MASTER_PORT=7077
-
修改conf目錄下slaves文件
-
將配置好的spark集羣進行分發(這裏是僞分佈式, 不用分發),分發到不同的節點上
scp -r ./spark-2.2.0-bin-hadoop2.7/ hadoop@hadoop02:$PWD
- 安裝spark集羣的所有節點是不需要安裝scala, spark安裝包會集成scala
- 可以配置spark全局環境變量
vi /etc/profile export SPARK_HOME=自己安裝spark路徑 $PATH=$SPARK_HOME/bin:$PATH
-
啓動集羣, 進入到spark安裝目錄中的sbin目錄
-
Jps查看一下(主節點會有Master, 從節點會有worker)
-
spark集羣的webUI界面 port:8080
三 spark 程序執行
- 使用當前spark自帶的任務, 求解 π
- 提交任務的時候需要在當前的$SPARK_HOME/bin目錄下提交
./spark-submit --class org.apache.spark.examples.SparkPi --master spark://hadoop:7077 /opt/app/spark-2.2.0-bin-hadoop2.7/examples/jars/spark-examples_2.11-2.2.0.jar 100
在提交任務的時候可以指定cores 和 memory
./spark-submit \
--class org.apache.spark.examples.SparkPi \
--master spark://hadoop:7077 \
--executor-memory 512m \
--total-executor-cores 1 \
/opt/app/spark-2.2.0-bin-hadoop2.7/examples/jars/spark-examples_2.11-2.2.0.jar 100
//其中--executor-memory 512m 爲設置內存512M, --total-executor-cores 1: 設置總共使用1個核
運行結果
四 sparkShell
spark shell 是spark 自帶的交互式程序, 可以方便的使用命令在shell進行交互式編程, 在shell中可以編寫scala語句. scala語句可以在本地執行, 也可以提交給集羣運行. 一般情況下, shell作爲測試使用
spark -shell兩個模式
- 本地模式[Local]: 在本地模擬啓動一個spark-submit進程, 不會和集羣有任何聯繫
- 集羣模式[cluster]: 將任務提交到集羣上運行,並且可以和集羣進行交互
啓動本地模式:在bin目錄下執行spark-shell
啓動集羣模式: 在bin目錄下執行
./spark-shell \
--master spark://hadoop:7077 \
--executor-memory 512m \
--total-executor-cores 1
//後兩個命令不是必須的, 但是第二個命令是必須要有的, 是集羣的位置, 要寫內部端口
集羣模式下, shell會在webUI界面下只有一個常駐
- 在這裏需要注意的是退出spark-shell的時候不要用Ctrl+C, spark-shell開啓後, 回啓動一個進程來監控一直進行監控, 當使用Ctrl+C後, 這個進程並不會停止, 所以再次啓動shell的時候會出現錯誤, 需要使用命令將這個進程殺死
netstat -apn | grep 4040 kill -9 進程號
五 spark2.2shell和spark1.6shell的對比
spark 2.2創建sparkcontext和sparksession對象的時候會告訴用戶
spark 1.6創建sparkcontext和SQLcontext對象的時候不會告訴用戶
六 Wordcount
6.1 集羣模式版本
- 上傳到hdfs一個文件word.txt
vi word.txt ------------------------ hello world hello zhangsan hello lisi hello wangwu this is a test file there are zhangsan lisi wangwu ------------------------ hdfs dfs -put /
sc.textFile("hdfs://hadoop:8020/word.txt").flatMap(_.split(" ")).map((_,1)).redcueByKey(_+_).saveAsTextFile("hdfs://hadoop:8020/out")
6.2 scala版本的Wordcount
-
maven中pom文件
<properties> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> <encoding>UTF-8</encoding> <scala.version>2.11.8</scala.version> <spark.version>2.2.0</spark.version> <hadoop.version>2.7.1</hadoop.version> <scala.compat.version>2.11</scala.compat.version> </properties> <dependencies> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala.version}</version> </dependency><dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.11</artifactId> <version>${spark.version}</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-client</artifactId> <version>${hadoop.version}</version> </dependency> </dependencies> <build> <sourceDirectory>src/main/scala</sourceDirectory> <!--<testSourceDirectory>src/test/scala</testSourceDirectory>--> <plugins> <plugin> <groupId>net.alchim31.maven</groupId> <artifactId>scala-maven-plugin</artifactId> <version>3.2.2</version> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> <configuration> <args> <arg>-dependencyfile</arg> <arg>${project.build.directory}/.scala_dependencies</arg> </args> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.3</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <filters> <filter><artifact>*:*</artifact> <excludes> <exclude>META-INF/*.SF</exclude> <exclude>META-INF/*.DSA</exclude> <exclude>META-INF/*.RSA</exclude> </excludes> </filter> </filters> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass></mainClass> </transformer> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build>
-
SparkWordCount
import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* * @Description: java類作用描述 * ClassName SparkWordCount * @Author: WCH * @CreateDate: 2018/12/29$ 11:09$ * @Version: 1.0 */ class SparkWordCount { def main(args: Array[String]): Unit = { //模板封裝成一個模板後調用即可 /** * 模板代碼 * 需要創建SparkConf()對象 * 必傳參數1 setAppName("")-->設置任務的名稱, 不傳默認是一個UUID產生的名字 * 必傳參數2 setMaster("")設置運行模式(不寫這個參數可以打包提交到集羣, 寫這個參數可以設置本地模式) * "local"-->本地一個線程進行處理 * "local[數值]"-->開啓相應數值的線程來模擬spark集羣運行任務 * "local[*]"-->當前程序中, 有多少空閒線程, 就使用多少線程類模擬spark集羣運行任務 * */ val conf = new SparkConf().setAppName("SparkWordCount").setMaster("local") //創建sparkContext對象 val sc = new SparkContext(conf) //通過當前sparkContext對象處理數據 //讀取文件, 參數是一個String類型的字符串, 傳入的是一個路徑 val lines: RDD[String] = sc.textFile(args(0)) //切分數據 val words: RDD[String] = lines.flatMap(_.split(" ")) //將每一個單詞生成爲元組 val tuples: RDD[(String, Int)] = words.map((_, 1)) //spark中提供了一個算子, reduceByKey, 相同的key爲一組進行求和 val sumed: RDD[(String, Int)] = tuples.reduceByKey(_ + _) //對當前這個結果進行排序 sortBy()比scala中的sortBy()多了一個參數, 用來指定升序還是降序, 默認true是升序 val sorted: RDD[(String, Int)] = sumed.sortBy(_._2, false) //將數據提交到集羣進行存儲, 無返回值 sorted.saveAsTextFile(args(1)) //本地模式 //一定要設置setMaster() //可以直接打印 println(sorted.collect.toBuffer) //或者 sorted.foreach(println) //回收資源, 結束任務 sc.stop() } }
-
將代碼打包上傳到集羣運行
./spark-submit \ --class Day00.SparkWordCount \ --master spark://hadoop:7077 \ --executor-memory 512m \ --total-executor-cores 1 \ /home/hadoop/data/Spark00-1.0-SNAPSHOT.jar hdfs://hadoop:8020/word.txt hdfs://hadoop:8020/out2
運行效果
查看結果
6.3 Java版本的Wordcount
package Day01;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import org.apache.spark.api.java.function.FlatMapFunction;
import org.apache.spark.api.java.function.Function2;
import org.apache.spark.api.java.function.PairFunction;
import scala.Tuple2;
import java.util.Arrays;
import java.util.Iterator;
public class JavaWordcount {
public static void main(String[] args) {
SparkConf conf = new SparkConf();
conf.setAppName("JavaWordCount");
//這裏在提交到集羣中時需要註釋掉, 否則運行的是local模式
conf.setMaster("local[2]");
JavaSparkContext jsc = new JavaSparkContext(conf);
//獲取數據
JavaRDD<String> lines = jsc.textFile("hdfs://192.168.91.100:8020/word.txt");
//切分
JavaRDD<String> words = lines.flatMap(new FlatMapFunction<String, String>() {
@Override
public Iterator<String> call(String s) throws Exception {
return Arrays.asList(s.split(" ")).iterator();
}
});
//將單詞生成元組
JavaPairRDD<String, Integer> tup = words.mapToPair(new PairFunction<String, String, Integer>() {
@Override
public Tuple2<String, Integer> call(String s) throws Exception {
return new Tuple2<String, Integer>(s, 1);
}
});
//聚合
JavaPairRDD<String, Integer> aggred = tup.reduceByKey(new Function2<Integer, Integer, Integer>() {
@Override
public Integer call(Integer v1, Integer v2) throws Exception {
return v1 + v2;
}
});
//spark 沒有在JavaAPI中提供sortBy算子, 這裏需要把元組中的數據對調一下再進行排序
JavaPairRDD<Integer, String> swaped = aggred.mapToPair(new PairFunction<Tuple2<String, Integer>, Integer, String>() {
@Override
public Tuple2<Integer, String> call(Tuple2<String, Integer> tup) throws Exception {
return tup.swap();
}
});
//排序
JavaPairRDD<Integer, String> sorted = swaped.sortByKey(false);
//將排序後的結果進行反轉
JavaPairRDD<String, Integer> res = sorted.mapToPair(new PairFunction<Tuple2<Integer, String>, String, Integer>() {
@Override
public Tuple2<String, Integer> call(Tuple2<Integer, String> tup) throws Exception {
return tup.swap();
}
});
//返回的是一個數組 Return an array that contains all of the elements in this RDD.
System.out.println(res.collect());
//釋放資源
jsc.stop();
}
}
運行效果
6.4 Lamda表達式版本的Wordcount
package Day01;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaPairRDD;
import org.apache.spark.api.java.JavaRDD;
import org.apache.spark.api.java.JavaSparkContext;
import scala.Tuple2;
import java.util.Arrays;
public class JavaLamdWC {
public static void main(String[] args) {
SparkConf conf = new SparkConf().setAppName("JavaLamdWC").setMaster("local[2]");
JavaSparkContext jsc = new JavaSparkContext(conf);
JavaRDD<String> lines = jsc.textFile("hdfs://hadoop:8020/word.txt");
JavaRDD<String> words = lines.flatMap(line -> Arrays.asList(line.split(" ")).iterator());
JavaPairRDD<String, Integer> tup = words.mapToPair(word -> new Tuple2<>(word, 1));
JavaPairRDD<String, Integer> aggred = tup.reduceByKey((v1, v2) -> v1 + v2);
JavaPairRDD<Integer, String> swaped = aggred.mapToPair(tuple -> tuple.swap());
JavaPairRDD<Integer, String> sorted = swaped.sortByKey(false);
JavaPairRDD<String, Integer> res = sorted.mapToPair(tuple -> tuple.swap());
System.out.println(res.collect());
res.saveAsTextFile("hdfs://hadoop:8020/output");
jsc.stop();
}
}
運行結果