20일 안에 Spark 배우기(0) 가장 간단한 Spark 버전 시작하기

Spark는 Scala로 작성된 빠르고 다재다능하며 확장 가능한 빅데이터 분석 엔진입니다. 소위 빅데이터 분석은 주로 대량의 데이터를 분석하고 처리하며 현재 빅데이터 개발 경력에 필수적인 기술입니다.

1. 간략한 소개

다음은 스파크에 대한 간략한 소개입니다. 뭐, 주로 스파크가 얼마나 좋은지에 대한 이야기인데 보기 싫으시면 바로 2단계로 가셔도 됩니다.

특징

1) 빠름: Hadoop의 MapReduce와 비교하여 Spark의 메모리 기반 작업은 100배 이상 빠르고, 하드 디스크 기반 작업도 10배 이상 빠릅니다. Spark는 메모리를 기반으로 데이터 스트림을 효율적으로 처리할 수 있는 효율적인 DAG 실행 엔진을 구현합니다. 계산의 중간 결과는 메모리에 저장됩니다.

2) 사용 편의성: Spark는 Java, Python 및 Scala API를 지원하며 80개 이상의 고급 알고리즘도 지원하므로 사용자는 다양한 애플리케이션을 빠르게 구축할 수 있습니다. 또한 Spark는 대화형 Python 및 Scala 셸을 지원하며 이러한 셸에서 Spark 클러스터를 사용하여 문제에 대한 솔루션을 확인하는 것이 매우 편리합니다.

3) 범용성: Spark는 통합 솔루션을 제공합니다. Spark는 일괄 처리, 대화형 쿼리(Spark SQL), 실시간 스트림 처리(Spark Streaming), 기계 학습(Spark MLlib) 및 그래프 컴퓨팅(GraphX)에 사용할 수 있습니다. 이러한 다양한 유형의 처리는 모두 동일한 애플리케이션 내에서 원활하게 사용될 수 있습니다. Spark의 통합 솔루션은 매우 매력적입니다. 결국 모든 회사는 통합 플랫폼을 사용하여 직면한 문제를 처리하고 개발 및 유지 관리에 드는 인건비와 플랫폼 배포에 드는 재료비를 절감하기를 원합니다.

4) 호환성: Spark는 다른 오픈소스 제품과 쉽게 통합될 수 있습니다. 예를 들어 Spark는 Hadoop의 YARN 및 Apache Mesos를 리소스 관리 및 스케줄러로 사용할 수 있으며 HDFS, HBase 및 Cassandra를 포함한 모든 Hadoop 지원 데이터를 처리할 수 있습니다. 이는 이미 Hadoop 클러스터를 배포한 사용자에게 특히 중요합니다. 데이터 마이그레이션을 수행하지 않고도 Spark의 강력한 처리 기능을 사용할 수 있기 때문입니다. Spark는 또한 타사 리소스 관리 및 스케줄러에 의존하지 않고 내장된 리소스 관리 및 스케줄링 프레임워크로 Standalone을 구현하여 Spark 사용에 대한 임계값을 더욱 낮추고 누구나 Spark를 매우 쉽게 배포하고 사용할 수 있도록 합니다. 또한 Spark는 EC2에 독립형 Spark 클러스터를 배포하는 도구도 제공합니다.

2. 20줄의 코드로 스파크 시작하기

참고: 현재 환경은 idea + jdk8이며, 이 글의 모든 코드는 이전 Java 프로그래밍 기반을 기반으로 합니다.

1. 항아리 패키지

먼저 idea에서 일반 maven 프로젝트를 생성하고, 프로젝트 pom 파일로 가서 maven dependency를 도입해 주면 도입할 필요가 없다.

<dependencies>
        <!-- scala依赖 开始 -->
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-reflect</artifactId>
            <version>2.12.8</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-library</artifactId>
            <version>2.12.8</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.scala-lang</groupId>
            <artifactId>scala-compiler</artifactId>
            <version>2.12.8</version>
            <scope>compile</scope>
        </dependency>

        <!-- scala依赖 结束 -->

        <!-- spark依赖 开始 -->
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-sql_2.12</artifactId>
            <version>2.4.3</version>
        </dependency>

        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-mllib_2.12</artifactId>
            <version>2.4.3</version>
        </dependency>

        <!-- spark依赖 结束 -->
    </dependencies>

    <build>
        <plugins>
            <!-- 该插件用于将 Scala 代码编译成 class 文件 -->
            <plugin>
                <groupId>net.alchim31.maven</groupId>
                <artifactId>scala-maven-plugin</artifactId>
                <version>3.4.6</version>
                <executions>
                    <execution>
                        <!-- 声明绑定到 maven 的 compile 阶段 -->
                        <goals>
                            <goal>testCompile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

2. 데이터 세트 생성

프로젝트 디렉터리에 데이터를 저장할 데이터 폴더를 생성하고, 워드 파일을 생성한 후 다음 내용을 입력하면,

다음 작업은 스파크 통계를 사용하여 각 단어의 발생 횟수를 분석하는 것입니다.

java~hadoop~java
html~js
java
js~jquery

3. 계산을 위한 WordCount.scala 파일을 생성합니다.파일 형식은 object이므로 Spark를 사용하는 순서는 대략 다음과 같습니다.

1. 스파크 컨텍스트 생성

2. 데이터 파일 읽기

3. 데이터를 적절한 형식으로 처리합니다.

4. 통계적 계산

5. 결과를 얻고 저장하세요

구체적인 처리 코드는 다음과 같습니다

object WordCount {
    
    

  def main(args: Array[String]): Unit = {
    
    
    // 第一个参数启动的方式,第二个参数启动任务的名称
    val spark = new SparkContext("local",
      "WordCount")

    // 读取数据,word就是刚创建的文件
    val data = spark.textFile("data/word")

    // 方便计算的格式
    val result = data
      .flatMap(_.split("~")) // 使用~切分每条记录
      .map((_,1)) // java,1 html,1
     .countByKey() // 统计相同key值的数量

    println(result)
  }

}

마지막으로 각 단어의 발생 횟수가 인쇄됩니다.

이것은 가장 간단한 Spark 사용 사례입니다.

3. 코드 실행 과정 소개

위 코드는 가장 기본적인 스파크 케이스 코드이며, 다음 내용은 위 코드의 실행 과정을 소개합니다.

3.1 공통 키워드

스파크를 학습하기 전, 학생들이 글을 이해하지 못하는 일이 없도록 먼저 자주 사용되는 일련의 키워드를 정리합니다.

RDD

RDD(Resilient Distributed Dataset)는 분산 데이터 세트라고 불리며, 스파크에서 가장 기본적인 데이터 추상화이며, 요소를 병렬로 계산할 수 있는 불변적이고 분할 가능한 집합을 나타내며, 스파크의 기본 개체입니다.

결함:

​세밀한 쓰기 및 업데이트 작업(예: 웹 크롤러)을 지원하지 않습니다.
Spark는 대략적인 방식으로 데이터를 씁니다. 소위 대략적인 방식은 데이터를 일괄적으로 쓰는 것을 의미합니다(일괄 쓰기).
그러나 데이터를 읽는 것은 세분화되어 한 문장으로 작성할 수 있다는 의미입니다. 스트립 읽기(스트립을 하나씩 읽기)는
증분 반복 계산을 지원하지 않지만 Flink에서는 지원합니다.

DAG 방향성 비순환 그래프

루프가 없는 유향 그래프에서는 어떤 정점도 여러 개의 간선을 거쳐 점으로 돌아올 수 없기 때문에 그래프에 루프가 없습니다.
개인적인 느낌: 스파크에서는 다양한 RDD를 상호 변환하여 연산하고 처리하는 것을 말하며 최종적으로 결과는 다음과 같습니다. 획득.

변환 연산자

변환 변환은 스파크에서 RDD 변환을 위한 일련의 방법을 말하며 지연 로딩이므로 즉시 실행되지 않고 작업 연산자를 만날 때만 실행됩니다.

액션 연산자

계산을 처리하거나 수행하는 방법

직업

작업, 프로그램에서 작업 연산자를 만나면 이전 일련의 작업을 수행하기 위해 작업이 제출됩니다. 작업에는 여러 작업이 있으며 작업은 순차적으로 실행됩니다.

폭과 좁음에 대한 의존성

연산자가 실행 중일 때 RDD가 변환됩니다. 이전 RDD가 상위 RDD이고 후속 하위 RDD가 됩니다. 상위 RDD가 맵 연산자와 같은 하위 RDD에 들어가면 좁은 종속성이 됩니다. RDD가 하나 이상의 RDD가 변환되어 생성될 수 있으며, 이를 groupByKey 연산자와 같은 광범위한 종속성이라고 합니다.

단계

작업에는 하나 이상의 단계가 포함됩니다. 각 단계는 순서대로 실행됩니다. 단계 구분은 셔플 종속성을 기반으로 합니다.

단계 구분: Spark 작업은 RDD 간의 종속성을 기반으로 DAG 방향 비순환 그래프를 형성합니다. DAG는 DAGScheduler에 제출됩니다. DAGScheduler는 DAG를 서로 종속된 여러 단계로 나눕니다. 단계 구분의 기초는 다음과 같습니다. RDD 간의 관계는 너비에 따라 다릅니다. 광범위한 종속성이 발생하면 단계가 나누어지고 각 단계에는 하나 이상의 작업이 포함됩니다. 그런 다음 이러한 작업은 실행을 위해 taskSet 형식으로 TaskScheduler에 제출됩니다.

Stage는 계속해서 Task로 분해되는데, Task의 개수는 실제로 Stage의 병렬성, 즉 Task의 최소 실행 단위이며, Task는 궁극적으로 Executor에서 Task 형태로 실행된다.

작업, 단계 및 태스크 관계 요약

Job은 Action 메소드에 의해 제한되며, Action 메소드를 만나면 Job이 트리거됩니다.

Stage는 RDD 전체 종속성(예: Shuffle)으로 제한되는 Job의 하위 집합이며 Shuffle이 발생할 때 한 번 나뉩니다.

작업은 병렬도(파티션 수)로 측정되는 스테이지의 하위 집합입니다. 파티션 수는 작업 수와 동일합니다.

노동자

현재 노드 메모리 및 CPU 사용량을 관리하고, 마스터가 할당한 리소스 지침을 받고, ExecutorRunner 시작 프로그램을 통해 작업을 할당합니다. 작업자는 계약자와 유사합니다. 작업자 프로세스는 토폴로지 구성 요소를 실행하기 위해 하나 이상의 실행기 스레드를 시작합니다( 스파우트 또는 볼트)

집행자

스파크 태스크(task)의 실행 단위는 워커에서 실행되는데, 실제로는 컴퓨팅 자원(cpu 코어, 메모리)의 집합체인 JVM 프로세스이다. 작업자의 메모리와 CPU는 여러 실행기에 의해 공유되며, 스파크 애플리케이션이 시작되면 실행기는 동시에 시작되어 전체 수명 주기를 따릅니다. 두 가지 주요 핵심 기능이 있습니다:
1. Spark 애플리케이션을 구성하는 작업을 실행하고 결과를 드라이버 프로세스에 반환하는 역할
2. 자체 블록 관리자를 통해 사용자 프로그램에서 캐싱이 필요한 RDD에 대한 메모리 내 저장소를 제공합니다. (블록 관리자). RDD는 Executor 프로세스에 직접 캐시되므로 작업은 캐시된 데이터를 최대한 활용하여 런타임 중에 작업을 가속화할 수 있습니다.

분할

Spark 데이터 파티셔닝, 대량의 데이터를 각 노드의 파티션에 할당하여 처리합니다.

혼합

Job은 여러 단계로 나누어져 Wide dependency가 Trigger되면 Shuffle 단계로 진입하며 Shuffle은 Map(Red) 단계와 Reduce(Write) 단계로 나누어진다.

맵 측의 작업 수는 파티션 수와 일치하며, 축소 측에서는 기본 구성으로 Spark.default.parallelism을 사용하며, 그렇지 않은 경우에는 마지막 RDD 파티션 수를 작업 수로 사용합니다.

셔플은 HashShuffle과 SortShuffle로 구분됩니다.

HashShuffle은 동일한 키에 대해 해시 알고리즘을 수행하여 동일한 키를 동일한 디스크 파일에 기록하며
각 디스크 파일은 다운스트림 단계의 하나의 작업에만 속하며 다음 단계에는 몇 개의 작업이 있는지, 몇 개의 작업이 있는지 현재 단계에서는 각 작업에 대해 몇 개의 디스크 파일이 생성됩니까?

Spark.shuffle.consolidateFiles를 true로 설정하면 최적화가 가능하며 shuffleFileGroup이 나타납니다. 실행 중에 각 작업 배치는 새 디스크 파일을 생성하거나 디스크 파일 수를 줄이지 않고도 shuffleFileGroup을 재사용합니다.

SortShuffe는 HashShuffle에 비해 정렬 처리를 추가합니다. SortShuffe는 Spark 1.2 이후 기본으로 사용됩니다. 차이점은 각 작업이 Shuffle 작업을 수행할 때 더 많은 임시 디스크 파일이 생성되지만 결국 모든 임시 파일이 병합된다는 점입니다.) 디스크 파일이 있고 해당 인덱스 파일이 있습니다.

두 가지 작동 모드가 있는데, 첫 번째는 일반 모드이고, 두 번째는 바이패스 모드입니다(읽기 작업 수가 BypassMergeThreshold 매개변수 값보다 작거나 집계 셔플 연산자가 아닌 경우에 입력됨).

바이패스 모드의 차이점: 1. 디스크 쓰기 메커니즘이 다릅니다. 2. 정렬하지 않습니다. 정렬이 수행되지 않으므로 성능 오버헤드 중 이 부분을 절약할 수 있습니다.

주인

클러스터 및 노드를 관리하며 계산에는 참여하지 않습니다.

노동자

컴퓨팅 노드, 프로세스 자체는 계산에 참여하지 않고 마스터에 보고합니다.

ExecutorRunner 시작 프로그램을 통해 현재 노드 메모리 및 CPU 사용량을 관리하고, 마스터가 할당한 자원 지시를 받고, 작업을 할당하는 등 계약자와 유사하며, 새로운 프로세스를 관리 및 할당하고, 계산 서비스를 수행합니다.

운전사

프로그램을 실행하는 주요 방법은 프로그램 입구에 속하며 주요 기능은 1. 사용자 프로그램을 작업(job)으로 변환, 2. 클러스터에서 자원을 적용, 3. 작업의 스케줄링 및 구문 분석을 담당합니다. 4. 스테이지를 생성하고 실행자에게 작업을 예약합니다.

3.2 20줄의 코드 처리 흐름

처리 흐름은 크게 세 부분으로 나눌 수 있는데, 첫 번째는 작업 제출, 두 번째는 해당 리소스 찾기, 두 번째는 작업 예약입니다.

프로그램을 시작하는 방법은 다양하며, 실행 방법은 SparkContext 객체 생성 시 전달된 master 값에 따라 달라집니다. 로컬 실행 방법을 사용할 수 있습니다(일반적으로 코드를 테스트할 때 이 방법을 사용할 수 있습니다).

local: 로컬에서 실행 중, 프로세스 1개, 병렬 처리 없음; local[k]: k 프로세스 실행 중; local[*]: 프로세스 수는 CPU 코어 수와 같습니다.

로컬 시작 외에 클러스터 모드를 사용하여 시작할 수도 있습니다. 일반적인 방법에는 세 가지가 있으며 가장 일반적으로 사용되는 방법은 YARN입니다.

시작 모드 특징 방법
독립형 독립형 모드 완전한 서비스를 갖춘 기본 단순 클러스터 불꽃://
아파치 메소스 분산 자원 관리 프레임워크 메소스://
하둡 원사 Yarn에서 실행되는[참고 1] 통합 리소스 관리 메커니즘은 드라이버 위치에 따라 Yarn 클라이언트와 Yarn 클러스터로 구분됩니다. Yarn 클라이언트: 드라이브는 로컬에서 실행되고 작업은 YRAN 클러스터에서 실행되며 배포 시 –deploy-mode 클라이언트를 사용합니다. Yarn 클러스터: 드라이버와 작업이 모두 클러스터에 있으며 배포 시 –deploy-mode 클러스터를 사용합니다.

참고 1: Hadoop 리소스 관리자인 YARN은 상위 계층 애플리케이션에 대한 통합 리소스 관리 및 스케줄링을 제공할 수 있는 일반 리소스 관리 시스템으로, 도입으로 활용도, 통합 리소스 관리 및 데이터 공유 측면에서 클러스터에 새로운 이점을 가져왔습니다. .. 엄청난 혜택.

위의 코드에서는 local을 사용합니다.

val spark = new SparkContext("local","WordCount")

​ 1. 여기서 실행 시 종속 파일과 jar 패키지를 스캔하고 SparkContext 생성을 시작하고 Driver 측을 초기화한 후 Executor를 준비합니다. 먼저 Driver가 시작되고 Master에 애플리케이션을 등록합니다. Master는 리소스를 기반으로 이를 찾습니다. 제출된 스크립트의 요구 사항 내부 리소스는 모든 작업자 중 최소 하나의 Executor를 시작한 다음 이러한 작업자 사이에 Executor를 할당할 수 있습니다. Worker의 Executor가 시작된 후 드라이버에 역으로 등록됩니다. 모든 Executor가 등록된 후 환경이 초기화되고 작업 실행이 시작됩니다.

2. 드라이버가 메인 기능을 실행하고 DAG 그래프를 작성하기 시작하고 구성이 완료된 후 DAG 그래프가 DAGScheduler에 제출됩니다. DAGScheduler(DAG 스케줄러)는 단계를 나누기 시작하고 Action 연산자에 따라 단계를 나누기 시작합니다. .위 코드에서

.countByKey()

이 메소드는 Action 연산자에 속하며, 이 라인이 실행되면 위의 작업은 한 단계로 나누어지고, 각 단계는 순차적인 종속성을 가지며, 그 단계의 TaskSet이 TaskScheduler로 전송됩니다.

3. TaskScheduler(작업 스케줄러)는 TaskSet(작업 세트)에서 모든 작업을 가져오고 작업 분할은 넓은 종속성과 좁은 종속성에 따라 처리되며 이는 다음 두 줄의 코드입니다.

.flatMap(_.split("~")) // 使用~切分每条记录
.map((_,1)) // java,1 html,1

위의 연산자는 모두 상위 RDD와 1-1 관계를 가지므로 모두 좁은 종속성입니다.

광범위한 종속성은 통합 및 분할을 위해 여러 RDD에 속하며 셔플을 트리거하려면 리소스를 쉽게 소모하는 네트워크 전송이 필요합니다.

​ 4. 다음으로 모든 작업, 데이터, 실행 코드가 executor로 전송되고, executor는 해당 작업을 스레드 풀에 넣어 실행하고, 실행 결과를 TaskScheduler로 피드백하고, TaskScheduler는 그 결과를 다시 TaskScheduler로 피드백한다. 모든 작업이 완료될 때까지 DAGScheduler를 실행하고 모든 리소스를 해제합니다.

추천

출처blog.csdn.net/lihao1107156171/article/details/126403591