중간 중간 쓸 데 없는 내용이나 잘못된 내용이 들어가 있을 수 있으니 직접 판단해야 함 ;;;

 

1.


Hadoop 1 과 2 의 차이

Hadoop2 에 YARN 이 도입되어,
Hadoop 1 의 Task TrackerResource Manager와 Application Master로 분리되었고
MR 작업 등에서 자원 관리를 더 효율적으로 하게 됨
Hadoop2 에서 HA 구성이 가능하게 됨



여러 디스크에 데이터를 병렬로 쓰거나 읽을 때 나타나는 문제점


- 하드웨어 장애
  해결 방법 : 데이터를 여러 곳에 복제 (RAID 혹은 HDFS 의 복제)

- 정합성을 지키는 일
  해결 방법 : 데이터 블럭 스캐너(체크섬을 통해 무결성 체크)를 사용하여 주기적으로 확인

- 어떤식으로든 분산된 데이터들을 하나로 결합해야 함
  해결 방법 : MR 모델 프로그래밍으로 결합 가능


정합성 : 분산된 데이터들이 모두 같은 데이터인지 아닌지
무결성 : 데이터 자체가 깨지지 않고 온전히 자신의 값을 유지하는지



맵리듀스는 일괄 질의 처리기
비정형 쿼리를 수행하고 합리적인 시간 내에 결과를 보여줌
대화형 분석에는 적합하지 않음
따라서 수 초 이내에 결과를 받는 것은 불가능

YARN (Yet Another Resource Negotiator) 은 클러스터 자원 관리 시스템
MR, Spark 를 포함한 어떤 분산 프로그램도 하둡 클러스터에 저장된 데이터를 처리할 수 있도록 해줌
YARN 의 도움으로, Spark 가 HDFS 에 접근해서 Data Locality 이점을 받을 수 있음



RDB 와 MR 비교

RDB 는 트랜잭션이 ACID(원자성(Atomicity), 일관성(Consistency), 격리성(Isolation), 지속성(Durability) ), MR 은 없음
RDB 는 쓰기 기준 스키마, MR 은 읽기 기준 스키마
RDB 는 여러 번 읽고 쓰기, MR 은 한 번 쓰고 여러번 읽기



정형 데이터 : 형식이 정의된 항목으로 구조화 된 데이터. 스키마가 뚜렷한 데이터. XML
반정형 데이터 : 스키마가 유연하거나 심지어 생략이 가능한 데이터. JSON
비정형 데이터 : 어떠한 내부 구조도 없는 데이터. 텍스트, 이미지

하둡은 읽기 스키마 구조이기 때문에, 처리 시점에 어떤 데이터가 와도 처리 가능



데이터 센터 환경에서 가장 중요한 자원은 바로 네트워크 대역폭 

대규모 분산 컴퓨팅에서, 분산 처리되는 각 프로세스를 조율하지 않아도 됨
task 등이 실패하면 알아서 재시작이 됨
MR 태스트들 간 상호 의존성이 없는 비공유 아키텍처이기 때문에 이런 일이 가능함


 

2.


Hadoop job 은 여러개의 Map 태스크, Reduce 태스크로 나뉘어짐
YARN 에 의해 스케줄링되어 클러스터의 여러 노드에서 실행됨
특정 노드의 태스크 하나가 실패하면 자동으로 다른 노드를 재할당하여 다시 실행

잡의 입력을 입력 스플릿이라 부르는 고정 크기 조각으로 분리함
입력 스플릿 개수만큼맵 태스크 생성하고 맵 태스크의 input 으로 넣어줌

스플릿 크기가 작을수록 부하 분산에 좋은 효과
반대로 크기가 작을수록 맵 태스크 생성 오버헤드가 있고, 스플릿 관리 오버헤드가 있어 실행 시간이 증가함
적절한 스플릿 크기는 HDFS 블록 크기와 같은 크기

데이터 로컬리티 이득을 보려면, 데이터가 존재하는 노드에서 맵 태스크를 실행해야 함
만약 모든 데이터 복제본이 있는 노드에 자원이 없어서 맵 태스크를 실행하지 못하게 된다면
동일 랙의 다른 노드에서 가용한 맵 슬롯을 찾음 (왜냐하면 네트워크 전송 오버헤드를 최대한 줄이기 위해)
만약 그것도 없다면, 다른 랙의 다른 노드에서 가용한 맵 슬롯을 찾음



맵 태스크 결과는 local 에 저장됨
리듀스를 위한 중간 결과물인데 HDFS 에 넣었다가 복제되면 그건 그것대로 오버헤드이기 때문

리듀스 태스크는 각 맵 태스크의 결과를 입력으로 받음(네트워크를 통해 입력받음)
따라서 리듀스는 데이터 로컬리티 장점이 없음
리듀스 태스크는 사용자가 독립적으로 지정 가능

컴바이너 함수는 셔플 단계에서 네트워크로 전송되는 데이터 양을 줄이는 역할


 

3.


HDFS 블록 크기가 큰 이유는, 탐색 비용을 최소화하기 위해서
블록의 시작점을 탐색하는 데 걸리는 시간을 줄일 수 있고, 데이터 전송에 더 많은 시간을 할애 가능
반대로 분산 처리율은 떨어짐 (스플릿 크기와 같다는 전제)

블록 개념을 도입하여 얻은 이점
- 디스크보다 큰 파일을 저장 가능
- 블럭만 다루면 되니까 스토리지 관리가 쉬움
- 내고장성 (장애에 견디는 능력)가용성 (정상적으로 사용 가능한 능력) 을 제공하는데 필요한 복제 구현 가능

블록의 복제 계수를 높이면 읽기 부하를 클러스터에 전체에 분산 가능
반대로 복제 계수가 높으면 디스크 용량에 부담이 됨


네임노드는 아래 두 파일을 이용하여, 파일과 디렉터리에 대한 메타데이터를 유지
- 네임스페이스 이미지 : local 디스크에 영속적으로 저장.
    실제 메타데이터를 저장
- 에디트 로그 : local 디스크에 영속적으로 저장.
    주기적으로 업데이트되는 메타데이터들을 임시로 저장하는 곳.
    주기적으로 네임스페이스 이미지와 병합됨

데이터노드는 블록을 저장하고 탐색, 블록 목록을 주기적으로 네임노드에 보고

네임노드 장애 복구 기능에 3 가지 방법 사용 가능
- 메타데이터를 주기적으로 백업
- 보조 네임노드를 사용
    네임노드의 메타데이터를 주기적으로 복제해서 갖고 있음
    에딧 로그와 네임스페이스 이미지를 병합해서 네임노드에 줌
- HA 구성 

네임노드는 파일에 따라 저장하는 메타데이터가 정해짐
예를 들어 500mb 짜리 파일 하나를 HDFS 에 저장하면,
블럭은 총 4개 생기지만 파일은 하나이기 때문에
네임노드에 저장되는 메타데이터는 하나
128mb 짜리 파일 다섯개를 HDFS에 저장하면,
블럭은 총 5개 생기고 파일도 다섯개이기 때문에
네임노드에 저장되는 메타데이터는 다섯

참고 https://gyuhoonk.github.io/hive-merge-query



빈번하게 접근하는 블록은, (자바 힙 외부에서 관리되는) off-heap 블록 캐시라는 
데이터 노드의 메모리캐싱 가능

패더레이션 기능을 사용하면,
여러 네임 노드가 파일시스템의 네임스페이스 일부를 나눠 관리할 수 있게 됨



네임 노드에 장애가 나서 복구하게 되면, 아래 작업들 때문에 꽤 긴 시간(30분 정도)동안 HDFS 가 먹통이 됨
- 네임스페이스 이미지를 메모리에 로드
- 에디트 로그 갱신
- 전체 데이터 노드로부터 블록 리포트 받기

따라서 네임 노드 장애가 일어나도 가용할 수 있도록, HA 구성을 하는 게 좋음
HA 설명 : https://eyeballs.tistory.com/251

정기적인 유지 관리를 위해, active NN 와 standby NN 역할을 바꾸게 하는데 이를 우아한 장애 복구라고 함

split brain 이 나타나면, fencing 메소드를 통해 처리.
SSH 펜싱 명령어로 기존 네임 노드를 확실하게 죽임



HDFS 에서 디렉터리는 데이터 노드에는 없고 네임 노드 메모리에서만 관리됨
따라서 복제 계수도 없음

HDFS 의 권한은 다음과 같음
- 읽기 권한 : 파일 읽기, 디렉터리 내용 보기
- 쓰기 권한 : 파일 쓰기/삭제, 디렉터리 만들거나 삭제
- 실행 권한 : 하위 디렉터리 접근 (파일에 대한 실행 권한은 무시됨)

권한 검사는 클라이언트의 사용자 이름을 기준으로 검사함
슈퍼유저는 권한 검사 하지 않음



MR 프로그램은 어떠한 파일시스템도 접근 가능(HDFS, local, s3,, 등)

WebHDFS 프로토콜을 이용한 HTTP Rest API 를 사용하여 HDFS 에 접근 가능

HDFS 파일을 읽을 때 globbing 이라는 와일드카드 문자를 사용하면 편함



HDFS 에서 파일 읽기 상세
- 클라이언트는 파일의 첫 번째 블록 위치를 파악하기 위해 RPC 를 이용하여 네임노드 호출
- 네임노드는 해당 블록의 가장 가까운 복제본을 갖는 데이터노드의 주소 반환
- 클라이언트는 로컬 데이터노드에서 직접 데이터 읽음
- 다 읽었으면, 다음 블록 위치를 파악하기 위해 다시 네임노드 호출

읽다가 장애가 난다면, 다른 복제본을 갖는 데이터노드의 주소를 받고, 그 노드에서 데이터를 읽음



HDFS 에 파일 쓰기 상세
- 클라이언트는 새로운 파일을 쓰기 위해 RPC 를 이용하여 네임노드 호출
- 네임노드는 동일한 파일 체크, 권한 체크 등의 검사 진행
- 검사 통과 후, 네임노드는 데이터를 저장한 데이터노드 주소 3개(복제계수)를 반환
- 데이터 노드 목록은 파이프라인을 형성함
- 클라이언트가 (패킷화된) 데이터를 첫번째 데이터노드에 보내어 저장
- 첫번째 데이터노드가 저장한 데이터를 두번째 데이터노드로 보내어 저장 (비동기적으로 수행)
- 두번째 데이터노드가 저장한 데이터를 세번째 데이터노드로 보내어 저장 (비동기적으로 수행)

(패킷화된) 데이터를 ack 큐라는 중간 큐에 저장한 후 데이터노드들에 쓰는데,
만약 장애가 나서 쓰기 실패하면, ack 큐 내의 패킷들은 다시 데이터 앞에 붙게되어 잃어버리지 않게 됨
모든 데이터 노드로부터 ack 응답을 받으면 ack 큐 내의 데이터가 제거

파일을 쓰는 데이터노드는 다음 순서로 결정됨
1. (클라이언트가 데이터노드라면) 클라이언트 노드
1. (클라이언트가 데이터노드가 아니라면) 무작위 노드
2. 1번 노드와 다른 랙의 다른 노드
3. 2번 노드와 같은 랙의 다른 노드
4. 무작위
...

위의 전략은 다음을 충족시킴
- 신뢰성 : 블록을 두 랙에 저장
- 쓰기 대역폭 : 쓰기는 하나의 네트워크 스위치만 통과함
- 읽기 성능 : 두 랙에서 가까운 랙 선택
- 블록 분산



HDFS 는 클러스터 전반에 걸쳐 파일 블록이 고르게 분산되었을 때 가장 잘 동작
만약 데이터가 한 노드에 몰려있다면, 처리 부하가 한 노드로 몰릴 수 있기 때문


 

 

4.


YARN 은 클러스터 자원을 요청하고 사용하기 위한 API 를 제공
하지만 사용자가 해당 API 를 직접 이용하진 못 함

리소스 매니저 : 클러스터 전체 자원 사용량 관리
노드 매니저 : 컨테이너 구동 및 모니터링

YARN 자체는 클라이언트, 마스터, 프로세스 같은 애플리케이션이 서로 통신하는 기능 제공하지 않음
주요 YARN 애플리케이션(Spark, Tez 등)은 하둡 RPC 같은 원격 호출 방식을 이용하여 상태 변경 전달하고 클라이언트로부터 결과 받음
애플리케이션마다 호출 방식이 다름



YARN 에서 애플리케이션 구동하는 절차
- 클라이언트는 리소스 매니저에게 애플리케이션 마스터 프로세스 구동 요청
- AM 를 시작할 노드 매니저 찾고, 그 위에서 AM 을 실행
- AM 에서 필요한 자원을 RM 에 요청
- RM 는 리소스와 함께 지역성 이득을 받을 수 있는 NM 을 반환
- AM 이 NM 에게 컨테이너 구동 명령 후, NM 이 컨테이너 구동하고 task 실행

AM 이 노드매니저 위에 있지 않고, 클러스터 바깥에 존재할 수 있음
이를 비관리 애플리케이션 마스터라고 부름

AM 은 어느 때나 RM 에게 자원 요청이 가능



YARN 스케줄러 : https://eyeballs.tistory.com/257

큐 탄력성 : 캐퍼시티 스케줄러 사용시 사용 가능
  다른 큐가 놀고있으면 놀고있는 큐의 자원을 가져다가 사용 가능

페어 스케줄러 : 실행 중인 모든 애플리케이션에 동일하게 자원을 할당하지만,
  실제로 자원은 사용자 사이에서만 균등하게 공유됨 (큐 이름이 명시되지 않으면, default 로 사용자 이름으로 된 큐가 생성됨)

선점 : 자원 균등 공유에 위배되는 큐에서 실행되는 컨테이너 죽여 자원을 얻는 기능
  죽은 컨테이너는 다시 수행되어야하기에 전체 효율이 떨어짐

YARN 의 모든 스케줄러지역성 요청가장 우선시함

지연 스케줄링 : 지역성 요청을 위해 조금 늦게 컨테이너를 할당하는 것
  하트비트를 통해 가용 자원이 있는지 알 수 있음

RM 가 NM의 자원을 계산할 때는 메모리만 고려함 (CPU 는 고려하지 않음)
우성 자원 공평성이 true 가 되면 CPU 까지 고려됨


 

5.


하둡은 32bit 체크섬을 이용하여 데이터 무결성 검사를 함
체크섬은 크기가 작아서 손상될 가능성이 매우 낮음
스토리지 오버헤드도 1%가 안 됨

HDFS 는 데이터 쓸 때 체크섬을 계산하여 함께 저장
데이터를 읽을 때 클라이언트가 체크섬으로 확인

각 데이터노드는 체크섬 검증 로그를 영구 저장함
클라이언트가 체크섬 확인을 마치면 그 검증 로그를 갱신

DataBlockScanner : 3주에 한 번씩 전체 데이터 블럭의 체크섬을 검증하는 백그라운드 스레드



직렬화 : 네트워크 전송을 위해 구조화된 객체바이트 스트림으로 전환
역직렬화 : 바이트 스트림을 일련의 구조화된 객체로 역전환

하둡 시스템에서 노드 사이의 프로세스 간 통신RPC 를 사용하여 구현


sequence file : https://eyeballs.tistory.com/487



행 기반 파일 포맷 : Sequence file, Map file, Avro
  한 행에서 여러 컬럼에 접근할 때 잘 동작
  쓰기 작업 실패시 마지막 동기화 포인트까지 데이터 읽기 가능

컬럼 기반 파일 포맷 : Parquet, Orc
  소수의 컬럼만 접근할 때 잘 동작
  압축 효율이 좋음
  IO 할 때 더 많은 메모리가 필요
  IO 한 데이터를 각 행으로 분리하는 버퍼가 추가로 필요하기 때문


 

 

6.


하둡은 클라이언트에서 whoami 명령어의 결과인 사용자에 대해 HDFS 권한을 확인함
(그룹명 확인은 groups)

하둡 웹 인터페이스 실행 사용자명은 dr.who 임
따라서 웹 인터페이스를 통해 시스템 파일에 접근 불가 (왜냐면 권한이 없기 때문)



시스템 데몬 로그 : 각 하둡 데몬은 (log4j 를 사용하여) 표준 출력과 에러를 저장한 로그 생성
  HADOOP_LOG_DIR 환경변수에 지정된 dir 에 생성

맵리듀스 잡 히스토리 : 잡을 실행하는 과정에서 발생하는 이벤트(task 완료 등) 로그
  HDFS 내의 한 곳에 모임

맵리듀스 태스크 로그 : 각 태스크 자식 프로세스가 (log4j 를 사용하여) 표준 출력 표준 에러 로그 생성
  YARN_LOG_DIR 환경변수에 지정된 dir 에 생성


 

 

7.


맵리듀스 작동 방법 : job 제출

- 리소스 매니저에 (맵리듀스 잡 ID 로 사용될) 애플리케이션 ID 요청 
- 클라이언트는, 잡 실행에 필요한 잡 리소스(jar 파일, 환경 설정 파일, 미리 계산된 입력 스플릿 등)를
  HDFS 같은 공유 파일 시스템 내 잡 ID 이름의 디렉터리에 복사
  HDFS 복제계수는 10으로 아주 높은데, 높은 이유는 노드 매니저가 잡 태스크를 실행할 때 접근성을 높이기 위해
- 리소스 매니저에게 잡 제출

잡을 제출하면, HDFS 에 잡 리소스가 올라온 상황이 됨



맵리듀스 작동 방법 : job 초기화

- RM 가 노드 매니저 위에 컨테이너 하나 할당하고 그 위에서 AM 실행
- AM 은 (클라이언트가 HDFS 에 입력한 job 리소스로부터) 입력 스플릿 정보를 읽음
- 입력 스플릿별로 맵 태스크 객체 생성
- 만약 job 이 작아서 AM 실행되는 노드 매니저위에서 태스크 실행이 가능하면, 우버 태스크로 실행
  job 이 작다는 것은 HDFS 블록 하나보다 입력이 작은 경우



맵리듀스 작동 방법 : task 할당

- AM 은 RM 에게 잡의 모든 맵과 리듀스 태스크를 위한 컨테이너 요청 (CPU, Memory 등)
  우선순위는 맵 태스크가 리듀스 태스크보다 높음
- 맵 태스크는 데이터 지역성을 고려한 노드 매니저 위에서 실행


맵리듀스 작동 방법 : task 실행

- NM 위에서 컨테이너가 시작됨
- 각 태스크는 자바 애플리케이션으로 실행
- 태스크 실행 전 job 리소스를 HDFS 로부터 컨테이너 local 로 가져옴

태스크는 독립된 JVM 위에서 동작하기 때문에
(태스크의 버그, 강제 종료, hang 등으로) 노드 매니저에게 영향을 주지 않음



맵리듀스 작동 방법 : 진행 상황과 상태 갱신

- 하둡은 진행 중인 태스크는 실패로 보지 않기 때문에 진행 상황 보는 것이 아주 중요
- 사용자는 콘솔 화면에서 map, reduce 의 처리 비율을 볼 수 있음
- task 는 AM 에게 3초마다 진행 상황과 상태 정보를 집계하여 보고
- AM 에 보고된 진행 정보는 RM 의 WebUI 를 통해 사용자에게 보여짐



맵리듀스 작동 방법 : job 완료

- AM 이 task 로부터 작업 마무리 되었다는 보고 받으면 job 상태를 '성공' 으로 변경
- 사용자에게 통지할 메세지 출력

클라이언트는 mr 작업이 마무리 된 것을 HTTP job 통지를 통해 callback 받을 수 도 있음



사용자 코드 이슈로 태스크 실패
- AM 에게 실패 보고
- 사용자 로그에 기록
- task 컨테이너 자원 풀어줌

hang 에 걸린 태스크
- 10분 이상 task 보고를 받지 못한 AM 은 해당 task 를 실패로 간주. 강제 종료
- 다른 노드 매니저에 동일한 task 재실행
- 같은 이슈가 4번 반복되면 job 실패

애플리케이션 마스터 실패
- AM 이 주기적으로 RM 에게 보내는 하트비트가 끊기는 경우
- AM 실패시 다른 노드 매니저에서 AM 을 재실행
- 같은 이슈가 2번 반복되면 job 실패

노드 매니저 실패
- NM 가 주기적으로 RM 에게 보내는 하트비트가 끊기는 경우
- RM 은, 실패한 NM 에 컨테이너 할당하지 않도록 노드 풀에서 제거
- 실패한 NM 에 AM 이나 task 실행시, 위의 절차대로 AM 와 task 재실행

리소스 매니저 실패
- RM 이 실패하면 모든 실행중인 잡이 실패함
- HA 구성하여 RM 복구 가능 (RM 에 Failover Controller 가 포함되어있음 : https://eyeballs.tistory.com/251)
- 실행중인 애플리케이션에 대한 모든 정보zookeeper 혹은 HDFS 에 보관되기에
  standby RM 가 active RM 이 된 후에도 핵심 상태 복구 가능
- RM 이 재실행되면 모든 AM 이 재실행 됨
- RM 이 재실행되면, NM 와 Client 는 round robin 방식으로 Active RM 을 직접 찾음



맵 부분

- 처리 결과는 환형 구조의 인메모리 버퍼에 씀
- 메모리가 꽉차면, 메모리 내에서 리듀서 개수에 맞게 파티션 나누고 정렬하고, 정렬된 채로 disk 에 spill
- map 결과는 여러 spill 의 병합(파티셔닝은 아직 되어있음)
- 3개 이상의 spill 인 경우 컴바이너가 실행됨

map 의 결과는 job 이 끝날때까지 사라지지 않음
왜냐면 reducer 가 복사해가야하는데 실패할 수 있으니까



리듀스 부분

- HTTP 를 통해 map 의 결과 중 자신에게 맞는 파티션 부분을 복사해서 가져옴
- map 을 어떻게 찾는가? AM 에게 물어봐서 map 위치 찾음
- 리듀스 disk 에 map 의 여러 결과들이 축적되면 더 크고 정렬된(정렬 순서 유지) 하나의 형태로 병합 (round 단위로 병합)
- 하나로 병합된 후 리듀스의 입력으로 들어감



투기적 실행
- 하나의 느린 태스크가 전체 job 수행 시간을 지연시킬 수 있음
- 느린 태스크를 감지하면, 또 다른 동일한 태스크를 실행
- 둘 중 하나가 먼저 끝나면, 끝나지 못한 다른 태스크는 강제 종료

투기적 실행의 목적잡 실행 시간을 줄이는 것이지만
클러스터 효율성 측면에서 비용이 발생하고 전반적인 단위 시간당 산출물이 줄어듦
그래서 투기적 실행은 안 하는 게 좋음
(리듀스가 투기적 실행을 해버리면, 셔플을 중복으로 하기 때문에 네트워크 트래픽을 심각하게 증가시킴...)


 

 

8.


입력 스플릿
https://eyeballs.tistory.com/281
https://eyeballs.tistory.com/264


 

 

10.


데이터 노드에 RAID 를 적용하여도 이득은 거의 없음
- RAID 가 제공하는 데이터 중복성을 HDFS 가 이미 갖고 있기 때문
- RAID 에 데이터를 쓸 때 가장 느린 디스크에 의해 속도가 결정남
  HDFS 에 데이터를 쓸 때 병렬로 쓰기 때문에 가장 느린 디스크보다 속도가 빠름
- RAID 디스크가 고장나면 전체가 고장날 수 있음

네임 노드에 RAID 적용은 이득이 있음



마스터 노드인 네임 노드, 리소스 매니저는 각기 다른 서버에서 동작하도록 함
네임 노드와 보조 네임 노드 역시 각기 다른 서버에서 동작하도록 함
데이터 노드, 노드 매니저들은 마스터 노드와 다른 서버들 위에서 함께 동작

이렇게 마스터 노드를 분리하는 이유 고가용성 HA 때문
active 가 죽는 경우 standby 가 일 해야하기 때문



네트워크 거리 계산을 위한, 네트워크 토폴로지 설정 정보는 관리자가 직접 넣음
알아서 계산하지 않음



아래는 하둡 설치 절차

hadoop 설치할 때는 /usr/local 혹은 /opt 에 설치

hadoop 데몬 실행시 하둡 전용 사용자 계정(hdfs, mapred, yarn 등)을 생성하는 것이 좋음
다른 서비스와 하둡 프로세스를 구분하기 위함

제어 스크립트(start-dfs.sh 등)는 SSH 를 이용하여 전체 클러스터에 작업 수행
따라서 SSH 접근시 비밀번호가 없어야 함
제어 스크립트를 사용하는 것은 선택사항

HDFS 처음 설치시, 파일 시스템 포맷 진행이 반드시 필요
포맷 작업새로운 빈 파일시스템을 생성하는 것
데이터 노드는 동적으로 클러스터에 포함/제외 될 수 있기에 포맷 작업은 오로지 네임 노드가 진행

workers 파일에 데이터 노드와 노드 매니저가 동작할 워커 노드들의 ip 넣음

start-dfs.sh 실행시, 네임 노드hdfs getconf -namenodes 명령어의 결과로 나온 노드들에서 실행됨
리소스 매니저start-yarn.sh 명령어가 실행된 노드에서 실행



하둡의 각 노드들자신만의 환경 설정 파일을 갖고 있음
따라서 관리자는 이 파일들을 전체 클러스터에 동기화 해야 함
왜냐면 모든 파일이 동일한 내용을 갖어야 하기 때문
좋은 성능의 노드가 들어와도 동일한 환경 설정 파일을 활용해야 함(...)



하둡의 각 데몬 당 1gb 의 메모리가 기본으로 할당됨
hadoop-env.sh 의 HADOOP_NAMENODE_OPTS 속성에 JVM 옵션으로 메모리 용량 설정하면
다른 하둡 데몬에 영향 없이 Name Node 의 메모리 용량 증가 가능

로그 파일 default 는 $HADOOP_HOME/logs
대개 /var/log/hadoop 로 변경하는데, 이유는 hadoop home 이 바뀌어도 동일한 곳에 로그를 유지하기 위함

하둡 로그는 두 가지
.log : log4j 통해서 생성. 애플리케이션 로그 메세지. 알아서 지워지지 않음
.out : 표준 출력, 표준 에러. 최근 5개만 로그만 보관됨

하둡 데몬은 데몬 사이 통신을 위한 RPC, WebUI 제공을 위한 HTTP 모두 실행
추가적으로 데이터 노드 블록 전송을 위해 TCP/IP 실행

기본적으로 데이터 노드는 저장된 저장 디렉터리 가용한 모든 공간을 사용하려고 함

단락 지역 읽기
- 블록이 있는 노드에서 클라이언트가 동작한다면, TCP/IP 없이 곧바로 블록 읽을 수 있음


 

11.


클라이언트가 HDFS 에 업데이트를 하면,
업데이트는 local disk 의 edit log 에 기록된 후 메모리상의 메타데이터가 변경

fsimage 는 메타데이터의 영속적인 체크포인트
업데이트 내역은 fsimage 에 곧바로 쓰이지 않는데, 왜냐면 크기가 많이 늘어나 성능이 안 좋아지기 때문

네임 노드 장애 발생시, fsimage 를 메모리에 로드하고
edit log 에서 특정 지점 이후 발생한 변경 내역들을 메모리에 반영

edit log 역시 크기가 커질 수 있음
따라서 보조 네임노드를 이용하여 fsimage 와 edit log 를 병합
- 보조 네임노드는 네임노드로부터 fsimage 와 edit log 를 가져감
- 그 동안 네임노드는 새로운 edit log 를 사용
- 보조 네임노드는 fsimage 와 edit log 를 병합
- 병합한 fsimage 를 네임노드에게 줌



네임노드 시작시, fsimage 를 메모리에 로드하고
edit log 변경 내역들을 메모리에 반영하고
데이터 노드들로부터 파일 위치 등을 보고받음
이 작업을 하는 동안 안전 모드가 켜지며, 쓰기는 금지되고 읽기만 가능


dfsadmin : HDFS 의 상태 정보 확인 및 다양한 관리 작업 수행 도구

fsck : HDFS 에 저장된 파일 상태 점검 도구
- 초과 복제 블록 : 초과된 만큼 삭제
- 복제 기준 미만 블록 : 미만인 만큼 복제
- 잘못 분배된 블록 : 한 랙에 모든 블록이 있는 경우. 다시 넓게 퍼뜨림
- 모든 복제본이 손상된 블록 : 놔두거나 lost+found 로 옮김
- 존재하지 않는 블록 : 놔두거나 lost+found 로 옮김

블록 스캐너 : 데이터 노드에 저장된 모든 블록을 3주마다 점검. 모든 데이터 노드가 실행

diskbalancer : 하나의 데이터 노드여러개의 disks 가 있는 경우, disks 간 데이터 불균형이 일어났을 때 불균형을 해소시켜줌
balancer : 클러스터에서(여러 데이터노드 간) 데이터 불균형이 일어났을 때 불균형을 해소시켜줌. 
https://eyeballs.tistory.com/280



메트릭 : 하둡 데몬이 수집. 관리자를 위한 정보
카운터 : MR task 가 수집. MR 사용자를 위한 정보

아래는 최적화 내용

< 메모리 >
MR 작업은 CPU 보다 메모리 자원에 더 민감함. 실제로 MR 작업시 메모리를 많이 사용
스왑 메모리 사용량을 모니터링하고 메모리 옵션값을 조절하여 최대한 swap out 이 발생하지 않도록 함

< IO >
file/dir 에 접근 할 때마다 시간 기록을 하지 않도록 noatime 옵션으로 구성
복제 등은 이미 HDFS 에서 제공하고 있으므로 추가 복제를 일으키는 RAID를 사용하지 않음

< 네트워크 >
컴바이너를 꼭 사용하여 셔플되는 데이터 양을 줄여 네트워크 오버헤드 줄임
대용량의 매퍼 결과값을, Snappy 등을 사용하여 압축하는 것으로 네트워크 오버헤드를 줄일 수 있음

< 기타 >
JVM GC 실행 횟수 등을 모니터링 하면서 GC 튜닝을 한다던가 코드에서 쓸데없이 낭비되는 메모리를 줄이는 방향으로 한다던가 함

참고 [링크1] [링크2]


 

 

Hive

1.


하이브에서 작성된 쿼리는 일련의 MR 잡으로 변환되어 실행됨

하이브는 HDFS 에 저장된 데이터에 스키마를 입히는 방식으로 데이터를 테이블로 구조화 (읽기 스키마)

테이블 스키마 같은 메타데이터는 메타스토어라 불리는 DB 에 저장
메타스토어가 로컬 머신에 있으면, 한번에 한명의 유저만 사용 가능(derby 를 사용하지 말아야 하는 이유)
실제 운영 환경에선 공유 원격 메타스토어를 사용

Hive 는 HADOOP_HOME 환경변수가 설정되어 있다면 HDFS 사용 가능


'hive' 명령어를 사용하면, 사용자 머신에 메타스토어 데이터베이스를 만듦
hive 명령어 실행한 위치에 metastore_db 라는 디렉터리 만들어 그 안에 필요한 파일 저장

local 데이터를 읽고 local 에 저장할 수 있음
저장시 데이터를 변경하지 않고 그대로 저장
local 에 저장할 때 하이브가 저장하는 경로는 웨어하우스 디렉터리(기본값 /user/hive/warehouse)

하이브는 특정 테이블 질의할 때 모든 파일을 다 읽음
그래서 효율적인 쿼리를 위해 버켓팅, 파티셔닝이 필요



하이브 속성 설정 우선순위
1. hive> 에 넣는 SET 명령어
2. 명령어에 넣는 -hiveconf 옵션
3. *-site.xml
4. *-default.xml



Hive 쿼리 실행 엔진은 MR, Tez, Spark 를 지원


 

2.


하이브 서비스
- cli : hive 드라이버에 바로 접근. 접근 권한 확인 하지 않아서 되도록 hiveserver2 사용
- hiveserver2 : 다른 언어로 개발된 클라이언트와 연동 가능하도록 하이브 쓰리프트 서비스 실행
  hiveserver2 로 쓰리프트 서비스가 실행되고,
  이를 통해 다른 언어에서 thrift, JDBC, ODBC 연결자로 하이브에 연결 가능
  접근 권한 확인 등을 hiveserver2 에서 진행
- beeline : JDBC 로 hiveserver2 프로세스에 접근하는 명령행 인터페이스
- hwi : 하이브 웹 인터페이스
- 메타스토어 : 기본적으로 메타스토어는 하이브 서비스와 동일한 프로세스에서 실행됨
  이 서비스는 메타스토어를 독립형 원격 프로세스로 실행함

 

 

3.


메타스토어는 하이브 메타데이터를 저장하는 핵심 저장소
메타스토어는 서비스데이터 보관 저장소로 나뉨

내장 메타스토어
- 메타스토어 서비스 : 하이브 서비스와 동일한 JVM 내에서 동작
- 메타스토어 저장소 : 하이브 서비스와 동일한 JVM 내에서 동작. derby
  local 에 데이터 저장하는 derby 데이터베이스
  derby 는 한 번에 db파일 하나에만 접근 가능해서 하나의 하이브 세션만 사용 가능
  (다른 사용자 등에 의해) 두 번째 세션 사용 불가
  따라서 다중 세션(다중 사용자) 지원 불가

로컬 메타스토어
- 메타스토어 서비스 : 하이브 서비스와 동일한 JVM 내에서 동작
- 메타스토어 저장소 : 원격 머신에서 별도의 프로세스로 실행되는 데이터베이스. mysql, postgresql etc
  다중 세션(다중 사용자) 지원 가능
  mysql, postgresql 등을 원격 데이터베이스로 사용

원격 메타스토어
- 메타스토어 서비스 : 하나 이상의 메타스토어 서버가 하이브 서비스와 별도의 JVM 프로세스로 실행
- 메타스토어 저장소 : 원격 머신에서 별도의 프로세스로 실행되는 데이터베이스. mysql, postgresql etc
  클라이언트와 메타스토어 서버는 thrift로 통신함
  데이터베이스 계층이 방화벽 역할을 대신하기 때문에
  클라이언트는 데이터베이스 자격 증명을 얻을 필요가 없어서 관리성과 보안성이 높아진다는데
  무슨 말인지 모르겠음
  메타스토어 서비스가 별도의 서버에서 실행되면, 가용성과 확장성이 제공됨


 

 

4.


rdb 와 hive 차이
- rdb 는 쓰기 스키마, hive 는 읽기 스키마
  쓰기 스키마는 index 를 지원해서 쿼리가 빠르지만,
  읽기 스키마는 디스크 직렬화가 필요없어서 데이터 write 가 매우 빠름
- rdb 의 트랜잭션, 색인 기능은 hive 에서 일부 지원
  트랜잭션(update)이 활성화된 hive 는 update 가 가능하지만,
  실제 테이블 내 데이터가 업데이트를 하는 건 아니update 내역을 별도의 작은 델타 파일로 저장
- hive 의 insert into : 하이브 테이블, 파티셔닝 된 테이블 내에 데이터를 추가하며 insert 함
  insert overwrite : 하이브 테이블, 파티셔닝 된 테이블 내의 데이터를 모두 지우고 insert 함
- 데이터를 읽을 때 SHARED_READ lock 을 얻는데,
  해당 lock 이 존재하면 다른 사용자가 읽기 가능, update 불가능
- 데이터를 update 할 때 EXCLUSIVE lock 을 얻는데,
  해당 lock 이 존재하면 다른 사용자가 읽기/update 가 불가능

hive 가 지원하는 색인
- 콤팩트 색인 : HDFS 블록 넘버로 색인
- 비트맵 색인 : 특정 값이 출현하는 행을 효율적으로 저장하기 위해 압축된 비트셋으로 색인
색인을 위한 데이터는 별도의 테이블에 저장됨

 

6.


하이브 테이블의 데이터 저장소는 local disk, s3, HDFS 등 다양하게 사용 가능

관리 테이블 : 하이브가 데이터를 직접 관리
  load 쿼리 사용시, 해당 데이터가 웨어하우스 디렉터리(local, HDFS 등)으로 이동
  drop 쿼리 사용시, 해당 데이터와 메타데이터가 실제로 삭제

외부 테이블 : 하이브가 데이터를 직접 관리하지 않음
  외부 테이블(HDFS, S3 등)에 데이터를 저장하고 삭제하는 것은 hive 가 아닌 사용자
  drop 쿼리 사용시, 메타데이터만 삭제되고 데이터는 삭제되지 않음


파티션 : 데이터를 각 dir 에 나눠 저장. PARTITIONED BY
버킷 : 지정한 컬럼값을 해쉬 처리 한 후, 버킷수로 나눈 나머지만큼 파일로 나눠 저장. dir 가 아닌 파일에 저장. CLUSTERED BY

버킷을 사용하는 이유
- 매우 효율적인 쿼리가 가능
  테이블에 대한 추가 구조를 부여하게 되고, 쿼리 수행 시 이 추가 구조 사용 가능
- 효율적인 샘플링에 유리
- 버켓팅한 테이블은 조인시에 SMB(sort merge bucket) 조인으로 처리하여 속도 향상



row format : 행 구분자 설정, 특정 행의 필드가 저장된 방식 설정

- 지정가능한 구분자 
  FIELDS TERMINATED BY '\t'            -- 칼럼을 구분하는 기준
  COLLECTION ITEMS TERMINATED BY ','   -- 리스트를 구분하는 기준
  MAP KEYS TERMINATED BY '='           -- 맵데이터의 키와 밸류를 구분하는 기준
  LINES TERMINATED BY '\n'             -- 로(row)를 구분하는 기준
  ESCAPED BY '\\'                      -- 값을 입력하지 않음
  NULL DEFINED AS 'null'               -- null 값을 표현(0.13 버전에서 추가)

- 특정 행의 필드 저장 방식 : 데이터 저장시 SerDe 를 통해 직렬화하여 저장하고 읽을 때 역직렬화하여 읽나 봄
기본서데, 정규식(RegExSerDe), JSON(JsonSerDe), CSV(OpenCSVSerde)가 존재함

stored as : 데이터를 저장하는 파일 포맷 지정
저장 포맷은 TEXTFILE, SEQUENCEFILE, ORC, PARQUET 등이 존재
바이너리인 sequence, orc, parquet 등은 행의 형식이 바이너리 포맷에 따라 결정되므로 row format 지정 불필요

참고 https://wikidocs.net/23469



hive 는 읽기 스키마를 사용하기 때문에
테이블의 이름 변경, 테이블의 정의 변경, 새로운 컬럼 추가 등이 자유로움


 

셔플 조인은 가장 느린 조인

맵(Map) 단계에서 각 테이블을 읽고, 조인 컬럼을 키로 설정하여 셔플

리듀서로 데이터가 이동되고 리듀서에서 테이블을 조인

 

버켓팅 되어있으면 Bucket Map Join 이 빨라짐.

https://data-flair.training/blogs/bucket-map-join/

join 의 기준이 되는 key 들이 모두 버케팅 되어있는 상황에서 Join 을 진행하면,

작은 테이블의 버킷들(Table a, Table c)이 큰 테이블의 버킷(Table b)의 메모리에 모두 복사됨

이렇게되면 join 에 필요한 모든 key 가 하나의 Mapper 에서 접근 가능하기 때문에 join 속도 향상

작은 테이블 크기가 메모리에 올라갈 정도로 작아야 함

브로드캐스트 조인임.

 

Sort Merge Join 은 조인 테이블이 버켓팅 되어 있을 때 사용 가능

버켓팅된 키의 정보를 이용하여 빠르게 조인

다음 절차로 join 이 진행됨

- Table a 와 Table b 에서 join 에 필요한 데이터를 읽음

- 별도의 공간에서 읽은 데이터를 정렬sort 함

- 정렬된 데이터를 기준으로 join 함

 

참고 : https://coding-factory.tistory.com/757

 

 


hive 명령어와 beeline 명령어 차이?

- hive 명령어는 하이브 옵션 설정, 쿼리 실행 등이 가능

- beeline 은 단지 hive 에 thrift 로 접근하는 인터페이스

 

thrift : 다양한 언어로 개발된 소프트웨어들을 쉽게 결합(통신)하는 프레임워크. 내부에서 RPC 사용

JDBC :

- Java Database Connectivity

- JAVA 언어로 DB 에 접근해 DML 쿼리 하기 위한 인터페이스

- Java와 연동되는 DBMS에 따라 그에 맞는 JDBC를 설치할 필요가 있음

ODBC

- Open Database Connectivity

- 응용프로그램에서 다양한 DB 에 접근해 DML 쿼리하기 위한 인터페이스

- 접속처의 데이터베이스가 어떠한 DBMS에 의해 관리되고 있는지 의식할 필요가 없음

 

hive 에서 orc 를 사용하는 이유

- 높은 압축률

- 컬럼 기반 포맷이라 처리 속도가 빠름

- 스키마를 가지고 있음

- orc 는 hive 에 최적화되어있고, parquet 은 spark 에 최적화 되어있음

 

 

 

ORDER BY vs DISTRIBUTE BY vs SORT BY vs CLUSTER BY

 

ORDER BY

- 매퍼에서 나오는 모든 데이터를 하나의 리듀서로 몰아서 정렬 수행

- 리듀서가 하나 뿐이라, 저장되는 파일도 하나

- limit 을 추가하여 리듀서에 부하를 줄이는 게 좋음

- order by COLUMN

 

SORT BY

- ORDER BY 와 다르게, 리듀서가 하나 이상, 각 리듀서에서 정렬 수행

- 각 리듀서별로 정렬하기 때문에, 모든 리듀서 결과는 전체 정렬 되어있지 않음

- 리듀서 개수를 1로 설정하면 ORDER BY 와 같은 결과

- sort by COLUMN

 

DISTRIBUTE BY

- distributed by 의 대상이 되는 컬럼의 값 기준으로 group 지어 하나의 리듀서에 들어감

정렬 수행하지 않음

- 예)

  정렬 대상 : a a b c c c d

  리듀서 1) a d a

  리듀서 2) c b c c

  (리듀서 개수와 상관 없이) 같은 값은 모두 하나의 리듀서에 몰려 있음. 

 

CLUSTER BY : 

 

- distributed by 와 sort by 를 같이 사용

- 즉, distributed by 실행하며 정렬까지 진행

- 예)

  정렬 대상 : a a b c c c d

  리듀서 1) a a d

  리듀서 2) b c c c

 

참고) https://saurzcode.in/2015/01/hive-sort-order-distribute-cluster/

 

 

 

Hive 정적 파티션 vs 동적 파티션

 

정적 파티션

- 데이터의 테이블에 파티션 값을 직접 입력

  예)

  INSERT INTO TABLE tbl(yymmdd='20220625')
  SELECT name FROM temp;

  > hdfs://hive/tables/yymmdd=20220625/

 

동적 파티션

- 데이터의 컬럼값을 기준으로 파티션이 생성

- 쿼리 시점에 어떤 데이터가 어떤 파티션에 가는지 모름

- 동적 파티션은 느림

  예)

  INSERT INTO TABLE tbl(yymmdd)
  SELECT name, yymmdd FROM temp;

  > hdfs://hive/tables/yymmdd=20220625/

  > hdfs://hive/tables/yymmdd=20220626/

  > hdfs://hive/tables/yymmdd=__HIVE_DEFAULT_PARTITION__/

 

 

 

HDFS 에서 작은 파일들 합치기

https://gyuhoonk.github.io/hive-merge-query

 

결론

작은 파티션들이 많으면, HDFS IO 도 많아지고 NN memory 에 부담도 커짐

Hive

- insert into 등의 쿼리는 매퍼만 동작하는데,

  매퍼에서 읽은 데이터를 그대로 HDFS 블럭으로 저장하기 때문에 블럭 개수가 늘어남

  이를 합쳐주기 위해 (sort by 등을 추가하여) 리듀서를 추가

Spark

- 셔플 파티션은 기본값이 200 이라서, 셔플 후에는 200개의 작은 파티션들이 생성되어 HDFS 에 저장됨

  이를 합쳐주기 위해 셔플 파티션 값을 조정하거나, repartition 혹은 coalesce 를 사용하여 파티션 개수 줄임

 

 

 

 

Zookeeper


주키퍼란, 분산 작업을 제어하기 위한 트리 형태데이터 저장소

노드 종류는 세 가지
- 영구 노드(Permanent Node) : 한 번 저장한 데이터가 영구적으로 유지되는 노드
- 임시 노드(Ephemeral Node) : 클라이언트 세션이 유효한 동안만 살아있는 노드
- 순차 노드(Sequence Node) : 저장하는 순서에 따라 자동으로 일련번호가 붙는 노드

주키퍼는 빠른 처리를 위해 모든 트리 노드를 메모리에 올려놓고 처리하지만
Memcached, Redis 와는 다르게 사용됨

주키퍼에서 제공하는 기능 중, 데이터 변경을 감시하여 콜백을 실행하는 감시자(Watcher)가 있음
감시자를 트리 내의 특정 노드에 등록하면,
별도로 데이터 폴링을 하지 않더라도 노드 변경 사항을 전달받을 수 있음

주키퍼 클러스터(앙상블)는 한 대의 leader 와 나머지 follower 로 구성
클라이언트의 읽기 요청은 leader, follower 모두 수행 가능
클라이언트의 쓰기 요청은 leader 만 가능
쓰기 요청을 받은 follower 가 leader 에게 요청을 넘기고,
leader 는 follower 들로부터 쓰기 ack 응답을 요청
과반수 이상의 ack 응답이 오면 follower 들에게 쓰기 진행

NN 같이 분산 처리 제어를 위해 사용되는 주키퍼는 소모하는 하드웨어 자원이 굉장히 적음
multi tenant 기능이 존재함
클라이언트 세션을 생성할 때 특정 노드 경로를 지정하면, 이후 접근은 이 경로 하위만을 사용함
즉, 클라이언트마다 각기 다른 경로를 주고 그 경로만 사용하도록 함

클라이언트 계정마다 각기 다르게 노드를 사용할 수 있도록 ACL(Access Control List) 지정 가능
상위 노드에 ACL 이 걸려있어도 하위 노드에 ACL 이 자동으로 붙지 않음
모든 하위 노드에 ACL을 적용해야 하는데 좋은 방법이 아님
따라서 주키퍼를 공유 서버 형태로 제공하기 위험함




참고 https://d2.naver.com/helloworld/583580



리더 선출 기능
- 주키퍼에 리더 선출을 위한 path 생성 (예를 들면 /election)
- 해당 path 이하 SEQUENCE| EPHEMERAL 플래그를 줌
- 서버 (혹은 프로세스) 가 붙을 때마다 순차적으로 값이 붙음 (sequence flag 때문)
- 생성된 znode 들 중, 리더는 항상 가장 작은 값을 갖는 znode
- 가장 작은 znode 값에 감시자가 붙음
- 리더가 죽으면 감시자가 알게되고, 그 다음 작은 값을 갖는 znode 가 리더가 됨

참고 https://zookeeper.apache.org/doc/current/recipes.html

분산락 기능
- 주키퍼에 분산락 기능을 위한 path 생성 예를 들면 /lock)
- 해당 path 이하 SEQUENCE| EPHEMERAL 플래그를 줌
- 서버 (혹은 프로세스) 가 붙을 때마다 순차적으로 값이 붙음 (sequence flag 때문)
- lock 을 원하는 서버들이 getchildren 함수를 사용하여 /lock 이하 노드들을 받음
- 가장 낮은 znode 를 갖는 노드를 받은 서버가 lock 을 가져감
- 나머지 서버들은 기다림
- lock 을 해제할때는 lock 을 가져간 서버에서 가장 낮은 znode 를 삭제
- 그 다음 낮은 znode 를 가져간 서버가 lock 을 가져감...

참고 http://think-in-programer.blogspot.com/2011/01/5-zookeeper.html

분산처리 시스템에서 ACID 속성중 정합성(Consistency) 독립성(Isolation)을 보장하는것은 쉽지 않다. 
주키퍼는 데이터 저장시 아래와 같은 사항을 보장한다.
- 순차적 정합성(Sequential Consistency) : 주키퍼 클러스터에 저장되는 데이터는 강한 정합성(Strong Consistency)를 보장하지 않고, 이벤추얼 정합성(Eventual Consistency)을 보장한다. 이벤추얼 정합성은 일정 시간이 지나면 정합성이 맞춰지는 속성이다.
특정 클라이언트로부터 데이터 저장에 대한 요청이 있을때, 분산되어 있는 주키퍼 서버에 반영되는 순서는, 클라이언트에서 전송된 요청 순서대로 처리되는것을 보장한다.
- 원자성(Atomic) : 전체가 수행되거나 전체가 실패되는 행위로, 부분적인 성공은 존재하지 않는다.
- 단일 이미지 뷰 제공 (Single System Image) : 클라이언트는 어떤 주키퍼 서버에 접속하더라도 동일한 데이터 뷰를 제공 받는다.
- 안정성 (Reliability) : 주키퍼에 저장된 데이터는 (클라이언트의 명시적인 호출에 의해 수정되지 않는 한) 영속성을 가지고 있다.
출처: https://sungwookkang.com/1431 


eventual consistency 와 strong consistency
https://velog.io/@soongjamm/Eventual-Consistency-%EB%9E%80 
CAP 이론 중 일관성과 가용성을 기준으로 갈림

Consistency 일관성 : 모든 사용자가 동일한 값을 반환 받음
Availability 가용성 : 모든 요청에 대해 (실패가 아닌) 정상적인 응답 반환 받음

결론
eventual consistency
- 업데이트 후, 모든 노드가 업데이트 되지 않음(정합성이 맞춰지지 않음)
- 사용자는 오래된 정보를 볼 수 있어 가용성이 유지되나 일관성 없음
- 언젠가는 모든 노드에 업데이트가 적용(언젠가는 정합성이 맞춰짐)
- 예) Zookeeper

strong consistency : 
- 업데이트 후, 모든 노드가 업데이트 적용받을 때 까지 lock 에 걸림(정합성이 처음부터 유지됨)
- lock 에 걸려서 사용자가 사용 불가. 가용성 없으나 일관성은 유지
- 예) RDB



왜 3대 이상의 홀수 개수로 유지하는 것이 좋은가?

짝수로 운영해도 문제는 없으나
짝수나 홀수나 장애(결함) 허용 개수가 동일함

3대인 경우 과반수는 3/2+1 = 2대 : 결함 허용 개수는 1대 (=3-2)
4대인 경우 과반수는 4/2+1 = 3대 : 결함 허용 개수는 1대 (=4-3)
5대인 경우 과반수는 5/2+1 = 3대 : 결함 허용 개수는 2대 (=5-3)
6대인 경우 과반수는 6/2+1 = 4대 : 결함 허용 개수는 2대 (=6-4)


 

 

HDFS 는 one-copy-update-semantics consistency 를 갖음

모든 클라이언트는 파일의 복사본이 하나만 존재하는 것처럼 파일의 내용을 동일하게 봄

모든 사용자가 파일 업데이트를 즉시 볼 수 있으며

디렉터리 목록 결과는 해당 디렉터리 내의 최신 상태를 보여줌

 

반면 S3 는 eventual consistency 를 갖음

업데이트가 모든 사용자에게 영향을 끼치기까지 시간이 좀 걸림

 

참고  [공식 문서] [HDFS vs S3 비교]

 

 

 

 

 

 

 

 

 

하둡 MR 은 잡의 입력을 입력 스플릿 혹은 스플릿 이라는 고정 크기 조각으로 분리

분리 된 개수만큼 맵 태스크가 생성

스플릿의 각 레코드를 사용자 정의 맵 함수로 처리

 

스플릿 크기가 작을 수록, 병렬 처리성(부하 분산)에 효과적이다.

하지만 크기가 너무 작아지면 스플릿 관리와 맵 태스크 생성을 위한 오버헤드 때문에

잡의 실행 시간이 증가함

 

일반적인 스플릿 크기는 HDFS 블록의 기본 크기인 128mb 가 적당

최적의 스플릿 크기가 HDFS 블록 크기(128mb)와 같아야 하는 이유는 

그 블록 크기가 단일 노드에 저장된다고 확신할 수 있는 가장 큰 입력이기 때문

하나의 스플릿이 두 블록에 걸쳐있을 때(128mb 이상일 때)

두 블록 모두 저장하는 HDFS  노드는 존재할 가능성이 낮아서

스플릿의 일부 데이터를 네트워크를 통해 맵 태스크가 실행되는 다른 노드로 전송해야 함

이렇게 되면 맵 태스크 전체가 로컬 데이터만 이용할 때보다 느려짐

 

입력 스플릿에 대한 추가 설명 : https://eyeballs.tistory.com/264

 

 

맵 태스크의 결과는 HDFS 가 아닌 로컬 디스크에 저장됨.

HDFS 에 저장되면 replication 해야하니까 적절치 않음.

 

 

Reduce 태스크의 경우 입력값이 Map 태스크의 결과값이기 때문에

HDFS 를 이용한 데이터 지역성의 장점이 없음.

 

 

위에 필기 중간에 맵리듀스 셔플 정렬 부분 그림

 

 

아래는 셔플 절차를 다시 쓴 것

 

 

리듀서 부분에 대해 좀 더 알아본다.

 

맵의 결과는 맵이 실행된 노드의 로컬 디스크에 저장됨.

맵 태스크는 각기 다른 시간에 끝날 수 있으므로,

리듀스 태스크는 각 맵 태스크의 출력이 끝나는 즉시 리듀스가 실행되고 있는 노드로 맵의 결과를 복사하기 시작.

 

맵 출력의 크기가 충분히 작다면, 리듀스 태스크 JVM 메모리로 복사가 됨.

인메모리 버퍼가 한계치에 도달하거나

맵 출력 수가 한계치에 도달하면 병합되어 디스크에 spill이 됨.

(이때 컴바이너가 지정되었다면 병합 도중 실행되어 디스크에 쓰여지는 데이터양을 줄임)

 

복사된 파일이 디스크에 저장축적되면 background thread 가 이들을 더 크고 정렬된 형태의 파일로 병합.

(추후 병합 시간을 절약하기 위함)

 

모든 맵 출력이 복사되었다면, 리듀스 태스크는 정렬병합단계로 이동

맵 출력을 병합하고 정렬 순서를 유지

이 작은 라운드 단위로 이뤄지고 병합 계수에 따라 파일을 병합

예를 들어 50개의 맵 출력이 존재하고 병합계수가 10이라면 5개의 라운드가 구성되어

각 라운드마다 10개의 파일을 하나로 병합함

결과적으로 5개의 중간 파일이 생성

 

이 5개의 중간 파일들을 하나로 병합하지 않고,

곧바로 리듀스 함수로 전송하여 디스크 IO를 줄임.

즉, 최종 라운드는 리듀스 함수로 곧바로 전송함.

 

 

 

 

 

 

 

 

 

+ Recent posts