HDFS 이레이저 코딩

HDFS 이레이저 코딩 (Erasure Coding)

목적 (Purpose)

복제(replication)는 비쌉니다. HDFS의 기본 3x 복제 방식은 저장 공간과 다른 리소스(예: 네트워크 대역폭)에 200% 오버헤드가 있습니다. 그러나 I/O 활동이 상대적으로 낮은 웜(warm) 및 콜드(cold) 데이터셋의 경우, 추가 블록 복제본은 정상 작동 중에 거의 접근되지 않으면서도 첫 복제본과 동일한 리소스를 소비합니다.

출처: HDFS Erasure Coding

따라서 자연스러운 개선은 복제 대신 **이레이저 코딩(EC, Erasure Coding)**을 사용하는 것입니다. EC는 훨씬 적은 저장 공간으로 동일한 수준의 장애 허용을 제공합니다. 일반적인 EC 설정에서 저장 오버헤드는 50%를 넘지 않습니다. EC 파일의 복제 계수는 의미가 없습니다. 항상 1이며 -setrep 명령으로 변경할 수 없습니다.

배경 (Background)

저장 시스템에서 EC의 가장 주목할 만한 사용은 RAID(Redundant Array of Inexpensive Disks)입니다. RAID는 스트라이핑(striping)을 통해 EC를 구현합니다. 스트라이핑은 논리적으로 연속적인 데이터(예: 파일)를 더 작은 단위(비트, 바이트, 블록 등)로 나누고 연속 단위를 서로 다른 디스크에 저장합니다. 이 가이드의 나머지에서 이 스트라이핑 분배 단위를 **스트라이핑 셀(striping cell, cell)**이라 부릅니다. 원본 데이터 셀의 각 스트라이프에 대해 일정 수의 패리티 셀이 계산되고 저장됩니다. 이 과정을 **인코딩(encoding)**이라 합니다. 어떤 스트라이핑 셀의 오류는 살아남은 데이터와 패리티 셀에 기반한 디코딩 계산을 통해 복구될 수 있습니다.

EC를 HDFS에 통합하면 저장 효율을 향상시키면서도 기존 복제 기반 HDFS 배포와 유사한 데이터 내구성을 제공할 수 있습니다. 예를 들어 6개 블록을 가진 3x 복제 파일은 6*3 = 18 블록의 디스크 공간을 소비합니다. 그러나 EC(데이터 6, 패리티 3) 배포에서는 9 블록의 디스크 공간만 소비합니다.

아키텍처

EC 맥락에서 스트라이핑은 몇 가지 중요한 이점이 있습니다. 첫째, 온라인 EC(데이터를 즉시 EC 형식으로 쓰기)를 가능하게 하여 변환 단계를 피하고 즉시 저장 공간을 절약합니다. 온라인 EC는 또한 여러 디스크 스핀들을 병렬로 활용해 순차 I/O 성능을 향상시킵니다. 이는 특히 고성능 네트워킹을 가진 클러스터에서 바람직합니다. 둘째, 작은 파일을 여러 DataNode에 자연스럽게 분배하여 여러 파일을 단일 코딩 그룹으로 묶을 필요를 제거합니다. 이는 삭제, 할당량 보고, 페더레이션 네임스페이스 간 마이그레이션 같은 파일 연산을 크게 단순화합니다.

일반적인 HDFS 클러스터에서 작은 파일은 총 저장 소비의 3/4 이상을 차지할 수 있습니다. 작은 파일을 더 잘 지원하기 위해 이 작업의 첫 단계에서 HDFS는 스트라이핑을 사용한 EC를 지원합니다. 향후 HDFS는 연속(contiguous) EC 레이아웃도 지원할 것입니다. 자세한 내용은 HDFS-7285의 설계 문서와 토론을 참고하세요.

  • NameNode 확장 - 스트라이프 HDFS 파일은 논리적으로 블록 그룹(block group)으로 구성되며, 각 그룹은 일정 수의 내부 블록을 포함합니다. 이 추가 블록들로 인한 NameNode 메모리 소비를 줄이기 위해 새로운 계층 블록 명명 프로토콜이 도입되었습니다. 블록 그룹의 ID는 내부 블록 중 어느 하나의 ID에서 유추할 수 있습니다. 이는 블록이 아닌 블록 그룹 수준에서 관리를 가능하게 합니다.
  • 클라이언트 확장 - 클라이언트 읽기/쓰기 경로가 블록 그룹의 여러 내부 블록에 병렬로 작동하도록 강화되었습니다. 출력/쓰기 경로에서 DFSStripedOutputStream은 현재 블록 그룹의 내부 블록을 저장하는 각 DataNode에 대해 하나씩 데이터 스트리머 집합을 관리합니다. 스트리머는 대부분 비동기적으로 작동합니다. 코디네이터가 블록 그룹 종료, 새 블록 그룹 할당 등 전체 블록 그룹에 대한 작업을 담당합니다. 입력/읽기 경로에서 DFSStripedInputStream은 요청된 논리 바이트 범위의 데이터를 DataNode에 저장된 내부 블록의 범위로 변환합니다. 그런 다음 읽기 요청을 병렬로 발행합니다. 실패 시 디코딩을 위한 추가 읽기 요청을 발행합니다.
  • DataNode 확장 - DataNode는 실패한 이레이저 코딩 블록의 백그라운드 복구를 위한 추가 ErasureCodingWorker(ECWorker) 태스크를 실행합니다. 실패한 EC 블록은 NameNode가 감지하고, NameNode는 복구 작업을 할 DataNode를 선택합니다. 복구 태스크는 하트비트 응답으로 전달됩니다. 이 과정은 복제 블록이 실패 시 재복제되는 방식과 유사합니다. 재구성(Reconstruction)은 세 가지 핵심 작업을 수행합니다.
    • 소스 노드에서 데이터 읽기: 전용 스레드 풀을 사용해 소스 노드에서 입력 데이터를 병렬로 읽습니다. EC 정책에 따라 모든 소스 대상에 읽기 요청을 스케줄링하고 재구성을 위한 최소 수의 입력 블록만 읽습니다.
    • 데이터 디코딩 및 출력 데이터 생성: 입력 데이터에서 새 데이터와 패리티 블록을 디코딩합니다. 누락된 모든 데이터와 패리티 블록이 함께 디코딩됩니다.
    • 생성된 데이터 블록을 대상 노드로 전송: 디코딩이 끝나면 복구된 블록을 대상 DataNode로 전송합니다.

이레이저 코딩 정책 - 다양한 워크로드를 수용하기 위해 HDFS 클러스터의 파일과 디렉터리가 서로 다른 복제 및 이레이저 코딩 정책을 가질 수 있게 합니다. 이레이저 코딩 정책은 파일을 인코딩/디코딩하는 방법을 캡슐화합니다. 각 정책은 다음 정보로 정의됩니다.

  • EC 스키마: EC 그룹의 데이터 및 패리티 블록 수(예: 6+3)와 코덱 알고리즘(예: Reed-Solomon, XOR)을 포함합니다.
  • 스트라이핑 셀 크기: 스트라이프 읽기/쓰기의 세분성(버퍼 크기와 인코딩 작업 포함)을 결정합니다.

정책은 codec-num data blocks-num parity blocks-cell size라는 이름을 갖습니다. 현재 5개의 내장 정책이 지원됩니다: RS-3-2-1024k, RS-6-3-1024k, RS-10-4-1024k, RS-LEGACY-6-3-1024k, XOR-2-1-1024k.

기본 REPLICATION 스킴도 지원됩니다. 이는 디렉터리에만 설정할 수 있으며, 조상의 이레이저 코딩 정책을 상속하는 대신 디렉터리가 3x 복제 방식을 채택하도록 강제합니다. 이 정책은 3x 복제 방식 디렉터리를 이레이저 코딩 디렉터리와 섞을 수 있게 합니다.

REPLICATION은 항상 활성화되어 있습니다. 모든 EC 정책 중 RS(6,3)가 기본적으로 활성화됩니다.

HDFS 저장 정책과 유사하게 이레이저 코딩 정책은 디렉터리에 설정됩니다. 파일이 생성될 때 가장 가까운 조상 디렉터리의 EC 정책을 상속합니다.

디렉터리 수준 EC 정책은 그 디렉터리에 새로 생성되는 파일만 영향을 줍니다. 파일이 생성된 후에는 이레이저 코딩 정책을 조회할 수 있지만 변경할 수 없습니다. 이레이저 코딩된 파일이 다른 EC 정책의 디렉터리로 이름이 바뀌면 파일은 기존 EC 정책을 유지합니다. 파일을 다른 EC 정책으로 변환하려면 데이터를 다시 써야 하며, 이름 바꾸기보다는 파일을 복사(예: distcp로)하여 수행하세요.

사용자는 XML 파일을 통해 자신의 EC 정책을 정의할 수 있습니다. XML 파일은 다음 세 부분을 가져야 합니다.

  • layoutversion: EC 정책 XML 파일 형식의 버전을 나타냅니다.
  • schemas: 사용자가 정의한 모든 EC 스키마를 포함합니다.
  • policies: 사용자가 정의한 모든 EC 정책을 포함하며, 각 정책은 schema id와 스트라이핑 셀 크기(cellsize)로 구성됩니다.

user_ec_policies.xml.template이라는 샘플 EC 정책 XML 파일이 Hadoop conf 디렉터리에 있으며, 사용자가 참조할 수 있습니다.

Intel ISA-L - Intel ISA-L은 Intel Intelligent Storage Acceleration Library를 뜻합니다. ISA-L은 저장 애플리케이션을 위해 설계된 최적화된 저수준 함수의 오픈소스 컬렉션입니다. Intel AVX 및 AVX2 명령어 집합에 최적화된 빠른 블록 Reed-Solomon 유형 이레이저 코드를 포함합니다. HDFS 이레이저 코딩은 ISA-L을 활용해 인코딩 및 디코딩 계산을 가속화할 수 있습니다. ISA-L은 Linux와 Windows를 포함한 대부분의 주요 운영체제를 지원합니다. ISA-L은 기본적으로 활성화되지 않습니다. ISA-L 활성화 방법은 아래 지침을 참고하세요.

배포 (Deployment)

클러스터 및 하드웨어 구성

이레이저 코딩은 CPU와 네트워크 측면에서 클러스터에 추가 요구를 부과합니다.

  • 인코딩과 디코딩 작업은 HDFS 클라이언트와 DataNode 모두에서 추가 CPU를 소비합니다.
  • 이레이저 코딩은 클러스터에 구성된 EC 스트라이프 폭만큼의 최소 DataNode가 필요합니다. EC 정책 RS(6,3)의 경우 최소 9개 DataNode를 의미합니다.
  • 이레이저 코딩된 파일은 랙 장애 허용을 위해 랙에도 분산됩니다. 즉 스트라이프 파일을 읽고 쓸 때 대부분의 연산이 오프랙(off-rack)입니다. 따라서 네트워크 이등분 대역폭(network bisection bandwidth)이 매우 중요합니다.

랙 장애 허용을 위해 충분한 수의 랙을 갖는 것도 중요합니다. 그래야 평균적으로 각 랙이 EC 패리티 블록 수를 넘지 않는 수의 블록을 보유합니다. 이를 계산하는 공식은 (data blocks + parity blocks) / parity blocks(반올림)입니다. EC 정책 RS(6,3)의 경우 최소 3개 랙((6 + 3) / 3 = 3)을 의미하며, 계획 및 비계획 중단을 처리하려면 이상적으로 9개 이상입니다. 패리티 셀 수보다 적은 랙을 가진 클러스터에서는 HDFS가 랙 장애 허용을 유지할 수 없지만, 노드 수준 장애 허용을 보존하기 위해 스트라이프 파일을 여러 노드에 분산하려고 여전히 시도합니다. 이런 이유로 유사한 수의 DataNode를 가진 랙을 설정하는 것이 권장됩니다.

구성 키 (Configuration keys)

기본적으로 dfs.namenode.ec.system.default.policy에 정의된 것을 제외한 모든 내장 이레이저 코딩 정책은 비활성화되어 있으며, 이것은 기본적으로 활성화됩니다. 클러스터 관리자는 클러스터 크기와 원하는 장애 허용 속성에 따라 hdfs ec [-enablePolicy -policy <policyName>] 명령을 통해 정책 집합을 활성화할 수 있습니다. 예를 들어 9개 랙이 있는 클러스터의 경우 RS-10-4-1024k 같은 정책은 랙 수준 장애 허용을 보존하지 않으며, RS-6-3-1024k 또는 RS-3-2-1024k가 더 적절할 수 있습니다. 관리자가 노드 수준 장애 허용만 신경 쓴다면 클러스터에 최소 14개 DataNode가 있는 한 RS-10-4-1024k도 여전히 적절합니다.

시스템 기본 EC 정책은 dfs.namenode.ec.system.default.policy 구성으로 구성할 수 있습니다. 이 구성으로 -setPolicy 명령에 정책 이름이 인자로 전달되지 않으면 기본 EC 정책이 사용됩니다.

기본적으로 dfs.namenode.ec.system.default.policy는 "RS-6-3-1024k"입니다.

Reed-Solomon과 XOR용 코덱 구현은 다음 클라이언트 및 DataNode 구성 키로 구성할 수 있습니다: 기본 RS 코덱용 io.erasurecode.codec.rs.rawcoders, 레거시 RS 코덱용 io.erasurecode.codec.rs-legacy.rawcoders, XOR 코덱용 io.erasurecode.codec.xor.rawcoders. 사용자는 io.erasurecode.codec.self-defined-codec.rawcoders 같은 구성 키로 자체 정의 코덱도 구성할 수 있습니다. 이 키들의 값은 폴백 메커니즘을 가진 코더 이름 목록입니다. 이 코덱 팩토리들은 코덱이 성공적으로 로드될 때까지 구성 값에 지정된 순서로 로드됩니다. 기본 RS와 XOR 코덱 구성은 순수 Java 구현보다 네이티브 구현을 선호합니다. RS-LEGACY 네이티브 코덱 구현은 없으므로 기본값은 순수 Java 구현뿐입니다. 이 모든 코덱에는 순수 Java 구현이 있습니다. 기본 RS 코덱에는 Intel ISA-L 라이브러리를 활용해 코덱 성능을 향상시키는 네이티브 구현도 있습니다. XOR 코덱에도 Intel ISA-L 라이브러리를 활용해 코덱 성능을 향상시키는 네이티브 구현이 지원됩니다. 자세한 정보는 "Intel ISA-L 활성화" 절을 참고하세요. RS Legacy의 기본 구현은 순수 Java이고, 기본 RS와 XOR의 기본 구현은 Intel ISA-L 라이브러리를 사용하는 네이티브 구현입니다.

DataNode의 이레이저 코딩 백그라운드 복구 작업도 다음 구성 파라미터로 튜닝할 수 있습니다.

  • dfs.datanode.ec.reconstruction.stripedread.timeout.millis - 스트라이프 읽기 타임아웃. 기본값은 5000 ms.
  • dfs.datanode.ec.reconstruction.stripedread.buffer.size - reader 서비스의 버퍼 크기. 기본값은 64KB.
  • dfs.datanode.ec.reconstruction.threads - Datanode가 백그라운드 재구성 작업에 사용하는 스레드 수. 기본값은 8개 스레드.
  • dfs.datanode.ec.reconstruction.xmits.weight - 복제 블록 복구와 비교한 EC 백그라운드 복구 태스크가 사용하는 xmits의 상대 가중치. 기본값은 0.5. 0으로 설정하면 EC 복구 태스크의 가중치 계산을 비활성화합니다. 즉 EC 태스크는 항상 1 xmit를 갖습니다. 이레이저 코딩 복구 태스크의 xmits는 읽기 스트림 수와 쓰기 스트림 수 중 최대값으로 계산됩니다. 예를 들어 EC 복구 태스크가 6개 노드에서 읽고 2개 노드에 써야 하면 xmits는 max(6, 2) * 0.5 = 3입니다. 복제 파일의 복구 태스크는 항상 1 xmit로 계산됩니다. NameNode는 dfs.namenode.replication.max-streams에서, 복제 파일과 EC 파일의 xmits를 합친 DataNode의 총 xmitsInProgress를 뺀 값을 사용해 이 DataNode에 복구 태스크를 스케줄링합니다.

Intel ISA-L 활성화

기본 RS 코덱의 HDFS 네이티브 구현은 Intel ISA-L 라이브러리를 활용해 인코딩 및 디코딩 계산을 향상시킵니다. Intel ISA-L을 활성화하고 사용하려면 세 단계가 있습니다.

  • ISA-L 라이브러리 빌드. 자세한 정보는 공식 사이트 "https://github.com/01org/isa-l/" 을 참고하세요.
  • ISA-L 지원으로 Hadoop 빌드. 소스 코드의 (BUILDING.txt)에 있는 "Build instructions for Hadoop"의 "Intel ISA-L build options" 절을 참고하세요.
  • -Dbundle.isal을 사용해 isal.lib 디렉터리의 내용을 최종 tar 파일로 복사. tar 파일로 Hadoop을 배포. ISA-L이 HDFS 클라이언트와 DataNode에 사용 가능한지 확인.

Hadoop이 ISA-L을 올바르게 감지하는지 확인하려면 hadoop checknative 명령을 실행하세요.

관리 명령 (Administrative commands)

HDFS는 이레이저 코딩과 관련된 관리 명령을 수행하는 ec 서브커맨드를 제공합니다.

hdfs ec [generic options]
     [-setPolicy -path <path> [-policy <policyName>] [-replicate]]
     [-getPolicy -path <path>]
     [-unsetPolicy -path <path>]
     [-listPolicies]
     [-addPolicies -policyFile <file>]
     [-listCodecs]
     [-enablePolicy -policy <policyName>]
     [-disablePolicy -policy <policyName>]
     [-removePolicy -policy <policyName>]
     [-verifyClusterSetup -policy <policyName>...<policyName>]
     [-help [cmd ...]]

각 명령의 상세는 다음과 같습니다.

[ -setPolicy -path [-policy ] [-replicate] ]

지정된 경로의 디렉터리에 이레이저 코딩 정책을 설정합니다.

  • path: HDFS의 디렉터리. 필수 파라미터입니다. 정책 설정은 새로 생성되는 파일에만 영향을 주며 기존 파일에는 영향을 주지 않습니다.
  • policyName: 이 디렉터리 아래 파일에 사용할 이레이저 코딩 정책. dfs.namenode.ec.system.default.policy 구성이 설정되어 있으면 이 파라미터를 생략할 수 있습니다. 경로의 EC 정책이 구성의 기본값으로 설정됩니다.
  • -replicate: 디렉터리에 기본 REPLICATION 방식을 적용해 디렉터리가 3x 복제 방식을 채택하도록 강제합니다.

-replicate와 -policy <policyName>은 선택 인자입니다. 동시에 지정할 수 없습니다.

[ -getPolicy -path ]

지정된 경로의 파일이나 디렉터리의 이레이저 코딩 정책 상세를 얻습니다.

[ -unsetPolicy -path ]

디렉터리에 대한 이전 setPolicy 호출로 설정된 이레이저 코딩 정책을 해제합니다. 디렉터리가 조상 디렉터리에서 이레이저 코딩 정책을 상속하면 unsetPolicy는 no-op입니다. 명시적 정책이 설정되지 않은 디렉터리에서 정책을 해제해도 오류가 반환되지 않습니다.

[ -listPolicies ]

HDFS에 등록된 모든 (활성, 비활성, 제거) 이레이저 코딩 정책을 나열합니다. 활성된 정책만 setPolicy 명령에 사용하기에 적합합니다.

[ -addPolicies -policyFile ]

사용자 정의 이레이저 코딩 정책 목록을 추가합니다. 예시 정책 파일은 etc/hadoop/user_ec_policies.xml.template을 참고하세요. 최대 셀 크기는 속성 dfs.namenode.ec.policies.max.cellsize에 정의되며 기본값은 4MB입니다. 현재 HDFS는 사용자가 총 64개 정책을 추가할 수 있게 하며, 추가된 정책 ID는 64~127 범위입니다. 이미 64개 정책이 추가되어 있으면 정책 추가는 실패합니다.

[ -listCodecs ]

시스템에서 지원되는 이레이저 코딩 코덱과 코더 목록을 얻습니다. 코더는 코덱의 구현입니다. 코덱은 서로 다른 구현을 가질 수 있으므로 서로 다른 코더를 가집니다. 한 코덱의 코더들은 폴백 순서로 나열됩니다.

[ -removePolicy -policy ]

사용자 정의 이레이저 코딩 정책을 제거합니다.

[ -enablePolicy -policy ]

이레이저 코딩 정책을 활성화합니다.

[ -disablePolicy -policy ]

이레이저 코딩 정책을 비활성화합니다.

[ -verifyClusterSetup -policy ... ]

클러스터 설정이 모든 활성 이레이저 코딩 정책을 지원할 수 있는지 확인합니다. 선택 파라미터 -policy가 지정되면 클러스터 설정이 주어진 정책(들)을 지원할 수 있는지 확인합니다.

제한 사항 (Limitations)

상당한 기술적 어려움 때문에 일부 HDFS 연산, 즉 hflush, hsync, concat, setReplication, truncate 및 append는 이레이저 코딩된 파일에서 지원되지 않습니다.

  • 이레이저 코딩된 파일에 대한 append()와 truncate()는 IOException을 던집니다. 그러나 NEW_BLOCK 플래그가 활성화되면 닫힌 스트라이프 파일에 대한 append는 지원됩니다.
  • concat()은 파일이 서로 다른 이레이저 코딩 정책과 혼합되거나 복제 파일과 혼합되면 IOException을 던집니다.
  • setReplication()은 이레이저 코딩된 파일에서 no-op입니다.
  • DFSStripedOutputStream의 hflush()와 hsync()는 no-op입니다. 따라서 이레이저 코딩된 파일에서 hflush()나 hsync()를 호출해도 데이터가 영속적으로 보장되지 않습니다.

클라이언트는 StreamCapabilities API를 사용해 OutputStream이 hflush()와 hsync()를 지원하는지 조회할 수 있습니다. 클라이언트가 hflush()와 hsync()를 통한 데이터 영속성을 원한다면, 현재 해결책은 그러한 파일을 비이레이저코딩 디렉터리에서 일반 3x 복제 파일로 만들거나, FSDataOutputStreamBuilder#replicate() API를 사용해 이레이저 코딩 디렉터리에서 3x 복제 파일을 만드는 것입니다.

더 알아보기 (Learn more)