반응형

오늘은 HDFS로부터 클라이언트가 어떤 프로세스로 데이터를 읽는지에 대해 정리해보겠습니다. 



해당 내용은 '하둡 완벽 가이드(4)' 대한 정리 내용입니다.


[ HDFS에서 파일 읽기 ]

1. 클라이언트는 HDFS가 DistributedFileSystem 인스턴스인 FileSystem객체의 open() 메서드를 호출하여 원하는 파일을 엽니다.

2. DistributedFileSystem은 파일의 첫 번째 블록 위치를 파악하기 위해 RPC(Remote Procedure Call)를 사용하여 네임노드를 호출합니다. 네임노드는 블록별로 해당 블록의 복제본을 가진 데이터노드의 주소를 반환하는데 이때 클러스터의 네트워크 위상에 따라 클라이언트와 가까운 순으로 데이터노드가 정렬됩니다. 또한 클라이언트 자체가 데이터노드(예를 들면 맵리듀스 태스크)고 해당 블록의 복제본을 가지고 있으면 클라이언트는 로컬 데이터노드에서 데이터를 읽습니다.

3. 클라이언트는 스트림을 읽기 위해 read() 메서드를 호출합니. 파일의 첫 번째 블록의 데이터노드 주소를 저장하고 있는 DFSInputStream은 가장 가까운(첫 번째) 데이터노드와 연결합니다.

4. 해당 스트림에 대해 read() 메서드를 반복적으로 호출하면 데이터노드에서 클라이언트로 모든 데이터가 전송됩니다.

5. 블록의 끝에 도달하면 DFSInputStream은 데이터노드의 연결을 닫고 다음 블록의 데이터노드를 찾습니다. 클라이언트 관점에서 이러한 과정은 투명하게 전개되며 클라이언트는 단지 연속적인 스트림을 읽는 것처럼 느낍니다. 클라이언트는 스트림을 통해 블록을 순서대로 하나씩 읽고 DFSInputStream은 블록마다 데이터노드와 새로운 연결을 맺습니다. 클라이언트는 다음 블록의 데이터노드 위치를 얻기 위해 네임노드를 호출합니다.

6. 모든 블록에 대한 읽기가 끝나면 클라이언트는 FSDataInputStream의 close() 메서드를 호출합니다.


[ HDFS에서 데이터를 읽다가 데이터노드와의 통신 장애가 발생하는 경우 ]

데이터를 읽는 중에 데이터노드와 통신 장애가 발생하면 DFSInputStream은 해당 블록을 저장하고 있는 다른 데이터노드와 연결을 시도합니다. 이후 블록에 대한 불필요한 재시도를 방지하기 위해 장애가 발생한 데이터노드를 기억해둡니다. DFSInputStream은 데이터노드로부터 전송된 데이터의 체크섬도 검증합니다. 블록이 손상되었으면 DFSInputStream은 다른 데이터노드에 있는 블록의 복제본을 읽으려고 시도합니다. 물론 손상된 블록에 대한 정보는 네임노드에 보고됩니다.

[ HDFS 파일 읽기 설계의 핵심 ]

클라이언트는 데이터를 얻기 위해 데이터노드에 직접적으로 접촉하고, 네임노드는 각 블록에 적합한 데이터노드를 안내해주는 역할을 합니다. 데이터 트래픽은 클러스터에 있는 모든 데이터노드에 고르게 분산되므로 HDFS는 동시에 실행되는 클라이언트의 수를 크게 늘릴 수 있습니다. 한편으로 네임노드는 효율적인 서비스를 위해 메타데이터를 메모리에 저장하고 단순히 블록의 위치 정보 요청만 처리하며, 데이터를 저장하거나 전송하는 역할은 맡지 않으므로 클라이언트가 많아져도 병목현상은 거의 발생하지 않습니다.


포스팅을 마치도록 하겠습니다. 감사합니다:)



반응형
반응형

오늘은 HDFS 고가용성에 대해서 포스팅 정리~!


해당 내용은 '하둡 완벽 가이드(4)' 대한 정리 내용입니다.


[ HDFS 고가용성 ]

데이터 손실을 방지하기 위해 네임노드 메타데이터를 다수의 파일시스템에 복제하는 방식과 보조 네임노드를 사용하여 체크포인트를 생성하는 방식을 조합해서 활용할 수 있다. 그러나 이러한 방법도 파일시스템의 고가용성을 궁극적으로 보장하지는 않는다. 네임노드는 여전히 단일 고장점(SPOF, Single Point Of Failure)이다. 네임노드에 장애가 발생하면 맵리듀스 잡을 포함하여 모든 클라이언트가 파일을 읽거나 쓰거나 조회할 수 없게 된다. 네임노드는 메타데이터와 파일 블록의 매핑 정보를 보관하는 유일한 저장소이기 때문이다. 


[ HDFS 네임노드가 장애났을 경우 새로운 네임노드로 재구동 과정 - HA 구성 아닌 경우 ]

네임노드의 장애를 복구하기 위해 관리자는 파일시스템 메타데이터 복제본을 가진 새로운 네임노드를 구동하고 모든 데이터노드와 클라이언트에 새로운 네임노드를 사용하도록 알려주면 된다. 

1. 새로운 네임노드는 네임스페이스 이미지를 메모리에 로드한다.

2.에디트 로그를 갱신한다.

3.전체 데이터노드에서 충분한 블록 리포트를 받아 안전 모드를 벗어 날 때까지 어떤 요청도 처리하지 못한다.

이러한 과정을 거치는데 많은 파일 블록과 대형 클러스터에서 새로운 네임노드 재구성 까지는 30분 이상 걸리는 경우도 있다. (즉, 이런 장애 복구에 걸리는 시간을 감안할 수 있다면 이것도 하나의 방법이 될 수 있다.) 사실 네임노드의 갑작스런 장애는 거의 발생하지는 않는다. 


[ HDFS 고가용성(HA, High availability) - 하둡 2.x 릴리즈부터 ]

위와 같이 재구성하는데 오래걸리는 문제를 해결하기 위해 하둡 2.x릴리즈부터 hdfs의 고가용성을 지원한다. 

고가용성은 활성대비(active-standby)상태로 설정된 한 쌍의 네임노드로 구현된다. 활성 네임노드(active namenode)에 장애가 발생하면 대기 네임노드(standby namenode)가 그 역할을 이어받아 큰 중단 없이 클라이언트 요청을 처리한다. 이러한 방식을 지원하기 위해 HDFS의 구조를 일부 변경했다.

  • 네임노드는 에디트 로그를 공유하기 위해 고가용성 공유 스토리지를 반드시 사용해야 한다. 대기 네임노드가 활성화되면 먼저 기존 활성 네임노드의 상태를 동기화하기 위해 공유 에디트 로그를 읽고, 이어서 활성 네임노드에 새로 추가된 항목도 마저 읽는다.
  • 데이터노드는 블록 리포트를 두 개의 네임노드에 보내야 한다. 블록 매핑 정보는 디스크가 아닌 네임노드의 메모리에 보관되기 때문이다.
  • 클라이언트는 네임노드 장애를 사용자에게 투명한 방식으로 처리할 수 있도록 구성해야 한다.
  • 대기 네임노드는 보조 네임노드의 역할을 포함하고 있으며, 활성 네임노드 네임스페이스의 체크포인트 작업을 주기적으로 수행한다.

고가용성 공유 스토리지를 위해 NFS 필러나 QJM(quorum journal manager) 중 하나를 선택할 수 있다. QJM은 HDFS 전용 구현체로, 고가용성 에디트 로그를 지원하기 위한 목적으로 설계되었고 HDFS의 권장 옵션이다. QJM은 저널 노ㅓ드 그룹에서 동작하며, 각 에디트 로그는 전체 저널 노드에 동시에 쓰여 진다.


활성 네임노드에 장애가 발생하면 대기 네임노드는 매우 빠르게(수십초 이내) 기존 네임노드를 대체할 수 있다. 활성과 대기 네임노드는 모두 최신 에디트 로그와 실시간으로 갱신되는 블록 매핑 정보를 메모리에 유지하고 있기 때문이다. 하지만 실제로 장애 복구 시간을 보면 1분 정도 걸리는데, 시스템이 활성 네임노드에 장애가 발생했다고 판단하는 것은 매우 신중해야 하기 때문이다. 

반응형
반응형

안녕하세요 오늘은 하둡의 네임노드와 데이터노드에 대해서 정리해 보도록 하겠습니다.


해당 내용은 '하둡 완벽 가이드(4판)'에 대한 정리 내용입니다. 


[ HDFS 클러스터 구성 방식 ]

HDFS 클러스터는 마스터-워커(master-worker) 패턴으로 동작하는 두 종류의 노드(마스터인 하나의 네임노드(namenode)와 워커인 여러 개의 데이터노드(datanode)로 구성되어 있다. HDFS 클라이언트가 사용자를 대신해서 네임노드와 데이터노드 사이에서 통신하고 파일시스템에 접근한다. HDFS 클라이언트는 POXIS(Portable Operation System Interface)와 유사한 파일시스템 인터페이스를 제공하기 때문에 사용자는 네임노드와 데이터노드에 관련된 함수를 몰라도 코드를 작성할 수 있다.


[ 네임노드(NameNode) ]

네임노드(namenode)는 파일시스템의 네임스페이스를 관리한다. 네임노드는 파일시스템 트리와 그 트리에 포함된 모든 파일과 디렉터리에 대한 메타데이터를 유지한다. 이 정보는 네임스페이스 이미지(namespace image)와 에디트 로그(edit log)라는 두 종류의 파일로 로컬 디스크에 영속적으로 저장된다. 네임노드는 또한 파일에 속한 모든 블록이 어느 데이터노드에 있는지 파악하고 있다. 하지만 블록의 위치 정보는 시스템이 시작할 때 모든 데이터노드로부터 받아서 재구성하기 때문에 디스크에 영속적으로 저장하지는 않는다. 


[ 데이터노드(DataNode) ]

데이터노드는 파일시스템의 실질적인 일꾼이다. 데이터노드는 클라이언트나 네임노드의 요청이 있을 때 블록을 저장하고 탐색하며, 저장하고 있는 블록의 목록을 주기적으로 네임노드에 보고한다. 


[ 네임노드의 중요성 ]

네임노드가 없으면 파일시스템은 동작하지 않는다. 네임노드를 실행하는 머신이 손상되면 파일시스템의 어떤 파일도 찾을 수 없다. 데이터노드에 블록이 저장되어 있지만 이러한 블록 정보를 이용하여 파일을 재구성할 수는 없기 때문이다. 따라서 네임노드의 장애복구 기능은 필수적이다.


[ 네임노드 장애복구를 위한 하둡 메커니즘 ]

1. 네임노드 로컬 디스크와 원격의 NFS 마운트 두 곳에 동시에 백업하는 것이다.

파일시스템의 메타데이터를 지속적인 상태로 보존하기 위해 파일로 백업해야한다. 

2. 보조 네임노드(Secondary namenode)를 운영

보조 네임노드의 주 역할은 에디트 로그가 너무 커지지 않도록 주기적으로 네임스페이스 이미지를 에디트 로그와 병합하여 새로운 네임스페이스 이미지를 만드는 것이다. 병합 작업을 수행하기 위해 보조 네임노드는 충분한 CPU와 네임노드와 비슷한 용량의 메모리가 필요하므로 별도의 물리 머신에서 실행되는 것이 좋다. 또한 보조 네임노드는 주 네임노드에 장애가 발생할 것을 대비해서 네임스페이스 이미지의 복제본을 보관하는 역할도 맡는다. 하지만 주 네임노드의 네임스페이스 이미지는 약간의 시간차를 두고 보조 네임노드로 복제되기 때문에 주 네임노드에 장애가 발생하면 어느 정도의 데이터 손실은 불가피하다. 이럴 때 일반적인 복구 방식은 NFS에 저장된 주 네임노드의 메타데이터 파일을 보조 네임노드로 복사하여 새로 병합된 네임스페이스 이미지를 만들고 그것을 새로운 주 네임노드에 복사한 다음 실행하는 것이다.


결과적으로 안전한 하둡운영을 위해서는 네임노드의 메타데이터를 원격 NFS도 저장하고 보조 네임노드도 운영하는 것이라고 볼 수 있을 것 같다.

반응형
반응형


오늘은 HDFS에서 블록의 개념과 내용에 대해 포스팅 해보도록 하겠습니다.


기본적으로 HDFS 블록의 사이즈가 64,128,256MB (하둡 배포판에 따라 상이)인건 알고 계실텐데요? 왜 그렇고 어떻게 블록이 처리되는지에 대해 정리해보겠습니다. 해당 내용은 '하둡 완벽 가이드'의 내용을 학습하고 반복 학습겸 정리한 내용입니다.


블록

일반적으로 물리적인 디스크는 블록 크기란 개념이 있습니다. 블록 크기는 한 번에 읽고 쓸 수 있느 데이터의 최대량입니다.

보통 파일시스템의 블록의 크기는 수 킬로바이트고, 디스크 블록의 크기는 기본적으로 512byte입니다.


반면 HDFS도 블록의 개념을 가지고 있지만 HDFS의 블록은 기본적으로 128MB와 같이 굉장히 큰 단위입니다. HDFS의 파일은 단일 디스크를 위한 파일시스템처럼 특정 블록 크기의 청크로 쪼개지고 각 청크(chunk)는 독립적으로 저장됩니다. 단일 디스크를 위한 파일시스템은 디스크 블록 크기보다 작은 데이터라도 한 블록 전체를 점유하지만, HDFS 파일은 블록 크기보다 작은 데이터일 경우 전체 블록 크기에 해당하는 하위 디스크를 모두 점유하지는 않습니다.


예를 들어 HDFS의 블록 크기가 128MB고 1MB 크기의 파일을 저장한다면 128MB의 디스크를 사용하는 것이 아니라 1MB의 디스크만 사용합니다. 


블록은 내고장성(fault tolerance)과 가용성(availability)을 제공하는 데 필요한 복제(replication)를 구현할 때 매우 적합합니다.. 블록의 손상과 디스크 및 머신의 장애에 대처하기 위해 각 블록은 물리적으로 분리된 다수의 머신(보통 3개)에 복제되며 만일 하나의 블록을 이용할 수 없는 상황이 되면 다른 머신에 있는 복사본을 읽도록 클라이언트에 알려주면 됩니다. 블록이 손상되거나 머신의 장애로 특정 블록을 더 이상 이용할 수 없으면 또 다른 복사본을 살아 있는 머신에 복제하여 복제 계수(replication factor)를 정상 수중으로 돌아오게 할 수 있습니다.


일반적인 디스크 파일시스템과 같이 HDFS의 fsck 명령어로 블록을 관리할 수 있습니다.

> hdfs fsck / -files -blocks

파일시스템에 있는 각 파일을 구성하는 블록의 목록이 다음과 같이 출력됩니다.

기본 /(루트) 부터 순차적으로 디렉토리 들을 돌며 블록 상황을 보여줍니다.


HDFS 블록이 큰 이유는?

HDFS 블록은 디스크 블록에 비해 상당히 크다. 그 이유는 탐색 비용을 최소화하기 위해서다. 블록이 매우 크면 블록의 시작점을 탐색하는 데 걸리는 시간을 줄일 수 있고 데이터를 전송하는 데 많은 시간을 할애할 수 있다.(블록이 작고 너무 많으면 시작점을 탐색하는 비용 증가) 따라서 여러 개의 블록으로 구성된 대용량 파일을 전송하는 시간은 디스크 전송 속도에 크게 영향을 받는다. 

탐색 시간이 10ms고 전송률이 100MB/s 라고 하면, 탐색 시간을 전송 시간의 1%로 만들기 위해서는 블록 크기를 100MB로 정하면 된다. 하둡 배포판에 따라 다르지만 블록 크기의 기본값은 128MB다. 기본 블록 크기는 디스크 드라이브의 전송 속도가 향상될 때마다 계속 증가할 것이다.


이상으로 포스팅을 마치도록 하겠습니다:)



반응형
반응형


HDFS 설계 특성에 대해 정리해보도록 하겠습니다.


해당 포스팅은 '하둡 완벽 가이드' 내용을 정리한 것입니다. 공부하고 밑줄 쳐놓고 아까워 한 번 더 복습겸 포스팅해 봅니다.



HDFS 설계 특성

1. 매우 큰 파일  

'매우 큰'의 의미는 수백 메가바이트, 기가바이트 또는 테라바이트 크기의 파일을 의미한다. 최근에는 페타바이트 크기의 데이터를 저장하는 하둡 클러스터도 있다.'

기본적으로 하둡은 대용량 데이터를 처리하기 위해 설계되었다.


2. 스트리밍 방식의 데이터 접근

HDFS는 '가장 효율적인 데이터 처리 패턴은 한 번 쓰고 여러 번 읽는 것' 이라는 아이디어에서 출발했다. 데이터셋은 생성되거나 원본으로부터 복사된다. 그리고 시간이 흐르면서 다양한 분석을 수행할 수 있다. 분석이 전부는 아니지만 첫 번째 레코드를 읽는 데 걸리는 지연 시간보다 전체 데이터셋을 모두 읽을 때 걸리는 시간이 더 중요하다.


3. 범용 하드웨어

하둡은 고가의 신뢰도 높은 하드웨어만을 고집하지는 않는다. 하둡은 노드 장애가 발생할 확률이 높은 범용 하드웨어(여러 업체에서 제공하는 쉽게 구할 수 있는 하드웨어)로 구성된 대형 클러스터에서 문제없이 실행되도록 설계되었다. HDFS는 이러한 장애가 발생하더라도 사용자가 장애가 발생했다는 사실조차 모르게 작업을 수행하도록 설계되었다.


HDFS가 잘 맞지 않는 응용 분야

1. 빠른 데이터 응답 시간

데이터 접근에 수십 밀리초 수준의 빠른 응답 시간을 요구하는 애플리케이션은 HDFS와 맞지 않다. HDFS는 높은 데이터 처리량을 제공하기 위해 최적화되어 있고 이를 위해 응답 시간을 희생했다. 빠른 응답 시간을 원한다면 현재로서는 HBase가 하나의 대안이 될 수 있다.


2. 수많은 작은 파일

네임노드는 파일시스템의 메타데이터를 메모리에서 관리하기 때문에 저장할 수 있는 파일 수는 네임노드의 메모리 용량에 좌우된다. 경험상으로 파일, 디렉터리, 블록은 각각 150바이트 정도의 메모리가 필요하다. 따라서 파일 수가 백만 개고 각 파일의 블록이 하나면 적어도 300MB의 메모리가 필요하다. 물론 수백만 개의 파일은 괜찮겠지만 수십억 개의 파일은 하드웨어 용량을 넘어서게 된다.


3. 다중 라이터와 파일의 임의 수정

HDFS는 단일 라이터로 파일을 쓴다. 한 번 쓰고 끝나거나 파일의 끝에 덧붙이는 것은 가능하지만 파일에서 임의 위치에 있는 내용을 수정하는 것은 허용하지 않으며 다중 라이터도 지원하지 않는다. (하둡 3.0부터는 다중 라이터를 지원한다.


이상으로 포스팅을 마치도록 하겠습니다 :)

반응형
반응형


오늘은 스파크의 넓은 종속성(narrow dependency)와 좁은 종속성(wide dependency)에 대해서 포스팅 하도록 하겠습니다.


해당 내용은 '하이 퍼포먼스 스파크'와 '빅데이터 분석을 위한 스파크2 프로그래밍'의 내용을 정리한 것입니다.


[ 좁은 종속성(narrow dependency) ]

개념적으로 좁은 종속성은 자식 RDD의 각 파티션이 부모 RDD의 파티션들에 대해 단순하고 한정적인 종속성을 가지는 것이다. 디자인 시점에 종속성을 결정할 수 있고, 부모 파티션의 값과 상관이 없으며, 각각의 부모가 최대 하나의 자식 파티션을 가진다면 이 종속성은 좁다고 할 수 있다. 특히 좁은 트랜스포메이션의 파티션들은 하나의 부모 파티션에만 종속되거나(map 연산) 디자인 시점에 알게 된 부모 파티션들 중 알려진 일부에만 종속된다(coalesce). 그러므로 좁은 트랜스포메이션은 다른 파티션의 정보를 필요로 하지 않고 데이터의 임의의 부분에 대해 실행이 가능하다.

// 좁은 종속성. rdd에 map 연산으로 (x, 1) 의 튜플로 만든다.

val rdd2 = rdd1.map(x => (x, 1))


[ 넓은 종속성(wide dependency) ]

넓은 종속성을 가지는 트랜스포메이션은 임의의 데이터만으로 실행할 수는 없으며, 특별한 방법, 예를 들면 키의 값에 따라 파티셔닝된 데이터를 요구한다. (결국 키의 재분포, 즉 셔플이 필요하다는 의미). 일례로 sort같은 경우 같은 범위의 키들이 같은 파티션 안에 존재하도록 레코드들을 파티셔닝해야 한다. 넓은 종속성의 트랜스포메이션은 sort, reduceByKey, groupByKey, join 그리고 rePartition 함수를 호출하는 모든 것을 아우른다.

// 넓은 종속성, groupKey

val rdd3 = rdd2.groupByKey()


특별한 경우로는 스파크가 이미 데이터가 어떤 특정한 방법으로 파티션되어 있다는 것을 갈고 있다면 넓은 종속성의 연산이라도 셔플링을 하지 않는다. 대개 셔플링은 비싼 비용을 치러야 하고 셔플 과정에서 새로운 파티션으로 옮겨야 하는 데이터의 비율이 높을수록 이 비용은 더 비싸지게 마련이다. 


정리하자면, 하나의 RDD가 새로운 RDD로 변환될 때 기존 RDD를 부모 RDD, 새로운 RDD를 자식 RDD라고 하겠습니다. 이때 부모 RDD를 구성하는 파티션이 여러 개의 자식 RDD 파티션과 관계를 맺고 있으면 넓은 의존성을 갖고 있다고 말하고, 그 반대의 경우는 좁은 의존성을 갖고 있다고 표현할 수 있겠습니다.





포스팅을 마치도록 하겠습니다.


도움이 되셨다면 광고 한 번 클릭해주시는 센스 감사합니다:)

반응형
반응형



이번 포스팅은 저번 포스팅(스파크 설정 Part.1)에 이어 spark-submit 실행시 메모리, 익스큐터, 네트워크, 보안,암호화 관련 설정에 대해 정리해보겠습니다. 해당 내용은 '빅데이터 분석을 위한 스파크2 프로그래밍' 책의 내용을 기반으로 정리하였습니다.


[ 메모리 관련 설정 ]

  • spark.memory.fraction : 전체 힙 영역에서 익스큐터와 RDD 데이터 저장에 사용될 크기를 비율로 설정합니다. 기본값은 0.6이며 스파크 내부에서 사용하는 메타데이터나 객체 직렬화 및 역질렬화 등에 필요한 예비 메모리 공간을 확보해서 OOM을 방지할 목적으로 이 값을 조정할 수 있습니다.
  • spark.memory.storageFraction : 할당된 메모리에서 데이터 저장에 사용할 비율을 지정할 수 있습니다. 기본값은 0.5이며 이 값을 크게 할 경우 익스큐터에서 사용할 메모리 크기를 줄여야 합니다.
  • spark.memory.offHeap.enabled : 기본값은 false이며 true로 설정할 경우 off-heap메모리를 사용합니다. 이 값을 true로 설정했다면 spark.memory.offHeap.size에 오프-힙 메모리 크기를 지정해야 합니다.

[ 익스큐터 관련 설정 ]
  • spark.executor.cores : 익스큐터에 할당된 코어의 수를 지정합니다. 지정하지 않을 경우 얀 모드에서는 1, 스탠드얼론 모드와 메소스 coarse-grained모드에서는 사용 가능한 전체 코어의 개수가 사용됩니다.
  • spark.default.parallelism : 스파크에서 사용할 파티션의 수, 즉 스파크의 기본 병렬 처리 수준을 지정합니다.
  • spark.files.fetchTimeout : sparkContext.addFile() 메서드를 이용했을 때 드라이버로부터 파일을 받아오는 데 걸리는 최대 시간을 설정합니다. 기본값은 60s 입니다.

[ 네트워크 관련 설정 ]
  • spark.driver.host, spark.driver.port : 드라이버 프로세스의 호스트와 포트 정보를 설정합니다.
  • spark.network.timeout : 스파크의 기본 네트워크 타임아웃을 설정합니다. 이 값은 spark.core.connection.ack.wait.timeout 등 다른 설정 값들의 기본값으로 사용됩니다.

[ 보안 관련 설정 ]
  • spark.acls.enable : 스파크 acl을 활성화할지 여부를 설정합니다. 기본값은 false입니다.
  • spark.admin.acls : 스파크 잡에 접근할 수 있는 사용자(user)와 관리자(administrator) 정보를 설정하며, 콤마(,)를 이용해 다수의 사용자를 지정할 수 있습니다. 만약 그룹으로 설정할 경우 spark.admin.acls, groups 속성을 사용할 수 있습니다.
  • spark.authenticate : 스파크에서 사용자 인증 여부를 확인할 것인지를 설정합니다. 기본 값은 false이며, 이 경우 인증 여부와 상관없이 스파크 잡을 실행하고 접근할 수 있습니다.
  • spark.authenticate.secret : 잡을 실행하기 위한 비밀 키 정보를 설정합니다.
  • spark.ui.view.acls,spark.ui.view.acls.groups : 스파크 UI에서 잡 정보를 조회하기 위한 acl 정보를 설정합니다.
  • spark.ui.filters : 스파크 UI에 적용할 자바 서블릿 필터 정보를 지정합니다. 콤마(,)를 이용해 여러 개의 필터를 지정할 수 있으며, 자바 시스템 프로퍼티를 사용해 필터에서 사용할 파라미터 정보를 지정할 수 있습니다. 

[ 암호화 관련 설정 ]
  • spark.ssl.enabled : 기본값은 false이며 SSL 연결을 활성화할 것인지 설정합니다.
  • spark.ssl.keyStore : 키 스토어 파일이 저장된 경로를 지정합니다.
  • spark.ssl.keyStoreType : 키 스토어 파일의 타입을 지정합니다.
  • spark.ssl.keyStorePassword : 키 스토어 파일에 대한 비밀번호를 지정합니다.
  • spark.ssl.enabledAlgorithms : ssl을 위한 알고리즘(cipher) 리스트를 지정합니다. 콤마(,)를 이용해 여러 개 지정할 수 있습니다.

보안, 암호화 관련 설정은 거의 작업해 본적이 없는 것 같네요...보통 사용하는 하둡 클러스터 장비들이 사내 네트워크망에서만 접근 가능하도록 되어있어서ㅎㅎ

이상으로 포스팅을 마치도록 하겠습니다.


반응형
반응형

이번 포스팅에서는 spark-submit 실행시 스크립트상에서 설정할 수 있는 방법에 대해 정리하도록 하겠습니다.


해당 내용은 '빅데이터 분석을 위한 스파크2 프로그래밍' 책의 내용을 기반으로 정리하였습니다.


[ 애플리케이션 관련 설정 ]

  • spark.app.name : 애플리케이션 이름. SparkConf의 appName으로 설정하는 것과 같은 속성
  • spark.driver.cores : 드라이버가 사용할 코어 수. 클러스터 모드에서만 사용 가능하며 기본값은 1입니다.
  • spark.driver.maxResultSize : collect() 메서드 등의 호출 결과로 생성된 결과 값의 최대 크기입니다. 최소 1M 이상으로 지정해야 하며, 이 값을 초과할 경우 전체 잡은 실패로 종료됩니다. 기본값은 1g입니다.
  • spark.driver.memory : 드라이버가 사용할 메모리 크기이며, 클라이언트 모드에서 사용할 경우 반드시 SparkConf가 아닌 --driver-memory 실행 옵션이나 프로퍼티 파일을 사용해서 지정해야 합니다. 기본값은 1g입니다.
  • spark.executor.memory : 익스큐터 하나의 메모리 크기를 지정합니다. 기본값은 1g입니다.
  • spark.local.dir : RDD 데이터를 디스크에 저장하거나 셔플 시 매퍼의 결과를 저장하는 디렉터리를 지정합니다. 콤마(,)를 이용해 여러 위치를 지정할 수 있으며, 성능에 큰 영향을 주므로 반드시 빠른 로컬 디스크를 사용해야 합니다. 기본값은 /tmp 입니다.
  • spark.master : 클러스터 매니저 정보를 지정합니다.
  • spark.submit.deployMode : 디플로이 모드를 지정합니다. client 또는 cluster 모드를 사용할 수 있습니다.

[ 실행환경(Runtime Enviroment) 관련 설정 ]
  • spark.driver.extraClassPath : 드라이버 클래스패스에 추가할 항목을 지정합니다. 이 속성은 SparkConf가 아닌 --driver-memory 실행 옵션이나 프로퍼티 파일을 사용해서 지정해야 합니다. 유사한 속성으로 spark.driver.extraJavaOptions, spark.driver.extraLibraryPath가 있으며 각각 드라이버 실행 시 필요한 자바 옵션과 라이브러리 정보를 지정하는 용도로 사용됩니다.
  • spark.executor.extraClassPath : 익스큐터의 클래스패스에 추가할 항목을 지정합니다. 유사한 속성으로 spark.executor.extraJavaOptions와 spark.executor.extraLibraryPath가 있습니다.
  • spark.files, spark.jars : 각 익스큐터의 실행 디렉터리에 위치할 파일들 또는 jar 파일들을 지정하며, 콤마(,)를 이용해 여러 파일을 지정할 수 있습니다.
  • spark.submit.pyFiles : PYTHONPATH에 추가될 .zip, .egg, .py 파일을 지정하며, 콤마(,)를 이용해 여러 파일을 지정할 수 있습니다.
  • spark.jars.packages : 익스큐터와 드라이버의 클래스패스에 추가될 의존성 jar정보를 메이븐 코디네이트 형식으로 지정 할 수 있습니다.

[ 셔플 관련 설정 ] 
  • spark.reducer.maxSizeInFlight : 셔플 수행 시 각 리듀서가 매퍼의 실행 결과를 읽어갈 때 사용할 버퍼의 크기를 지정합니다. 기본값은 48m입니다.
  • spark.reducer.maxReqslnFlight : 리듀서에서 매퍼의 결과를 가져갈 때 동시에 수행 가능한 최대 요청 수를 지정합니다. 기본값은 int.MaxValue입니다.
  • spark.shuffle.compress : 맵의 결과를 압축할 것인지에 대한 설정입니다. true로 설정할 경우 spark.io.compress.codec에 지정한 압축 코덱을 사용해 압축합니다.
  • spark.shuffle.service.enabled : 외부 셔플 서비스를 사용할 것인지 여부를 지정합니다. 이와 관련된 내용은 이후의 동적 자원 할당 부분에서 다시 확인해 보겠습니다. 기본값은 false이며 true로 설정할 경우 외부 셔플 서비스를 사용하게 됩니다.

[ 스파크 UI 관련 설정 ] 
  • spark.eventLog.enabled : 스파크 이벤트 관련 로깅을 수행할 것인지를 설정합니다. 기본 값은 false이며 true로 설정할 경우 spark.eventLog.dir에 로깅을 수행할 경로를 지정해야 합니다. 이벤트 로깅을 활성화할 경우 종료된 애플리케이션에 대한 상세 실행 히스토리 정보를 스파크 UI에서 확인할 수 있습니다. 
  • spark.ui.port : 스파크 UI 포트를 지정합니다. 기본값은 4040입니다.
  • spark.ui.killEnabled : 스파크 UI를 통해 잡을 중지(kill)시킬 수 있도록 할 것인지 설정합니다. 기본값은 true입니다.
  • spark.ui.retainedJob : 종료된 잡에 대한 정보를 몇 개까지 유지할 것인지 설정합니다. 유사한 옵션으로 spark.ui.retainedStages, spark.ui.retainedTasks, spark.ui.retainedExecutors, spark.ui.retainedDrivers, spark.ui.retainedBatches 등이 있습니다.

[ 압축 및 직렬화(Serialization) 관련 설정 ]
  • spark.broadcast.compress : 브로드캐스트 변수의 값을 압축할 것인지 설정합니다. 기본값은 true입니다.
  • spark.io.compression.codec : 브로드캐스트 변수나 셔플을 위한 중간 결과물 등 스파크 내부에서 사용하는 데이터를 압축할 때 사용할 압축 코덱을 지정합니다. l4z, lzf, snappy를 사용할 수 있으며 기본값은 lz4입니다.
  • spark.kyro.classesToRegister : Kyro 직렬화를 위해 등록할 커스텀 클래스 정보를 지정합니다. 만약 클래스 등록 방식을 좀 더 커스텀하게 진행하고자 한다면 spark.kyro.registrator를 사용할 수 있습니다.
  • spark.serializer : 스파크에서 사용할 객체 직렬화 방식을 설정합니다. org.apache.spark.Serializer의 하위 클래스를 지정할 수 있으며, 현재 스파크에서는 JavaSerializer와 KyroSerializer라는 두 클래스를 제공하고 있습니다. 


다음 메모리 관련 설정, 익스큐터 관련 설정, 네트워크 관련 설정, 보안 관련 설정, 암호화 관련 설정은 다음 포스팅에서 하도록 하겠습니다.


도움이 되셨다면 광고도 한 번 클릭해주시는 센스^_^

반응형
반응형

해당 내용은 '빅데이터 분석을 위한 스파크2 프로그래밍' 책의 내용을 정리한 것입니다.


실제로 실무에서 스파크로 작업된 결과를 hdfs에 남기기전에 coalesce명령어를 써서 저장되는 파일의 개수를 지정해주곤 했다.


업무에서 사용하긴 했지만 실제 repartition연산과 어떤점이 다른지 모르고 사용했었는데 책을 보며 알게되어 기록.


핵심은 셔플을 하느냐 안하느냐!!!


coalesce와 repartition

RDD를 생성한 뒤 filter()연산을 비롯한 다양한 트랜스포메이션 연산을 수행하다 보면 최초에 설정된 파티션 개수가 적합하지 않은 경우가 발생할 수 있다.

이 경우 coalesce()나 repartition()연산을 사용해 현재의 RDD의 파티션 개수를 조정할 수 있다.


두 메서드는 모두 파티션의 크기를 나타내는 정수를 인자로 받아서 파티션의 수를 조정한다는 점에서 공통점이 있지만 repartition()이 파티션 수를 늘리거나 줄이는 것을 모두 할 수 있는 반면 coalesce()는 줄이는 것만 가능하다!!!


이렇게 모든 것이 가능한 repartition()메서드가 있음에도 coalesce()메서드를 따로 두는 이유는 바로 처리 방식에 따른 성능 차이 때문이다. 즉, repartition()은 셔플을 기반으로 동작을 수행하는 데 반해 coalesce()는 강제로 셔플을 수행하라는 옵션을 지정하지 않는 한 셔플을 사용하지 않기 때문이다. 따라서 데이터 필터링 등의 작업으로 데이터 수가 줄어들어 파티션의 수를 줄이고자 할 때는 상대적으로 성능이 좋은 coalesce()를 사용하고, 파티션 수를 늘여야 하는 경우에만 repartition() 메서드를 사용하는 것이 좋다.


오우.....이런 중요한 차이점이 있었다니....그렇다면 coalesce를 사용하면 셔플을 발생시키지 않기때문에 파티션마다 데이터의 사이즈가 다를꺼고 hdfs write했을때 repartition으로 개수를 조정한것과는 다르게 사이즈가 뒤죽박죽이겠네?!!! (나중에 시간되면 테스트해보자)


[ 업데이트 내용 ] 

댓글에서 관련내용에 대해 적어주신분이 있어 확인할겸 관련 내용 업데이트 합니다.


실제 repartition내부는 coalesce메소드를 호출하는 형태로 되어있습니다.


coalesce내부 소스코드도 올려봅니다.

소스코드의 주석을 보면 'This results in a narrow dependency' 좁은 의존성을 초래한다고 적혀 있는데 관련해서는 따로 포스팅하도록 하겠습니다.

그리고 위에서는 coalesce는 파티션 수를 줄이는 것만 가능하다고 적어놨지만 'true'옵션을 주면 늘리는 것 또한 가능하네요.

하지만 기존 처리하던 partitions의 개수보다 많은 파티션수로 처리할 경우에는 반드시 shuffle옵션을 true로 주셔야합니다(매개변수로 넘겨주면됨)


이상으로 포스팅을 마치도록 하겠습니다.


도움이 되셨다면 광고도 한 번 클릭해주시는 센스^_^

반응형

+ Recent posts