멀티테넌트 하둡 클러스터
운영 경험기
Name : 이유비
Team: Search System
목차
0. C3(Common Central Cluster)
1. HDFS 의 파일 개수를 줄여 네임노드의 부담 덜어주기
2. 곳곳에 도사리는 클러스터 장애를 피하는 비책
3. 클러스터 중단 없는 OS 업그레이드
들어가기 전에…
데이터 저장 리소스 관리
(cpu, mem, gpu)
네임노드 리소스매니저
데이터노드 노드매니저
Master
Slave
NN
DN
RM
NM
용어정리
애플리케이션 마스터 AM
0.
C3(Common Central Cluster)
0.1 C3가 지원하는 프레임워크
0.2 C3가 사용하는 하둡 패키지
- 패치 적용은 이슈 번호로
- 자체 수정은 네이버 github으로
- https://github.com/naver/hadoop
Hadoop 2.7.1
1.
HDFS 의 파일 개수를 줄여
네임노드의 부담 덜어주기
1.1 네임노드
네임노드에는 모든 파일의 메타 정보를 메모리에 유지하고 있습니다.
네임노드의 힙사이즈에 따라 전체 파일 개수/블럭 개수가 제한됩니다.
네임노드의 한계
파일개수
시간
한계치
Out Of Memory !
클러스터 중단!
1시간 내에는 복구되어야 해요!
방탄소년단 컴백한단 말이에요!
https://community.hortonworks.com/questions/40795/namenode-heapsize.html
https://www.cloudera.com/documentation/enterprise/5-8-x/topics/admin_nn_memory_config.html
1.1 네임노드
파일/블럭 개수가 한계치에 도달했다면…!
메모리 늘리면 되지!
=> 48GB -> 128GB
=> long stop-the-world*
*http://d2.naver.com/helloworld/1329
1.1 네임노드
파일/블럭 개수가 한계치에 도달했다면…!
다른 방법은…?
1. Hadoop archive
2. 오랫동안 사용하지 않는 파일 삭제
3. HIVE merge
4. HDFS federation
1.2 오랫동안 사용하지 않는 파일 삭제
HDFS 에서 access time 을 사용하려면?
Not “modification time” but “access time”
Þ hdfs-site.xml, dfs.namenode.accesstime.precision
예) dfs.namenode.accesstime.precision=3600000, 1시간(3600초)
access time
09:00
09:00
access
09:1009:2009:30
10:00
10:00
1.2 오랫동안 사용하지 않는 파일 삭제
HdfsFindTool
$ hadoop jar /opt/cloudera/parcels/CDH-*/jars/search-mr-*-job.jar
org.apache.solr.hadoop.HdfsFindTool -find /some/path -atime 1
// n: 24시간, 하루
-atime n // n 일 전 접근한 파일
-atime -n // n 일 이내에 접근한 파일
-atime +n // n 일 이내에 접근하지 않은 파일
https://github.com/cloudera/search
https://www.cloudera.com/documentation/enterprise/5-3-x/topics/search_hdfsfindtool.html
1.2 오랫동안 사용하지 않는 파일 삭제
HdfsFindTool
아쉬운 점
1. 파일명만 나온다.
2. 네임노드에 rpc 부하를 준다.
1.2 오랫동안 사용하지 않는 파일 삭제
- fsImage 를 분석!
$ hdfs oiv -i <fsImage> -o <outputFile> -t <tempFile> -p Delimited
// “Delimited” processor 를 쓰면, 파일 경로, access time 이 모두 보입니다.
// INodeReference error -> HDFS-9721** 적용
OIV(Offline Image Viewer)*
* https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html
** https://issues.apache.org/jira/browse/HDFS-9721
1.3 HIVE merge
자잘한 파일이 너무 많아!
hive 관련 파일수가 2500만개(!)
1.3 HIVE merge
자잘한 파일을 하나로!
합치고 줄이자!
hive.merge.mapredfiles=true (default: false)
hive.merge.mapfiles=true (default: true)
hive.merge.size.per.task=256000000 (default: 256000000)
hive.merge.smallfiles.avgsize=200000000 (default: 16000000)
1.3 HIVE merge
합치고 줄이자!
Þ 중간파일 압축!
Þ 결과파일 압축!
hive.exec.compress.intermediate=true
hive.intermediate.compression.codec=org.apache.hadoop.io.compress.GzipCodec
hive.intermediate.compression.type=BLOCK
hive.exec.compress.output=true
mapreduce.output.fileoutputformat.compress=true
mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec
mapreduce.output.fileoutputformat.compress.type=BLOCK;
1.3 HIVE merge
그 결과는?
그렇게 많이 줄지 않았는데? 약 80만 개
기존 데이터는 왜 줄었나? 기존 데이터도 접근 시, merge 적용
2450만
2350만
1.4 HDFS federation
네임노드 여러 개 두면 되지!
https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/Federation.html
1.4 HDFS federation
HA 일 때, 유의사항
*https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html
dfs.namenode.shared.edits.dir.c3=qjournal://node1:8485;node2:8485;node3:8485/c3
dfs.namenode.shared.edits.dir.c3v=qjournal://node1:8485;node2:8485;node3:8485/c3v
dfs.namenode.shared.edits.dir=qjournal://node1:8485;node2:8485;node3:8485/mycluster
1.4 HDFS federation
파일을 많이 생성하는 컴포넌트의 이전
- YARN Log
당시에 20~30%
현재는 약 19% 를 차지
81%
19%
HDFS 파일 개수
그 외
YARN log
1.5 파일을 많이 생성하는 컴포넌트 이전
다른 namespace 간 파일 이동
c3 c3v
$ hadoop fs -mv
$ hadoop distcp
1.5 파일을 많이 생성하는 컴포넌트 이전
YARN Log 이전
1. 로그 경로 변경 (YARN-3269*)
- yarn.nodemanager.remote-app-log-dir(yarn-site.xml)
- fs.defaultFS(core-site.xml)
old logs
(c3)
new logs
(c3v)
$ yarn logs ­applicationId {application ID}
2. 양쪽 로그를 조회하도록 코드 수정
* https://issues.apache.org/jira/browse/YARN-3269
요약
1. NN 힙사이즈 늘리기
2. 파일 개수 줄이기
- Hadoop archive, 오래된 파일 제거, HIVE merge
3. HDFS federation
커다란 컴포넌트 옮겨보기(YARN log)
파일 개수는 줄이고, NN 는 늘리고.
2.
곳곳에 도사리는
클러스터 장애를 피하는 비책
RM
NM NM NM~
NN
DN DN DN~
RS RS RS~
NN RM
HM HM
HM : HBase master
RS : Regionserver
NN : Namenode
DN : Datanode
RM : Resourcemanager
NM : Nodemanager
2.1 Namenode가 죽었다.
- Hadoop-2.7.2, 2.6.3 미만
- HDFS HA 구성하고, zkfc 로 auto failover 를 사용하는 경우
- 다수의 데이터노드 재시작 시
발생환경
2.1 Namenode가 죽었다.
단일 장애점(SPOF*), 클러스터 중단 가능성
=> 높은 가용성(HA**)으로 해결
Namenode 가 죽으면..?
• https://ko.wikipedia.org/wiki/단일_장애점
** https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html
2.1 Namenode가 죽었다.
NN 정상작동이지만, 불필요한 NN failover
Þ 사용자의 작업 지연 가능성
Þ 운영자에게 짜증나는 알림
우리의 경우는..
2.1 Namenode가 죽었다.
ZKFC(zookeeper failover controller)
NN1(Active ) NN2(Standby)
ZKFC
Health
Monitor
ASE
ZKFC
Health
Monitor
ASE
상태확인
Zk lock
NN1 의
breadcrumb
lock 을 놓음
lock 을 잡음
breadcrumb 가 자신의 것인지 확인
cf. ASE: ActiveStandbyElector
45초 동안 응답 없음
자신의 것이 아님을 인지,
다른 NN 을 죽인다.
(split-brain 방지)Lock 을 잡고 있음
SERVICE_NOT_RESPONDINGquitElection
ha.health-monitor.rpc-timeout.ms=45000
2.1 Namenode가 죽었다.
누가 그랬나? 데이터 노드 한꺼번에 재시작한 사람 == 나
NN1(Active )
ZKFC
Health
Monitor
ASE
상태확인
DN1 DN{N}
블럭 리포팅 처리
-> 대량의 “INFO” 로그 출력
~
다수 재시작RPC port
?
“Failover”
같은 RPC port 를 사용, 응답시간 초과
블럭 리포팅 처리 중,
namespace lock
-> 로그 출력에도 처리시간 지연
2.1 Namenode가 죽었다.
- 네임노드의 INFO 로그를 TRACE 로그로 변경(HDFS-9434*)
- LOG.info() => LOG.trace()
해결 방법
* https://issues.apache.org/jira/browse/HDFS-9434
2.1 Namenode가 죽었다.
더 좋은 해결 방법
- 네임노드에 zkfc 용 rpc port 를 따로 둔다.(HDFS-9311*)
NN
ZKFC
Health
Monitor ASE
DN1 DN{N}~
* https://issues.apache.org/jira/browse/HDFS-9311
RM
NM NM NM~
NN
DN DN DN~
RS RS RS~
NN RM
HM HM
HM : HBase master
RS : Regionserver
NN : Namenode
DN : Datanode
RM : Resourcemanager
NM : Nodemanager
2.2 Nodemanager 들이 다(!) 죽었다.
- standby RM 장비 변경 후, failover 가 진행될 때
- 변경 전 standby RM의 ip 를 NM 들이 캐싱하고 있었을 때
발생환경
2.2 Nodemanager 들이 다(!) 죽었다.
NN 과 RM 이 같은 장비에 있네?
RM 을 이전하자! 무중단으로!
Þ NM 이 전부(!) 죽어버렸다…
누가 그랬나? RM 이전한 사람 == 나
RM 이전 작업 시나리오
2.2 Nodemanager 들이 다(!) 죽었다.
Active RM Standby RM
1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4IP
DNS rm1 rm2
Active RMStandby RM
FINISH!
RM failover
문제 발생
2.2 Nodemanager 들이 다(!) 죽었다.
Active RM
1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4IP
DNS rm1 rm2
Active RM
NM NM NM
???
RM ­ AM: yarn.am.liveness-monitor.expiry-interval-ms
RM ­ NM: yarn.nm.liveness-monitor.expiry-interval-ms
NM 재시작
expired!
문제 원인
1. c3 는 운영 상의 이유(설정 변경)로 RM failover 가 여러 차례 발생했었다.
2. NM 에서 rm1, rm2 두 개의 IP 가 캐싱되고 있었다.
3. rm2 ip 를 변경한 후, NM 에서 변경을 인지했지만(로그에 출력됨),
새로운 ip 에 접속은 하지 않았다.(HDFS-11153*)
4. NM, AM 재시작으로 상황 해결
2.2 Nodemanager 들이 다(!) 죽었다.
* https://issues.apache.org/jira/browse/HDFS-11153
성공적인 RM 이전을 위한 시나리오
2.2 Nodemanager 들이 다(!) 죽었다.
Active RM
1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4IP
DNS rm1 rm2
NM NM NM NM 롤링 재시작
RM의 호스트명을
도메인네임으로 변경
Standby RM
Standby RM 을 이전
Standby RM 이전 전에 시작한 작업이
완료될 때까지 대기
Active RMStandby RM
Standby RM 이전
RM failover
FINISH!
RM
NM NM NM~
NN
DN DN DN~
RS RS RS~
NN RM
HM HM
HM : HBase master
RS : Regionserver
NN : Namenode
DN : Datanode
RM : Resourcemanager
NM : Nodemanager
2.3 Resourcemanager가 failover 중 죽었다.
- RM Restart feature* 를 사용
- application 정보를 zookeeper 에 저장하는 설정 사용
- RM 재시작 혹은 failover 시 발생
발생하는 환경
* https://hadoop.apache.org/docs/r2.7.1/hadoop-yarn/hadoop-yarn-site/ResourceManagerRestart.html
AM, NM 이 일정시간이 초과되면 모두 죽는다.
RM 이 죽으면..?
RM ­ AM: yarn.am.liveness-monitor.expiry-interval-ms
RM ­ NM: yarn.nm.liveness-monitor.expiry-interval-ms
2.3 Resourcemanager가 failover 중 죽었다.
문제 원인
2.3 Resourcemanager가 failover 중 죽었다.
하나의 znode 에 데이터가 너무 많다.
jute.maxbuffer 설정 값보다 크면 데이터 읽기 실패
=> failover 실패
1. 완료된 application 정보는 저장하지 않기 (yarn-site.xml)
yarn.resourcemanager.state-store.max-completed-applications=0(YARN-4464*)
해결방법
2.3 Resourcemanager가 failover 중 죽었다.
2. zookeeper 설정 변경(jute.maxbuffer)
export YARN_RESOURCEMANAGER_OPTS=-Djute.maxbuffer=10485760 (4mb ->10mb)
* https://issues.apache.org/jira/browse/YARN-4464
일정 주기로 znode 가 저장되는 곳을 -Djute.maxbuffer=10485760 설정으로 읽어 봅니다.
Þ 문제가 발생하면,
Þ Standby RM 설정을 변경시키고 재시작
Þ Active RM 은 설정만 변경
10MB 보다 커지면…?
2.3 Resourcemanager가 failover 중 죽었다.
znode 를 몰아넣지 말고, 계층구조를 두면 됩니다.
근본적인 해결책(YARN-2962*)
2.3 Resourcemanager가 failover 중 죽었다.
* https://issues.apache.org/jira/browse/YARN-2962
RM
NM NM NM~
NN
DN DN DN~
RS RS RS~
NN RM
HM HM
HM : HBase master
RS : Regionserver
NN : Namenode
DN : Datanode
RM : Resourcemanager
NM : Nodemanager
2.4 HBase regionserver 가 대량 죽었다.
- hbase.client.keyvalue.maxsize=0 설정 사용(크기 제한 x)
- 한 셀에 엄청 큰 데이터가 입력 됨
발생환경
2.4 HBase regionserver 가 대량 죽었다.
HBase master 가 region 을 다른 regionserver 에 재할당 한다.
Þ 보통은 문제 없다. 다시 살리면 된다.
Þ 계속 죽는 것이 문제.
HBase regionserver 가 죽으면..?
2.4 HBase regionserver 가 대량 죽었다.
1. 한 셀에 엄청 큰 데이터가 입력됨
누가 그랬나? 비정상적으로 큰 하나의 셀
2. 해당 셀을 처리할 때, 셀을 가지고 있는 HBase regionserver 에서 OOM 발생하여 죽음
3. 해당 region 을 다른 regionserver 에서 서빙
4. 그 regionserver 도 OOM 으로 죽음
5. 2~4 이 계속 반복되면서 전체 regionserver 가 죽음
2.4 HBase regionserver 가 대량 죽었다.
hbase.client.keyvalue.maxsize
위 설정이 클라이언트 설정이다보니, 클라이언트가 임의로 변경할 경우, 또 발생할 수 있다.
예방
클러스터 전체가 죽는 상황을 막기 위해
1. 주기적으로 죽어 있는 regionserver 시작
2. Regionserver 가 주기적으로 죽는 문제가 발생하면, 해당 테이블을 빨리 찾아서 disable
=> disable 후, region 이 offline 상태로 되므로, 해당 테이블을 참조하는 작업은 계속 실패
=> regionserver 에는 더 이상 OOM 이 발생하진 않는다.
요약
- 하둡 커뮤니티 이슈
- e.g. YARN, HDFS, HBASE
이슈의 지속적인 확인
테스트 클러스터 활용
https://issues.apache.org/jira/projects/YARN/issues
https://issues.apache.org/jira/projects/HDFS/issues
https://issues.apache.org/jira/projects/HBASE/issues
3.
클러스터 중단 없는 OS 업그레이드
3.1 centos6 -> centos7 ! Why?
1. Docker
왜 굳이?
- centos6 에 대한 docker 지원은 1.7.1 버전까지*
- ”—live-restore” 옵션은 1.12 버전부터
2. Tensorflow cpu 버전을 centos6 에서 구축하기란 매우 매우 힘들다.
3. 그 밖의 딥러닝 최신 패키지 제공을 위해서 …
* https://github.com/moby/moby/issues/14365
3.2 클러스터 무중단, Why?
전사 공통
C3는..
서비스 + 개발
개발자 400명 이상
à 중단하기 어려움
3.2 클러스터 무중단, How?
다른 OS 가 같이 있으면?
- YARN container 환경
- OS 에 의존하는 작업?
- YARN resource localization
고려할 점
일부 장비를 빼더라도 괜찮을까?
- 클러스터 가용성
3.3 OS 에 의존하는 작업?
어떻게 문제를 알아낼 것인가?
사용자의 작업을 전수 조사
- 사용자 개입 X
- 작업 추출, 테스트 클러스터에 돌려보기
3.3 OS 에 의존하는 작업?
작업 종류 호환성
Pure Java app. O
Native library X
Shell script Δ
Native library ? => distributed cache 조사
Shell script ? => hadoop streaming job 조사
어떤 작업이 문제가 있는가?
3.3 OS 에 의존하는 작업?
Native library 를 사용하는 작업
lib1.c lib2.c lib3.c
SWIG
PerlJS ???Python
3.3 OS 에 의존하는 작업?
Shell script 를 사용할 경우
- Awk (3.1.7v à 4.0.2v)
centos7centos6
3.4 YARN resource localization
OS 별 리소스 배포?
- YARN 에서는 리소스가 어떻게 배포될까?
3.4 YARN resource localization
YARN 에서 작업이 수행되는 과정*
YARN
client
HDFS
* https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources
Resource
Manager
1. 리소스(파일)를
HDFS 에 업로드
NM1 NM2 NM3
- 다음 내용은 사용자가 작업을 제출한 뒤의 내부 동작입니다.
3.4 YARN resource localization
YARN
client
HDFS
Resource
Manager
2. Application 제출
NM1 NM2 NM3
YARN 에서 작업이 수행되는 과정*
* https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources
3.4 YARN resource localization
YARN
client
HDFS
Resource
Manager
NM1 NM2 NM3
3. 컨테이너 스케쥴링(할당)
Container1 Container2 Container3
YARN 에서 작업이 수행되는 과정*
* https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources
YARN
client
HDFS
Resource
Manager
4. 리소스(파일)을 HDFS 에서
로컬로 다운로드
NM1 NM2 NM3
Container1 Container2 Container3
3.4 YARN resource localization
Resource
localization
YARN 에서 작업이 수행되는 과정*
* https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources
다른 OS 가 섞여 있을 때 문제점
3.4 YARN resource localization
HDFS
NM1 NM2 NM3
Container1 Container2 Container3
centos6 centos7 centos6
?
for 6
각 OS 에 맞는 리소스를 배포하기
3.4 YARN resource localization
HDFS
NM1 NM2 NM3
Container1 Container2 Container3
centos6 centos7 centos6
for 6 for 7
1. 하둡 패키지 코드 수정*
2. NM 재시작
3. 작업 제출 시 설정
mapreduce.job.cache.files=/file/_native_centos6_foo.bar,/file/_native_centos7_foo.bar
각 OS 에 맞는 리소스를 배포하기
3.4 YARN resource localization
* https://github.com/naver/hadoop/commit/6f18dc0af537cef734b6d4d064573341ca9fc870
예)
mysql-devel 설치 시,
- centos6: mysql, mysql-devel
- centos7: mysql-devel
1. yum package 의 dependency 가 다른 경우
3.5 OS 별 추가 고려사항
Hadoop 프로젝트에서의 Parameter substitution (e.g. $PATH)
à heterogenous cluster 라면 특히 유의
2. PATH 환경변수는 동일하게 맞추자.
3.5 OS 별 추가 고려사항
* http://www.tldp.org/LDP/abs/html/parameter-substitution.html
3.5 OS 별 추가 고려사항
2. PATH 환경변수는 동일하게 맞추자.
사례)
AM 은 centos7에 할당되고, map 작업은 centos6 에 할당될 경우,
PATH 문제로 ln 명령을 찾지 못하고, 컨테이너 실행 실패.
3.5 OS 별 추가 고려사항
2. PATH 환경변수는 동일하게 맞추자.
Why?
- centos7 PATH 에는 /bin 이 없다.
- /bin -> /usr/bin
- AM 에서 환경변수 치환 (mapred.child.env=PATH=.:$PATH), ln 명령에 문제 발생
- centos6: /bin/ln
- centos7: /usr/bin/ln
3.5 OS 별 추가 고려사항
2. PATH 환경변수는 동일하게 맞추자.
cf. AM: Application Master
AM container
mapred.child.env=PATH=.:$PATH
centos7
PATH=/usr/bin
centos6
PATH=/bin:/usr/bin
centos6
PATH=/usr/bin
centos6 에서는
/usr/bin/ln 이 없다!
이제 OS 에 따라 다른 리소스 배포 가능
환경 일치
=> centos7 장비 추가 가능
=> centos6 장비를 빼내고 업그레이드 진행 후 다시 장비 투입
centos6 + centos7
3.6 Nodemanager 디커미션
3.6 Nodemanager 디커미션
장비를 빼기 전, NM부터 제거해야..
NM
Container
NM
Container
대기
디커미션
graceful
디커미션
https://hadoop.apache.org/docs/r3.0.0-alpha4/hadoop-yarn/hadoop-yarn-site/GracefulDecommission.html
컨테이너 종료
Container
새 컨테이너 할당 금지
3.6 Nodemanager 디커미션
장비를 빼기 전, NM부터 제거해야..
하둡 버전 디커미션 graceful 디커미션
2.7.1 O X
3.0.0-alpha4↑ O O
리소스 한도를 확 줄여서 더 이상 새로운 작업이 할당되지 않도록 하자!
다른 방법은 없나…?
3.6 Nodemanager 디커미션
1. RM의 minimum-allocation 설정을 충분히 작게
3.6 Nodemanager 디커미션
cf. Hadoop 2.7.1 mapred-default.xml 에서 기본값*
Property 값
mapreduce.map.memory.mb 1024
mapreduce.reduce.memory.mb 1024
mapreduce.map.cpu.vcores 1
mapreduce.reduce.cpu.vcores 1
* https://hadoop.apache.org/docs/r2.7.1/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml
2. 리소스 설정 최소화하기
3.6 Nodemanager 디커미션
3. NM Restart 기능* 활성화
* https://hadoop.apache.org/docs/r2.7.1/hadoop-yarn/hadoop-yarn-site/NodeManagerRestart.html
Property 값
yarn.nodemanager.recovery.enabled true
yarn.nodemanager.recovery.dir /some/path
yarn.nodemanager.address 0 (Ephemeral port) 이외의 포트번호
3.6 Nodemanager 디커미션
4. NM 재시작
3.6 Nodemanager 디커미션
5. 해당 노드에서 수행 중인 작업이 완료되면 NM을 죽입니다.
3.6 Nodemanager 디커미션
3.7 중단 없는 OS 업그레이드
centos6 centos7centos7
클러스터에
장비 추가
하둡 컴포넌트
제거
업그레이드!
NM, … DN NM, … DN
하둡 컴포넌트
설치
클러스터에
장비 추가
클러스터에서
장비 제거
하둡 컴포넌트
설치
끝
요약
YARN container 환경 통일
작업에 영향이 없도록 장비 제거 후, 업그레이드 진행
문제 가능성이 있는 작업은 사전에 대비
Thank you!
yubi.lee@navercorp.com

[234]멀티테넌트 하둡 클러스터 운영 경험기

  • 1.
    멀티테넌트 하둡 클러스터 운영경험기 Name : 이유비 Team: Search System
  • 2.
    목차 0. C3(Common CentralCluster) 1. HDFS 의 파일 개수를 줄여 네임노드의 부담 덜어주기 2. 곳곳에 도사리는 클러스터 장애를 피하는 비책 3. 클러스터 중단 없는 OS 업그레이드
  • 3.
    들어가기 전에… 데이터 저장리소스 관리 (cpu, mem, gpu) 네임노드 리소스매니저 데이터노드 노드매니저 Master Slave NN DN RM NM 용어정리 애플리케이션 마스터 AM
  • 4.
  • 5.
    0.1 C3가 지원하는프레임워크
  • 6.
    0.2 C3가 사용하는하둡 패키지 - 패치 적용은 이슈 번호로 - 자체 수정은 네이버 github으로 - https://github.com/naver/hadoop Hadoop 2.7.1
  • 7.
    1. HDFS 의 파일개수를 줄여 네임노드의 부담 덜어주기
  • 8.
    1.1 네임노드 네임노드에는 모든파일의 메타 정보를 메모리에 유지하고 있습니다. 네임노드의 힙사이즈에 따라 전체 파일 개수/블럭 개수가 제한됩니다. 네임노드의 한계 파일개수 시간 한계치 Out Of Memory ! 클러스터 중단! 1시간 내에는 복구되어야 해요! 방탄소년단 컴백한단 말이에요! https://community.hortonworks.com/questions/40795/namenode-heapsize.html https://www.cloudera.com/documentation/enterprise/5-8-x/topics/admin_nn_memory_config.html
  • 9.
    1.1 네임노드 파일/블럭 개수가한계치에 도달했다면…! 메모리 늘리면 되지! => 48GB -> 128GB => long stop-the-world* *http://d2.naver.com/helloworld/1329
  • 10.
    1.1 네임노드 파일/블럭 개수가한계치에 도달했다면…! 다른 방법은…? 1. Hadoop archive 2. 오랫동안 사용하지 않는 파일 삭제 3. HIVE merge 4. HDFS federation
  • 11.
    1.2 오랫동안 사용하지않는 파일 삭제 HDFS 에서 access time 을 사용하려면? Not “modification time” but “access time” Þ hdfs-site.xml, dfs.namenode.accesstime.precision 예) dfs.namenode.accesstime.precision=3600000, 1시간(3600초) access time 09:00 09:00 access 09:1009:2009:30 10:00 10:00
  • 12.
    1.2 오랫동안 사용하지않는 파일 삭제 HdfsFindTool $ hadoop jar /opt/cloudera/parcels/CDH-*/jars/search-mr-*-job.jar org.apache.solr.hadoop.HdfsFindTool -find /some/path -atime 1 // n: 24시간, 하루 -atime n // n 일 전 접근한 파일 -atime -n // n 일 이내에 접근한 파일 -atime +n // n 일 이내에 접근하지 않은 파일 https://github.com/cloudera/search https://www.cloudera.com/documentation/enterprise/5-3-x/topics/search_hdfsfindtool.html
  • 13.
    1.2 오랫동안 사용하지않는 파일 삭제 HdfsFindTool 아쉬운 점 1. 파일명만 나온다. 2. 네임노드에 rpc 부하를 준다.
  • 14.
    1.2 오랫동안 사용하지않는 파일 삭제 - fsImage 를 분석! $ hdfs oiv -i <fsImage> -o <outputFile> -t <tempFile> -p Delimited // “Delimited” processor 를 쓰면, 파일 경로, access time 이 모두 보입니다. // INodeReference error -> HDFS-9721** 적용 OIV(Offline Image Viewer)* * https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/HdfsImageViewer.html ** https://issues.apache.org/jira/browse/HDFS-9721
  • 15.
    1.3 HIVE merge 자잘한파일이 너무 많아! hive 관련 파일수가 2500만개(!)
  • 16.
    1.3 HIVE merge 자잘한파일을 하나로! 합치고 줄이자! hive.merge.mapredfiles=true (default: false) hive.merge.mapfiles=true (default: true) hive.merge.size.per.task=256000000 (default: 256000000) hive.merge.smallfiles.avgsize=200000000 (default: 16000000)
  • 17.
    1.3 HIVE merge 합치고줄이자! Þ 중간파일 압축! Þ 결과파일 압축! hive.exec.compress.intermediate=true hive.intermediate.compression.codec=org.apache.hadoop.io.compress.GzipCodec hive.intermediate.compression.type=BLOCK hive.exec.compress.output=true mapreduce.output.fileoutputformat.compress=true mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.GzipCodec mapreduce.output.fileoutputformat.compress.type=BLOCK;
  • 18.
    1.3 HIVE merge 그결과는? 그렇게 많이 줄지 않았는데? 약 80만 개 기존 데이터는 왜 줄었나? 기존 데이터도 접근 시, merge 적용 2450만 2350만
  • 19.
    1.4 HDFS federation 네임노드여러 개 두면 되지! https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/Federation.html
  • 20.
    1.4 HDFS federation HA일 때, 유의사항 *https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html dfs.namenode.shared.edits.dir.c3=qjournal://node1:8485;node2:8485;node3:8485/c3 dfs.namenode.shared.edits.dir.c3v=qjournal://node1:8485;node2:8485;node3:8485/c3v dfs.namenode.shared.edits.dir=qjournal://node1:8485;node2:8485;node3:8485/mycluster
  • 21.
    1.4 HDFS federation 파일을많이 생성하는 컴포넌트의 이전 - YARN Log 당시에 20~30% 현재는 약 19% 를 차지 81% 19% HDFS 파일 개수 그 외 YARN log
  • 22.
    1.5 파일을 많이생성하는 컴포넌트 이전 다른 namespace 간 파일 이동 c3 c3v $ hadoop fs -mv $ hadoop distcp
  • 23.
    1.5 파일을 많이생성하는 컴포넌트 이전 YARN Log 이전 1. 로그 경로 변경 (YARN-3269*) - yarn.nodemanager.remote-app-log-dir(yarn-site.xml) - fs.defaultFS(core-site.xml) old logs (c3) new logs (c3v) $ yarn logs ­applicationId {application ID} 2. 양쪽 로그를 조회하도록 코드 수정 * https://issues.apache.org/jira/browse/YARN-3269
  • 24.
    요약 1. NN 힙사이즈늘리기 2. 파일 개수 줄이기 - Hadoop archive, 오래된 파일 제거, HIVE merge 3. HDFS federation 커다란 컴포넌트 옮겨보기(YARN log) 파일 개수는 줄이고, NN 는 늘리고.
  • 25.
  • 26.
    RM NM NM NM~ NN DNDN DN~ RS RS RS~ NN RM HM HM HM : HBase master RS : Regionserver NN : Namenode DN : Datanode RM : Resourcemanager NM : Nodemanager
  • 27.
    2.1 Namenode가 죽었다. -Hadoop-2.7.2, 2.6.3 미만 - HDFS HA 구성하고, zkfc 로 auto failover 를 사용하는 경우 - 다수의 데이터노드 재시작 시 발생환경
  • 28.
    2.1 Namenode가 죽었다. 단일장애점(SPOF*), 클러스터 중단 가능성 => 높은 가용성(HA**)으로 해결 Namenode 가 죽으면..? • https://ko.wikipedia.org/wiki/단일_장애점 ** https://hadoop.apache.org/docs/r2.7.1/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html
  • 29.
    2.1 Namenode가 죽었다. NN정상작동이지만, 불필요한 NN failover Þ 사용자의 작업 지연 가능성 Þ 운영자에게 짜증나는 알림 우리의 경우는..
  • 30.
    2.1 Namenode가 죽었다. ZKFC(zookeeperfailover controller) NN1(Active ) NN2(Standby) ZKFC Health Monitor ASE ZKFC Health Monitor ASE 상태확인 Zk lock NN1 의 breadcrumb lock 을 놓음 lock 을 잡음 breadcrumb 가 자신의 것인지 확인 cf. ASE: ActiveStandbyElector 45초 동안 응답 없음 자신의 것이 아님을 인지, 다른 NN 을 죽인다. (split-brain 방지)Lock 을 잡고 있음 SERVICE_NOT_RESPONDINGquitElection ha.health-monitor.rpc-timeout.ms=45000
  • 31.
    2.1 Namenode가 죽었다. 누가그랬나? 데이터 노드 한꺼번에 재시작한 사람 == 나 NN1(Active ) ZKFC Health Monitor ASE 상태확인 DN1 DN{N} 블럭 리포팅 처리 -> 대량의 “INFO” 로그 출력 ~ 다수 재시작RPC port ? “Failover” 같은 RPC port 를 사용, 응답시간 초과 블럭 리포팅 처리 중, namespace lock -> 로그 출력에도 처리시간 지연
  • 32.
    2.1 Namenode가 죽었다. -네임노드의 INFO 로그를 TRACE 로그로 변경(HDFS-9434*) - LOG.info() => LOG.trace() 해결 방법 * https://issues.apache.org/jira/browse/HDFS-9434
  • 33.
    2.1 Namenode가 죽었다. 더좋은 해결 방법 - 네임노드에 zkfc 용 rpc port 를 따로 둔다.(HDFS-9311*) NN ZKFC Health Monitor ASE DN1 DN{N}~ * https://issues.apache.org/jira/browse/HDFS-9311
  • 34.
    RM NM NM NM~ NN DNDN DN~ RS RS RS~ NN RM HM HM HM : HBase master RS : Regionserver NN : Namenode DN : Datanode RM : Resourcemanager NM : Nodemanager
  • 35.
    2.2 Nodemanager 들이다(!) 죽었다. - standby RM 장비 변경 후, failover 가 진행될 때 - 변경 전 standby RM의 ip 를 NM 들이 캐싱하고 있었을 때 발생환경
  • 36.
    2.2 Nodemanager 들이다(!) 죽었다. NN 과 RM 이 같은 장비에 있네? RM 을 이전하자! 무중단으로! Þ NM 이 전부(!) 죽어버렸다… 누가 그랬나? RM 이전한 사람 == 나
  • 37.
    RM 이전 작업시나리오 2.2 Nodemanager 들이 다(!) 죽었다. Active RM Standby RM 1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4IP DNS rm1 rm2 Active RMStandby RM FINISH! RM failover
  • 38.
    문제 발생 2.2 Nodemanager들이 다(!) 죽었다. Active RM 1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4IP DNS rm1 rm2 Active RM NM NM NM ??? RM ­ AM: yarn.am.liveness-monitor.expiry-interval-ms RM ­ NM: yarn.nm.liveness-monitor.expiry-interval-ms NM 재시작 expired!
  • 39.
    문제 원인 1. c3는 운영 상의 이유(설정 변경)로 RM failover 가 여러 차례 발생했었다. 2. NM 에서 rm1, rm2 두 개의 IP 가 캐싱되고 있었다. 3. rm2 ip 를 변경한 후, NM 에서 변경을 인지했지만(로그에 출력됨), 새로운 ip 에 접속은 하지 않았다.(HDFS-11153*) 4. NM, AM 재시작으로 상황 해결 2.2 Nodemanager 들이 다(!) 죽었다. * https://issues.apache.org/jira/browse/HDFS-11153
  • 40.
    성공적인 RM 이전을위한 시나리오 2.2 Nodemanager 들이 다(!) 죽었다. Active RM 1.1.1.1 2.2.2.2 3.3.3.3 4.4.4.4IP DNS rm1 rm2 NM NM NM NM 롤링 재시작 RM의 호스트명을 도메인네임으로 변경 Standby RM Standby RM 을 이전 Standby RM 이전 전에 시작한 작업이 완료될 때까지 대기 Active RMStandby RM Standby RM 이전 RM failover FINISH!
  • 41.
    RM NM NM NM~ NN DNDN DN~ RS RS RS~ NN RM HM HM HM : HBase master RS : Regionserver NN : Namenode DN : Datanode RM : Resourcemanager NM : Nodemanager
  • 42.
    2.3 Resourcemanager가 failover중 죽었다. - RM Restart feature* 를 사용 - application 정보를 zookeeper 에 저장하는 설정 사용 - RM 재시작 혹은 failover 시 발생 발생하는 환경 * https://hadoop.apache.org/docs/r2.7.1/hadoop-yarn/hadoop-yarn-site/ResourceManagerRestart.html
  • 43.
    AM, NM 이일정시간이 초과되면 모두 죽는다. RM 이 죽으면..? RM ­ AM: yarn.am.liveness-monitor.expiry-interval-ms RM ­ NM: yarn.nm.liveness-monitor.expiry-interval-ms 2.3 Resourcemanager가 failover 중 죽었다.
  • 44.
    문제 원인 2.3 Resourcemanager가failover 중 죽었다. 하나의 znode 에 데이터가 너무 많다. jute.maxbuffer 설정 값보다 크면 데이터 읽기 실패 => failover 실패
  • 45.
    1. 완료된 application정보는 저장하지 않기 (yarn-site.xml) yarn.resourcemanager.state-store.max-completed-applications=0(YARN-4464*) 해결방법 2.3 Resourcemanager가 failover 중 죽었다. 2. zookeeper 설정 변경(jute.maxbuffer) export YARN_RESOURCEMANAGER_OPTS=-Djute.maxbuffer=10485760 (4mb ->10mb) * https://issues.apache.org/jira/browse/YARN-4464
  • 46.
    일정 주기로 znode가 저장되는 곳을 -Djute.maxbuffer=10485760 설정으로 읽어 봅니다. Þ 문제가 발생하면, Þ Standby RM 설정을 변경시키고 재시작 Þ Active RM 은 설정만 변경 10MB 보다 커지면…? 2.3 Resourcemanager가 failover 중 죽었다.
  • 47.
    znode 를 몰아넣지말고, 계층구조를 두면 됩니다. 근본적인 해결책(YARN-2962*) 2.3 Resourcemanager가 failover 중 죽었다. * https://issues.apache.org/jira/browse/YARN-2962
  • 48.
    RM NM NM NM~ NN DNDN DN~ RS RS RS~ NN RM HM HM HM : HBase master RS : Regionserver NN : Namenode DN : Datanode RM : Resourcemanager NM : Nodemanager
  • 49.
    2.4 HBase regionserver가 대량 죽었다. - hbase.client.keyvalue.maxsize=0 설정 사용(크기 제한 x) - 한 셀에 엄청 큰 데이터가 입력 됨 발생환경
  • 50.
    2.4 HBase regionserver가 대량 죽었다. HBase master 가 region 을 다른 regionserver 에 재할당 한다. Þ 보통은 문제 없다. 다시 살리면 된다. Þ 계속 죽는 것이 문제. HBase regionserver 가 죽으면..?
  • 51.
    2.4 HBase regionserver가 대량 죽었다. 1. 한 셀에 엄청 큰 데이터가 입력됨 누가 그랬나? 비정상적으로 큰 하나의 셀 2. 해당 셀을 처리할 때, 셀을 가지고 있는 HBase regionserver 에서 OOM 발생하여 죽음 3. 해당 region 을 다른 regionserver 에서 서빙 4. 그 regionserver 도 OOM 으로 죽음 5. 2~4 이 계속 반복되면서 전체 regionserver 가 죽음
  • 52.
    2.4 HBase regionserver가 대량 죽었다. hbase.client.keyvalue.maxsize 위 설정이 클라이언트 설정이다보니, 클라이언트가 임의로 변경할 경우, 또 발생할 수 있다. 예방 클러스터 전체가 죽는 상황을 막기 위해 1. 주기적으로 죽어 있는 regionserver 시작 2. Regionserver 가 주기적으로 죽는 문제가 발생하면, 해당 테이블을 빨리 찾아서 disable => disable 후, region 이 offline 상태로 되므로, 해당 테이블을 참조하는 작업은 계속 실패 => regionserver 에는 더 이상 OOM 이 발생하진 않는다.
  • 53.
    요약 - 하둡 커뮤니티이슈 - e.g. YARN, HDFS, HBASE 이슈의 지속적인 확인 테스트 클러스터 활용 https://issues.apache.org/jira/projects/YARN/issues https://issues.apache.org/jira/projects/HDFS/issues https://issues.apache.org/jira/projects/HBASE/issues
  • 54.
  • 55.
    3.1 centos6 ->centos7 ! Why? 1. Docker 왜 굳이? - centos6 에 대한 docker 지원은 1.7.1 버전까지* - ”—live-restore” 옵션은 1.12 버전부터 2. Tensorflow cpu 버전을 centos6 에서 구축하기란 매우 매우 힘들다. 3. 그 밖의 딥러닝 최신 패키지 제공을 위해서 … * https://github.com/moby/moby/issues/14365
  • 56.
    3.2 클러스터 무중단,Why? 전사 공통 C3는.. 서비스 + 개발 개발자 400명 이상 à 중단하기 어려움
  • 57.
    3.2 클러스터 무중단,How? 다른 OS 가 같이 있으면? - YARN container 환경 - OS 에 의존하는 작업? - YARN resource localization 고려할 점 일부 장비를 빼더라도 괜찮을까? - 클러스터 가용성
  • 58.
    3.3 OS 에의존하는 작업? 어떻게 문제를 알아낼 것인가? 사용자의 작업을 전수 조사 - 사용자 개입 X - 작업 추출, 테스트 클러스터에 돌려보기
  • 59.
    3.3 OS 에의존하는 작업? 작업 종류 호환성 Pure Java app. O Native library X Shell script Δ Native library ? => distributed cache 조사 Shell script ? => hadoop streaming job 조사 어떤 작업이 문제가 있는가?
  • 60.
    3.3 OS 에의존하는 작업? Native library 를 사용하는 작업 lib1.c lib2.c lib3.c SWIG PerlJS ???Python
  • 61.
    3.3 OS 에의존하는 작업? Shell script 를 사용할 경우 - Awk (3.1.7v à 4.0.2v) centos7centos6
  • 62.
    3.4 YARN resourcelocalization OS 별 리소스 배포? - YARN 에서는 리소스가 어떻게 배포될까?
  • 63.
    3.4 YARN resourcelocalization YARN 에서 작업이 수행되는 과정* YARN client HDFS * https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources Resource Manager 1. 리소스(파일)를 HDFS 에 업로드 NM1 NM2 NM3 - 다음 내용은 사용자가 작업을 제출한 뒤의 내부 동작입니다.
  • 64.
    3.4 YARN resourcelocalization YARN client HDFS Resource Manager 2. Application 제출 NM1 NM2 NM3 YARN 에서 작업이 수행되는 과정* * https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources
  • 65.
    3.4 YARN resourcelocalization YARN client HDFS Resource Manager NM1 NM2 NM3 3. 컨테이너 스케쥴링(할당) Container1 Container2 Container3 YARN 에서 작업이 수행되는 과정* * https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources
  • 66.
    YARN client HDFS Resource Manager 4. 리소스(파일)을 HDFS에서 로컬로 다운로드 NM1 NM2 NM3 Container1 Container2 Container3 3.4 YARN resource localization Resource localization YARN 에서 작업이 수행되는 과정* * https://www.slideshare.net/Hadoop_Summit/a-secure-public-cache-for-yarn-application-resources
  • 67.
    다른 OS 가섞여 있을 때 문제점 3.4 YARN resource localization HDFS NM1 NM2 NM3 Container1 Container2 Container3 centos6 centos7 centos6 ? for 6
  • 68.
    각 OS 에맞는 리소스를 배포하기 3.4 YARN resource localization HDFS NM1 NM2 NM3 Container1 Container2 Container3 centos6 centos7 centos6 for 6 for 7
  • 69.
    1. 하둡 패키지코드 수정* 2. NM 재시작 3. 작업 제출 시 설정 mapreduce.job.cache.files=/file/_native_centos6_foo.bar,/file/_native_centos7_foo.bar 각 OS 에 맞는 리소스를 배포하기 3.4 YARN resource localization * https://github.com/naver/hadoop/commit/6f18dc0af537cef734b6d4d064573341ca9fc870
  • 70.
    예) mysql-devel 설치 시, -centos6: mysql, mysql-devel - centos7: mysql-devel 1. yum package 의 dependency 가 다른 경우 3.5 OS 별 추가 고려사항
  • 71.
    Hadoop 프로젝트에서의 Parametersubstitution (e.g. $PATH) à heterogenous cluster 라면 특히 유의 2. PATH 환경변수는 동일하게 맞추자. 3.5 OS 별 추가 고려사항 * http://www.tldp.org/LDP/abs/html/parameter-substitution.html
  • 72.
    3.5 OS 별추가 고려사항 2. PATH 환경변수는 동일하게 맞추자. 사례) AM 은 centos7에 할당되고, map 작업은 centos6 에 할당될 경우, PATH 문제로 ln 명령을 찾지 못하고, 컨테이너 실행 실패.
  • 73.
    3.5 OS 별추가 고려사항 2. PATH 환경변수는 동일하게 맞추자. Why? - centos7 PATH 에는 /bin 이 없다. - /bin -> /usr/bin - AM 에서 환경변수 치환 (mapred.child.env=PATH=.:$PATH), ln 명령에 문제 발생 - centos6: /bin/ln - centos7: /usr/bin/ln
  • 74.
    3.5 OS 별추가 고려사항 2. PATH 환경변수는 동일하게 맞추자. cf. AM: Application Master AM container mapred.child.env=PATH=.:$PATH centos7 PATH=/usr/bin centos6 PATH=/bin:/usr/bin centos6 PATH=/usr/bin centos6 에서는 /usr/bin/ln 이 없다!
  • 75.
    이제 OS 에따라 다른 리소스 배포 가능 환경 일치 => centos7 장비 추가 가능 => centos6 장비를 빼내고 업그레이드 진행 후 다시 장비 투입 centos6 + centos7 3.6 Nodemanager 디커미션
  • 76.
    3.6 Nodemanager 디커미션 장비를빼기 전, NM부터 제거해야.. NM Container NM Container 대기 디커미션 graceful 디커미션 https://hadoop.apache.org/docs/r3.0.0-alpha4/hadoop-yarn/hadoop-yarn-site/GracefulDecommission.html 컨테이너 종료 Container 새 컨테이너 할당 금지
  • 77.
    3.6 Nodemanager 디커미션 장비를빼기 전, NM부터 제거해야.. 하둡 버전 디커미션 graceful 디커미션 2.7.1 O X 3.0.0-alpha4↑ O O
  • 78.
    리소스 한도를 확줄여서 더 이상 새로운 작업이 할당되지 않도록 하자! 다른 방법은 없나…? 3.6 Nodemanager 디커미션
  • 79.
    1. RM의 minimum-allocation설정을 충분히 작게 3.6 Nodemanager 디커미션 cf. Hadoop 2.7.1 mapred-default.xml 에서 기본값* Property 값 mapreduce.map.memory.mb 1024 mapreduce.reduce.memory.mb 1024 mapreduce.map.cpu.vcores 1 mapreduce.reduce.cpu.vcores 1 * https://hadoop.apache.org/docs/r2.7.1/hadoop-mapreduce-client/hadoop-mapreduce-client-core/mapred-default.xml
  • 80.
    2. 리소스 설정최소화하기 3.6 Nodemanager 디커미션
  • 81.
    3. NM Restart기능* 활성화 * https://hadoop.apache.org/docs/r2.7.1/hadoop-yarn/hadoop-yarn-site/NodeManagerRestart.html Property 값 yarn.nodemanager.recovery.enabled true yarn.nodemanager.recovery.dir /some/path yarn.nodemanager.address 0 (Ephemeral port) 이외의 포트번호 3.6 Nodemanager 디커미션
  • 82.
    4. NM 재시작 3.6Nodemanager 디커미션
  • 83.
    5. 해당 노드에서수행 중인 작업이 완료되면 NM을 죽입니다. 3.6 Nodemanager 디커미션
  • 84.
    3.7 중단 없는OS 업그레이드 centos6 centos7centos7 클러스터에 장비 추가 하둡 컴포넌트 제거 업그레이드! NM, … DN NM, … DN 하둡 컴포넌트 설치 클러스터에 장비 추가 클러스터에서 장비 제거 하둡 컴포넌트 설치 끝
  • 85.
    요약 YARN container 환경통일 작업에 영향이 없도록 장비 제거 후, 업그레이드 진행 문제 가능성이 있는 작업은 사전에 대비
  • 86.