HDFS 메모리 저장소 지원

HDFS 메모리 저장소 지원 (Memory Storage Support)

HDFS가 DataNode가 관리하는 힙 밖(off-heap) 메모리에 쓰는 것을 지원하는 기능을 설명하는 문서예요. 지연 영속(Lazy Persist) 쓰기라고 부르며, 관리자 구성(RAM 디스크 설정), 애플리케이션 사용법을 다룹니다. Apache Hadoop 2.6.0부터 사용 가능하며 HDFS-6581에서 개발되었어요.

출처: 문서

본문

소개 (Introduction)

HDFS는 DataNode가 관리하는 힙 밖 메모리에 쓰기를 지원합니다. DataNode는 메모리 데이터를 디스크로 비동기적으로 플러시해서, 성능에 민감한 IO 경로에서 비싼 디스크 IO와 체크섬 계산을 제거합니다. 그래서 이런 쓰기를 Lazy Persist 쓰기라고 부릅니다. HDFS는 Lazy Persist 쓰기에 대해 최선(best-effort) 영속 보장을 제공해요. 복제본이 디스크에 영속되기 전에 노드가 재시작되면 드물게 데이터 손실이 발생할 수 있습니다. 애플리케이션은 지연시간을 줄이는 대신 일부 내구성 보장을 희생하기 위해 Lazy Persist 쓰기를 선택할 수 있어요.

이 기능은 Apache Hadoop 2.6.0부터 사용 가능하며 Jira HDFS-6581에서 개발됐습니다.

대상 사용 사례는 상대적으로 적은 양의 데이터(사용 가능한 메모리에 따라 몇 GB에서 수십 GB)를 낮은 지연시간으로 쓰면 이점이 있는 애플리케이션입니다. 메모리 저장소는 클러스터 안에서 실행되고 HDFS DataNode와 함께 배치된 애플리케이션을 위한 것이에요. 네트워크 복제로 인한 지연시간 오버헤드가 메모리 쓰기의 이점을 상쇄하는 것을 관찰했습니다.

Lazy Persist 쓰기를 쓰는 애플리케이션은 메모리가 부족하거나 설정되지 않으면 DISK 저장소로 폴백해 계속 동작합니다.

관리자 구성 (Administrator Configuration)

이 절은 클러스터에서 애플리케이션이 이 기능을 사용하기 전에 필요한 관리 단계를 열거합니다.

메모리 복제본에 사용할 RAM 제한 (Limit RAM used for replicas)

먼저 메모리에 저장할 복제본에 전용할 메모리 양을 결정합니다. hdfs-site.xml에서 dfs.datanode.max.locked.memory를 그에 맞게 설정하세요. 이것은 Centralized Cache Management 기능과 같은 설정입니다. DataNode는 Lazy Persist 쓰기와 Centralized Cache Management가 사용하는 메모리 합계가 dfs.datanode.max.locked.memory에 구성된 양을 초과하지 않도록 보장해요.

예: 메모리 내 복제본에 32GB 예약

<property>
  <name>dfs.datanode.max.locked.memory</name>
  <value>34359738368</value>
</property>

이 메모리는 DataNode가 시작 시 할당하지 않습니다.

Unix 계열 시스템에서는 DataNode 사용자의 "locked-in-memory size" ulimit(ulimit -l)도 이 파라미터와 일치하도록 늘려야 합니다(OS Limits 관련 절 참고). 이 값을 설정할 때 DataNode와 애플리케이션 JVM 힙, 운영체제 페이지 캐시 같은 다른 것들을 위한 메모리 공간도 필요하다는 점을 기억하세요. DataNode와 같은 노드에서 YARN Node Manager 프로세스가 실행 중이면 YARN 컨테이너용 메모리도 필요합니다.

DataNode에 RAM 디스크 설정 (Setup RAM Disks on Data Nodes)

각 DataNode에 RAM 디스크를 초기화합니다. RAM 디스크를 선택하면 DataNode 프로세스 재시작 시 데이터 영속성이 더 좋습니다. 다음 설정은 대부분의 Linux 배포판에서 동작해요. 다른 플랫폼에서 RAM 디스크를 사용하는 것은 현재 지원되지 않습니다.

tmpfs 선택 (vs ramfs)

Linux는 두 종류의 RAM 디스크인 tmpfs와 ramfs를 지원합니다. tmpfs의 크기는 Linux 커널에 의해 제한되지만 ramfs는 사용 가능한 모든 시스템 메모리를 채우도록 커집니다. tmpfs는 메모리 압력이 있을 때 내용이 디스크로 스왑될 수 있다는 단점이 있어요. 하지만 많은 성능 민감 배포가 스왑을 비활성화하고 실행되므로 실제로는 문제가 되지 않을 것으로 기대합니다.

HDFS는 현재 tmpfs 파티션 사용을 지원합니다. ramfs 추가 지원은 진행 중입니다(HDFS-8584 참고).

RAM 디스크 마운트 (Mount RAM Disks)

Unix mount 명령으로 RAM 디스크 파티션을 마운트합니다. 예: /mnt/dn-tmpfs/ 아래에 32GB tmpfs 파티션 마운트

sudo mount -t tmpfs -o size=32g tmpfs /mnt/dn-tmpfs/

노드 재시작 시 RAM 디스크가 자동으로 다시 만들어지도록 /etc/fstab에 항목을 만드는 것이 좋습니다. 또 다른 옵션은 대부분 Linux 배포판에서 기본적으로 사용 가능한 tmpfs 마운트인 /dev/shm 아래 하위 디렉터리를 사용하는 것입니다. 마운트 크기가 dfs.datanode.max.locked.memory 설정보다 크거나 같은지 확인하고, 아니면 /etc/fstab에서 덮어쓰세요. Lazy Persist 쓰기용으로 DataNode당 tmpfs 파티션을 두 개 이상 사용하는 것은 권장되지 않아요.

tmpfs 볼륨에 RAM_DISK 저장소 유형 태그

hdfs-site.xml의 dfs.datanode.data.dir 구성 설정으로 tmpfs 디렉터리에 RAM_DISK 저장소 유형을 태그합니다. 예: 하드 디스크 볼륨 3개(/grid/0, /grid/1, /grid/2)와 tmpfs 마운트 /mnt/dn-tmpfs가 있는 DataNode에서 dfs.datanode.data.dir은 다음과 같이 설정해야 해요.

<property>
  <name>dfs.datanode.data.dir</name>
  <value>/grid/0,/grid/1,/grid/2,[RAM_DISK]/mnt/dn-tmpfs</value>
</property>

이 단계는 매우 중요합니다. RAM_DISK 태그가 없으면 HDFS는 tmpfs 볼륨을 비휘발성 저장소로 취급하고 데이터가 영속 저장소에 저장되지 않아요. 노드 재시작 시 데이터를 잃게 됩니다.

저장소 정책 활성화 확인

Storage Policies를 켜는 전역 설정이 활성화되어 있는지 확인합니다(여기 문서화된 대로). 이 설정은 기본적으로 켜져 있어요.

애플리케이션 사용법 (Application Usage)

LAZY_PERSIST 저장소 정책 사용

애플리케이션은 LAZY_PERSIST 저장소 정책으로 HDFS가 파일에 Lazy Persist 쓰기를 사용할 수 있음을 나타냅니다. 정책 설정에는 관리 권한이 필요하지 않으며, 세 가지 방법 중 하나로 설정할 수 있어요.

디렉터리에 hdfs storagepolicies 명령 호출

디렉터리에 정책을 설정하면 그 디렉터리의 모든 새 파일에 적용됩니다. Storage Policies 문서에 설명된 대로 hdfs storagepolicies 명령으로 정책을 설정할 수 있어요.

hdfs storagepolicies -setStoragePolicy -path <path> -policy LAZY_PERSIST
디렉터리에 setStoragePolicy 메서드 호출

Apache Hadoop 2.8.0부터 애플리케이션은 FileSystem.setStoragePolicy로 저장소 정책을 프로그래밍 방식으로 설정할 수 있습니다. 예:

fs.setStoragePolicy(path, "LAZY_PERSIST");
새 파일에 LAZY_PERSIST CreateFlag 전달

애플리케이션은 FileSystem#create API로 새 파일을 만들 때 CreateFlag#LAZY_PERSIST를 전달할 수 있어요. 예:

FSDataOutputStream fos =
    fs.create(
        path,
        FsPermission.getFileDefault(),
        EnumSet.of(CreateFlag.CREATE, CreateFlag.LAZY_PERSIST),
        bufferLength,
        replicationFactor,
        blockSize,
        null);

더 알아보기 (Learn more)