Hadoop IO
하둡은 데이터 I/O를 위한 프리미티브(Primitive)를 제공한다. 데이터 무결성과 압축 같은 일부 프리미티브는 하둡보다 일반적인 기술이지만 멀티테라바이트의 데이터셋을 처리할 때는 이 프리미티브를 특별히 고려할 만한 가치가 있다. 다른 프리미티브로는 직렬화 프레임워크나 디스크 기반 데이터 구조와 같은 분산 시스템을 개발하기 위한 구성요소를 제공해주는 하둡 도구나 API가 있다.
데이터 무결성
손상된 데이터를 검출하는 일반적인 방법은 데이터가 시스템에 처음 유입되었을 때와 데이터를 손상시킬지도 모르는 신뢰할 수 없는 통신 채널로 데이터가 전송되었을 때마다 체크섬을 계산하는 것이 있다. 만일 새롭게 생성된 체크섬이 원본과 정확히 일치하지 않는다면 그 데이터는 손상된 것으로 간주한다. 이러한 기술은 데이터를 원상 복구하는 방법을 제공하지 않고 단순히 에러 검출만 수행한다. 따라서 저가의 하드웨어를 권장하지 않으며, 특히 ECC 메모리를 사용해야 한다. 주목할 점은 데이터가 아니라 체크섬이 손상될 수도 있다는 것이다. 그러나 체크섬은 데이터보다 훨씬 작기 때문에 손상될 가능성은 매우 낮다.
체크섬 : 중복 검사의 한 형태. 송신된 자료의 무결성을 보호하는 단순한 방법이다. 나열된 데이터를 더하여 체크섬 숫자를 얻고, 정해진 비트수의 모듈라로 정해진 비트수로 재구성 한다.
ECC 메모리 : 오류 정정 코드 메모리(Error correction code memory). 가장 일반적인 종류의 내부 데이토 손상을 감지하고 수정하는 기억 장치의 일종이다. ECC 메모리는 계산과학, 금융 컴퓨팅 등 모든 상황에서 데이터 손상에 대처해야 하는 대부분의 컴퓨터에 사용된다.
일반적으로 에러 검출 코드는 모든 크기의 입력에 대해 32비트 정수 체크섬을 계산하는 CRC-32(32비트 순환 중복 검사 32-bit cyclic redundancy check)를 사용한다. CRC-32는 하둡의 ChdecksumFileSystem에서 체크섬 계산을 하기 위해서도 사용되지만 HDFS에서는 CRC-32C라고 불리는 매우 효율적인 변형을 사용한다.
HDFS의 데이터 무결성
HDFS는 모든 데이터를 쓰는 과정에서 내부적으로 체크섬을 계산하고, 데이터를 읽는 과정에서 체크섬을 기본적으로 검증한다. dfs.bytes-per-checksum에 설정된 크기 만큼의 모든 바이트 데이터에 대해 별도의 체크섬이 생성된다. 기본적으로는 512바이트고, CRC-32C 체크섬이 4바이트의 long 타입이기 때문에 스토리지 오버헤드는 1%도 되지 않는다.
데이터노드는 데이터와 체크섬을 저장하기 전에 수신한 데이터를 검증할 책임이 있다. 이 같은 검증은 클라이언트로부터 수신한 데이터 또는 복제 과정에서 다른 데이터노드로부터 수신한 데이터에 대해 수행된다. 데이터를 쓰는 클라이언트가 데이터노드 파이프라인으로 데이터를 보내면 파이프라인의 마지막 데이터노드는 해당 데이터의 체크섬을 검증한다. 만일 데이터노드가 에러를 검출하면 클라이언트는 IOException의 서브클래스를 예외로 받고 어플리케이션 특성에 맞게 처리한다(예를 들어 재연산을 시도할 수 있다).
클라이언트가 데이터노드로부터 데이터를 읽을 때 클라이언트 역시 데이터노드에 저장된 체크섬과 수신된 데이터로부터 계산된 체크섬을 검증한다. 각 데이터노드는 체크섬 검증 로그를 영구 저장하기 때문에 각각의 블록이 검증되었던 마지막 시간을 알고 있다. 클라이언트가 성공적으로 하나의 블록을 검증하고 데이터노드에 알리면 데이터노드는 체크섬 검증에 대한 로그를 갱신한다. 이러한 통계치의 저장은 오류 디스크 검출에 유용하다.
클라이언트의 읽기 과정에서 블록을 검증하는 것 외에도 각 데이터노드는 저장된 모든 블록을 주기적으로 검증하는 DataBlockScanner를 백그라운드 스레드로 수행한다. 이것은 물리적 저장 매체에서 발생할 수도 있는 ‘비트로트(bit rot)’에 의한 데이터 손실을 피하기 위한 방법이다.
비트로트(bit rot) : 데이터 저장 장치에서 사소한 오류가 누적되어 컴퓨터 데이터가 점진적으로 손상되는 것을 이른다. 이 현상은 데이터 붕괴, 데이터 부패 또는 비트 부패라고도 일컬어진다.
HDFS는 블록의 복제본을 저장하기 때문에 손상되지 않은 새로운 복제본 생성을 위해 정상 복제본 중 하나를 복사하는 방식으로 손상된 블록을 치료할 수 있다. 만일 클라이언트가 블록을 읽는 과정에서 에러를 검출하면 훼손된 블록과 데이터노드에 대한 정보를 네임노드에 보고하고 ChecksumException을 발생시킨다. 네임노드는 그 블록 복제본이 손상되었다고 표시하고 다른 클라이언트에 제공하거나 또 다른 데이터노드로 복사하지 못하도록 한다. 그리고 네임노드는 해당 블록을 다른 데이터노드에 복제되도록 스케줄링해서 그 블록의 복제계수(replication factor)를 원래 수준을 ㅗ복구한다. 이러한 일이 발생하면 손상된 복제본은 삭제된다.
파일을 읽으려고 open() 메서드를 호출하기 전에 FileSystem의 setVerifychecksum() 메서드에 false를 전달해서 체크섬 검증을 비활성화할 수 있다. 쉘에서 -get 또는 -copyToLocal 명령어에 -ignoreCrc 옵션을 사용해도 동일하게 동작한다. 이 기능은 손상된 파일을 조사하려 할 때 이 파일로 무엇을 할 지 결정할 수 있어서 매우 유용하다. 예를 들어 해당 파일을 지우기 전에 그것을 복구할 수 있는지 여부를 파악하고자 할 수 있다.
Hadoop fs -checksum을 이용해서 파일의 체크섬을 확인할 수 있다. 이는 HDFS 안의 두 파일이 동일한 내용인지 확인할 때 유용한다. 예를 들면 distcp가 이러한 일을 수행한다.
LocalFileSystem
하둡 LocalFileSystem 은 클라이언트 측 체크섬을 수행한다. filename이라는 파일을 쓸 때 파일 시스템 클라이언트는 파일과 같은 위치의 디렉터리에 그 파일의 각 청크별 체크섬이 담긴 .filename.crc라는 숨겨진 파을 내부적으로 생성한다. 청크 크기는 기본적으로 512파이트이며 file.bytes-per-checksum 속성으로 변경할 수 있다. 청크 크기는 .crc 파일에 메타데이터로 저장되기 때문에 청크 크기의 설정이 변경되다 하더라도 파일을 다시 정확하게 읽을 수 있다. 파일을 읽을 때 체크섬이 검증되고 에러가 검출되면 LocalFileSystem이 ChecksumException을 발생한다.
체크섬은 일반적으로 파일을 읽고/쓰는 시간에 몇 퍼센트의 오버헤드를 추가하는 정도이므로 전체 계산 성능에 미치는 영향이 미미하다(자바에서는 원시 코드로 구현된다.) 대부분의 애플리케이션에서 이는 데이터 무결성을 위해 납득할 만한 비용이라고 할 수 있다. 그러나 기존 파일시스템이 자체적으로 체크섬을 지원한다면 LocalFileSystem의 체크섬을 비활성화할 수도 있다. 이를 위해 LocalFileSystem 대신 RawLocalFileSystem을 사용하면 된다. 애플리케이션에 전역적으로 체크섬을 비활성화하려면 fs.file.impl 속성을 org.apache.hadoop.fs.RawLocalFileSystem 값을 설정해서 파일 URI 구현을 변경(remap) 하면 된다. 대안으로 RawLocalFileSystem 인스턴스를 직접 생성할 수도 있는데, 이는 다음 에처럼 일부 읽기에 대해서만 체크섬 검증을 비활성화할 때 유용하다.
Configuration conf = ...
FileSystem fs = new RawLoaclFileSystem();
fs.initialize(null, conf);
ChecksumFileSystem
LocalFileSystem이 동작할 때 checksumFileSystem 을 사용하며, 이 클래스는 단순한 FileSystem의 래퍼로 구현되어 있기 때문에 다른 체크섬이 없는 파일시스템에 체크섬 기능을 쉽게 추가할 수 있다. 일반적인 사용법은 다음과 같다.
FileSystem rawFs = ...
FileSystem checksummedFs = new ChecksumFileSystem(rawFs);
내부의 파일시스템은 원신 파일시스템이라 불리며, ChecksumFilesystem의 getRawFileSystem() 메서드를 사용해서 얻을 수 있다.
ChecksumFileSystem 이 파일을 읽을 때 에러를 검출하면 reportChecksumFailure() 메서드를 호출할 것이다. 기본적인 구현에는 아무것도 하지 않는 것으로 되어 있지만 LocalFileSystem은 문제가 되는 파일과 체크섬을 같은 디바이스의 bad_files라는 별도의 디렉터리로 이동시킨다. 관리자는 주기적으로 이러한 훼손된 파일을 체크하고 그에 대해 적절한 처리를 해야 한다.