saprk及scala环境搭建
*1.本地idea配置scala*
访问scala官网下载scala安装包,windows和linux都需要。

先配置本地scala,解压scala-{版本号}.zip文件配置环境变量,和jdk一样。
SCALA_HOME->new %SCALA_HOME%=”解压路径”
PATH->添加%SCALA_HOME%/bin;
Win+R,输入scala可以运行就配置成功。
打开idea->File->Settings->plugins

从本地选择插件安装
在idea官网上可以找到scala的相关插件,自行选择版本
https://plugins.jetbrains.com/plugin/1347-scala
安装完创建maven项目,要么从pom中导入scala相关jar包,要么右键点击项目

在里面找到scala手动添加##每个项目都需要手动添加,嫌麻烦就在pom里导入jar包依赖
右键main文件夹->new dictionary “scala”->右键scala文件夹->Mark Dictionary as->source root
这样把新创建的scala文件夹作为了项目的代码根文件夹。
创建package->new scala object->scala需要选择object创建。

下面展示一些 内联代码片。
object wordcount {
def main(args: Array[String]): Unit = {
Printf(hello world!)
}
}
先来个helloworld,scala换行就相当于分号了,除非两条代码在同一行需要分号隔开,其他情况基本不需要分号,当然写了不会报错。
至此scala算是完事儿了。
*2.编写spark第一个wordcount程序*
*Pom依赖*
Pom中引入相关依赖,务必刷新maven下载jar包。
<dependencies>
<dependency>
<!-- 引入sparkjar -->
<groupId>org.apache.spark</groupId>
<artifactId>spark-core_2.12</artifactId>
<version>2.4.6</version>
</dependency>
<dependency>
<!-- 引入scala依赖,就不用再手动添加插件了 -->
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.12.8</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-reflect</artifactId>
<version>2.12.8</version>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>2.12.8</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<!-- scala的编译相关插件 -->
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<id>scala-compile-first</id>
<phase>process-resources</phase>
<goals>
<goal>add-source</goal>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.15.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
*遇到问题*
大坑!一开始安装最新的scala2.13.3,这沙雕版本不兼容spark2.4.6,一直报错
Exception in thread “main” java.lang.NoSuchMethodError: scala.util.matching (Java String,Java Long/Scala String,Scala Long)V
或
Exception in thread “main” java.lang.NoClassDefFoundError: scala/Cloneable
就出大问题,这个类型的问题就是版本不兼容,把scala换成2.12.x版本的,spark3.4.5或者3.4.6都可以兼容。版本匹配了还报错需要检查
File->project structure->Global Libraries有可能是scala早就配置好了,删除了重新加载或者手动添加正确版本。
*编写程序*
编写一个spark程序测试。
object wordcount {
def main(args: Array[String]): Unit = {
//链接spark所需配置文件,Master("local")->仅idea运行spark,AppName->进程名
val sparkConf = new SparkConf().setMaster("local").setAppName("WordCount1")
//创建链接和关闭链接
val sc = new SparkContext(sparkConf)
sc.stop()
}
}
运行如果报之前提到的错误就是scala和spark版本不匹配,换匹配的版本就行了。
报Failed to locate the winutils binary in the hadoop binary path是找不到本地的hadoop环境
把hadoop.tar.gz解压了再配置环境变量就行。没必要配置文件,能让程序找到hadoop的环境就行。
如果非要让hadoop在windows运行一个本地版本。
因为hadoop默认是不兼容windows的,需要下载一个winutils插件。
https://github.com/steveloughran/winutils
在这里下载一个合适的版本,大版本一致就行,比如你是2.7.5就可以用2.7.1。解压后用新的bin目录把hadoop/bin替换掉,然后配置hadoop/etc/hadoop/里的配置文件。

这些INFO都是spark的日志信息,虽然是红的但是没有ERROR就算成功。
可以编写spark相关的计算逻辑了。

创建文件夹和两个txt文件,随便弄几个不同的单词
object wordcount {
//链接spark所需配置文件,Master("local")->仅idea运行spark,AppName->进程名
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local").setAppName("WordCount1")
val sc = new SparkContext(sparkConf)
//TODO 读取目录下的文件
//RDD 是spark的计算单位,弹性数据集
val fileRDD: RDD[String] = sc.textFile("input")
//TODO spark自动按行切分,再每行按空格切分单词
val wordRDD: RDD[String] = fileRDD.flatMap(line => {line.split(" ")})
//TODO 将数据分组,就按照单词进行分组,每组一个Iterable迭代器
val groupRDD: RDD[(String,Iterable[String])] = wordRDD.groupBy(word=>word)
//TODO 分组后统计完成合并,把Iterable计数就行
val mapRDD: RDD[(String,Int)] = groupRDD.map {
case (word, iter) => {
(word, iter.size)
}
}
//TODO 采集结果打印控制台,把RDD采集成数组
val wordCountArray: Array[(String,Int)] = mapRDD.collect()
println(wordCountArray.mkString(","))
sc.stop()
}
}
结果正确

红色日志信息很烦,取消spark的日志信息。Resource下创建一个log4j.properties
log4j.rootLogger=ERROR, console
log4j.logger.com.test=DEBUG
log4j.logger.org=ERROR
log4j.logger.org.apache.spark=ERROR
log4j.logger.org.spark-project=ERROR
log4j.logger.org.apache.hadoop=ERROR
log4j.logger.io.netty=ERROR
log4j.logger.org.apache.zookeeper=ERROR
log4j.appender.console=org.apache.log4j.ConsoleAppender
log4j.appender.console.layout=org.apache.log4j.PatternLayout
log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
*优化计算逻辑*
原逻辑:按行读取,按单词切分,把相同单词放入同一个迭代器,统计迭代器size,打印控制台。
优化后逻辑:按行读取,按单词切分,把单词转换为(单词,数量)的kv格式(默认数量为1),合并时直接把数量求和,打印求和结果即可,省略了迭代器的步骤。
object wordCount2 {
def main(args: Array[String]): Unit = {
val sparkConf = new SparkConf().setMaster("local").setAppName("WordCount2")
val sc = new SparkContext(sparkConf)
//TODO 读取目录下的文件
//RDD 是spark的计算单位,弹性数据集
val fileRDD: RDD[String] = sc.textFile("input")
//TODO spark自动按行切分,再每行按空格切分单词
val wordRDD: RDD[String] = fileRDD.flatMap(line => {line.split(" ")})
//TODO 对粉刺后的数据进行结构转换
val mapRDD: RDD[(String,Int)] = wordRDD.map(word => (word, 1))
//TODO 分组聚合,根据单词分组,对value聚合
val wordToSumRDD: RDD[(String,Int)] = mapRDD.reduceByKey(_ + _)
//TODO 打印控制台
val wordCountArray: Array[(String,Int)] = wordToSumRDD.collect()
println(wordCountArray.mkString(","))
sc.stop()
}
}
项目分层
把spark的WordCount项目分为Dao-Service-Controller三层
其中dao负责数据交互,Service是数据分析逻辑,Controller负责控制wordcount
编写一个框架->简化spark链接和关闭链接的步骤
New->package->core
New->Tapplication,Tcontroller,TService,TDao,类型为trait
TApplication中将业务逻辑抽象处理,负责创建链接、关闭链接,之后只需要object wordcount with TApplication即可。
trait TApplication {
var envData : Any = null;
//创建链接
def start(t:String = "jdbc")(op : =>Unit) : Unit={
if(t=="spark"){
val sparkConf = new SparkConf().setMaster("local").setAppName("WordCount1")
envData = new SparkContext(sparkConf)
}
//业务抽象
try{
op
}catch {
case ex: Exception=> println(ex.getMessage)
}
//关闭链接
if(t=="spark"){
val sc :SparkContext = envData.asInstanceOf[SparkContext]
sc.stop()
} }
}
trait TController { def excute():Unit }
trait TDao {def readFile(path:String):RDD[String] = { EnvUtil.getEnv().textFile(path) } }
Wordcount暂时不需要数据交互,所以Dao层为空。
Controller层放置相关控制函数。
class wordCountController extends TController{
private val wordCountService=new wordCountService
override def excute(): Unit = {
val wordCountArray: Array[(String,Int)] = wordCountService.analysis()
println(wordCountArray.mkString(","))
}
}
Service层中放置实际的数据处理逻辑
class wordCountService extends TService{
private val wordCountDao = new wordCountDao
override def analysis(): Array[(String, Int)] = {
val fileRDD: RDD[String] = wordCountDao.readFile("input")
val wordRDD: RDD[String] = fileRDD.flatMap(line => {line.split(" ")})
val mapRDD: RDD[(String,Int)] = wordRDD.map(word => (word, 1))
val wordToSumRDD: RDD[(String,Int)] = mapRDD.reduceByKey(_ + _)
val wordCountArray: Array[(String,Int)] = wordToSumRDD.collect()
return wordCountArray
}
在application中只需要调用controller即可

*3.配置spark集群*
rz命令发送spark.tar.gz文件至三个节点,解压,配置环境变量。
cd spark-3.4.6/conf
mv spark-env.sh.template spark-env.sh
*编辑spark-env.sh*
export SCALA_HOME=/usr/local/bigdata/scala
export JAVA_HOME=/usr/local/bigdata/java/jdk1.8.0_211
export HADOOP_HOME=/usr/local/bigdata/hadoop-2.7.1
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
SPARK_MASTER_IP=Master
SPARK_LOCAL_DIRS=/usr/local/bigdata/spark-2.4.3
SPARK_DRIVER_MEMORY=512M
实际路径根据自身安装路径来。
*配置yarn-site.xml*
添加两条属性,用于检查应用的物理/虚拟内存,超过后不杀死进程(默认是true,会杀死进程)
<property>
<name>yarn.nodemanager.pmem-check-enabled</name>
<value>false</value>
</property>
<property>
<name>yarn.nodemanager.vmem-check-enabled</name>
<value>false</value>
</property>
重启hadoop,重启yarn。
rz发送scala.tart.gz安装包,解压,配置scala环境变量,scala -version 测试。
在确认hadoop和yarn启动后,启动spark,主节点上执行以下命令。因为spark和hadoop都有start-all.sh文件,所以最好切换spark目录执行。然后在主节点上启动spark客户端
./spark-3.4.6/sbin/start-all.shspark-shell --master spark://hadoop01:7077
*Spark测试*
执行一个spark自带的example测试一下,先本地试运行一下。
spark-submit \
--class org.apache.spark.examples.SparkPi \
--master local \
./spark-2.4.6/examples/jars/spark-examples_2.11-2.4.6.jar 10

然后再从yarn上运行,记得将master的参数改为yarn
spark-submit \
--class org.apache.spark.examples.SparkPi \
--master yarn \
./spark-2.4.6/examples/jars/spark-examples_2.11-2.4.6.jar 10
spark非常占用内存,yarn运行时务必给节点足够的内存,不然容易报错。

这里数值有问题是他算法的问题,忽略这个细节。真实环境中一般都用yarn,但是自己虚拟机使用yarn会非常卡,酌情使用。
至此spark开发环境已经搭建完成,进一步学习编写spark项目请移步spark实战项目开发
实战项目中使用的数据下载
实战项目源码下载
大数据hadoop环境搭建教程
apache手动搭建
CDH快速搭建