[Trouble Shooting] YARN log 와 long term application

Chan hae OH·2024년 4월 6일

1. 문제 발단


현재 운영하고 있는 Hadoop cluster 의 YARN 으로 실시간이나 배치 어플리케이션들을 띄우고 있다.

해당 환경에서 운영 중 DataNode 의 log 가 너무 많이 쌓여 disk 가 full 이 나는 경우가 발생했다.



2. 문제 원인 분석


  1. DataNode 의 로그 저장 경로를 처음부터 HDFS 가 사용하는 Disk 로 잡을 수는 없는지?

    가능해 보였지만, HDFS 가 컨트롤 하는 Disk 를 내 임의로 조작하는 것이 과연 맞을지 고민 되므로 다른 방법을 모색한다.

  2. DataNode 의 로컬 디스크에만 로그를 저장할 수 있는지?

    공식 문서 확인 결과 로그를 HDFS 나 기타 Object Storage 도 지원하는 듯 하다.



3. 문제 심층 분석


YARN 에서는 아래와 같이 log를 원격 저장소로 저장할 수 있는 옵션들을 제공한다.

참고 : yarn-default.xml (3.2.1)

  • yarn.nodemanager.log-dirs=(${yarn.log.dir}/userlogs): 컨테이너 로그를 저장할 위치. 애플리케이션의 현지화된 로그 디렉터리는 ${yarn.nodemanager.log-dirs}/application_${appid}에서 찾을 수 있다. 개별 컨테이너의 로그 디렉터리는 이 아래에 container_{$contid}라는 디렉터리에 있다. 각 컨테이너 디렉터리에는 해당 컨테이너에서 생성된 stderr, stdin 및 syslog 파일이 포함된다.

  • yarn.log-aggregation-enable=(true | false): 로그 집계 활성화 여부. 로그 집계는 각 컨테이너의 로그를 수집하고 이러한 로그를 파일 시스템으로 이동한다. HDFS, 애플리케이션이 완료된 후 사용자는 yarn.nodemanager.remote-app-log-diryarn.nodemanager.remote-app-log-dir-suffix 속성을 구성하여 이러한 로그가 이동되는 위치를 결정할 수 있다. 사용자는 애플리케이션 타임라인 서버를 통해 로그에 액세스할 수 있다.

  • yarn.log-aggregation.retain-seconds=(-1): 집계 로그를 삭제하기 전에 보관하는 기간. -1은 비활성화. 이 값을 너무 작게 설정하면 Namenode에 오류를 송신할 수 있다.

  • yarn.log-aggregation.retain-check-interval-seconds=(-1) : 집계된 로그 보존 확인 사이의 대기 시간. 0 또는 음수 값으로 설정되면 값은 집계된 로그 보존 시간의 1/10로 계산된다. 이 값을 너무 작게 설정하면 Namenode에 오류를 송신할 수 있다.

  • yarn.nodemanager.log.retain-seconds=(10800) : 사용자 로그를 보관하는 시간(초)이다. 로그 집계가 비활성화된 경우에만 적용 가능하다.

  • yarn.nodemanager.remote-app-log-dir=(path) : 로그 원격 저장소 경로

  • yarn.nodemanager.remote-app-log-dir-suffix=(userlog) : 로그 원격 저장소 경로에 저장된 디렉터리 명을 작성한다.

  • yarn.nodemanager.log-container-debug-info.enabled=(true) : 컨테이너 시작에 대한 추가 로그를 생성한다. 컨테이너가 시작할 때 어플리케이션의 스크립트 복사본을 생성하고 컨테이너 작업 디렉터리의 내용을 나열한다. 디렉터리 콘텐츠를 나열할 때 우리는 심볼릭 링크를 최대 깊이 5(컨테이너 작업 디렉터리 외부를 가리키는 심볼릭 링크 포함)까지 따르므로 컨테이너 실행 속도가 느려질 수 있다.

먼저 YARN 은 yarn.nodemanager.log-dirs 옵션에 따라 로그를 남긴다. 이 때 로그를 남기는 곳은 nodemanager 가 동작하는 로컬에 해당 로그를 남기게 된다.

그러나 로그가 많이 쌓이게 되면 결국 Disk 의 용량 만큼 쌓이게 될 것이다.

이 때 yarn.log-aggregation.retain-seconds 해당 옵션에 명시된 초 주기로 집계된 로그를 삭제 조치할 수 있다. 하지만 Hadoop 설치 파일이 들어있는 디스크는 그렇게 큰 디스크를 사용하지 않을 뿐 더러, 예상한 로그 삭제 주기를 넘어서 과도한 Adhoc 으로 인한 로그 발생으로 다시 Disk full 을 유발할 수도 있다.

그러면 우리는 이 로그를 다른곳으로 저장할 필요가 생긴다.
그러면 이때 우리는 yarn.nodemanager.remote-app-log-dir 옵션을 활용하여 원격 저장소에 해당 로그를 옮길 수 있도록 지정할 수 있다. 이렇게 되면 동작한 Container 로그는 yarn.nodemanager.log-dirs 경로에 작성되다가 Container 종료 시 yarn.nodemanager.remote-app-log-dir 경로로 옮겨 진다.

이렇게 하면 Batch 작업의 경우 어느정도 장기간 로그를 보관할 수 있는 장치가 마련된다.

하지만 실시간 작업의 경우 어떨까?

실시간 어플리케이션의 경우 종료가 되지 않고 계속해서 동작해야 한다.
위에서 보면 알겠지만 yarn.nodemanager.remote-app-log-dir 경로로 로그가 옮겨지는 순간은 어플리케이션이 종료되었을 때 이다. 이 말은 어플리케이션이 종료되지 않으면 yarn.nodemanager.log-dirs 경로에 계속해서 로그가 작성된다는 소리이다.

실제로 확인해본 결과 Batch 성으로 동작하는 Application 들은 원격 저장소로 선택한 HDFS 경로로 옮겨 졌다. 하지만 Spark Structured Streaming 의 경우 계속해서 로컬 경로에 작성되고 있었으며, 로그 사이즈도 너무 많이 발생하고 있었다.

그렇다면 실시간 어플리케이션의 경우 어떻게 로그를 해결해야할까?

혹시나 해서 동작중인 Spark Structured Streaming 어플리케이션의 로그를 삭제해봤다. 당연하게도 어플리케이션이 뱉어 내는 로그는 동작에 아무런 영향을 미치지 않았다.

그렇다면 YARN 에서 실시간 어플리케이션이 동작하며 발생하는 로그를 별도로 처리하는 것을 개발하는 것이 좋지 않을까 한다.



4. 문제 해결


우선 Linux 에 logrotation 기능을 통해 log 파일이 계속해서 커지지 않도록 하고, 주기를 적용해준다.

/opt/app/hadoop/logs/userlog/*.log {
    daily # 로테이션 주기
    rotate 3 # 로테이션 저장 기간
    compress # GZIP 압축 여부
    missingok # 로그 파일이 없어도 오류가 아님
    notifempty # 비어 있지 않은 경우에만 로그 파일을 로테이션
    create 644 yarn yarn # 생성되는 파일의
}

그러면 파일을 매일매일 분할 되어 백업이 생성된다.

이 후 생성되는 로그 파일 (예. application1.log) 을 매일 배치로 HDFS 나 기타 저장소에 별도 보관할 수 있도록 배치를 작성한다.

하지만 이런 방법은 실시간 로그 분석이 어려울 수도 있으므로, logstash 를 활용하는 것이 더 좋아 보일것으로 보인다. (한 파일의 read 시점을 지정하는 기능이 있는 듯 하다.)



profile
Data Engineer

0개의 댓글