리듀서 개수는 잡의 병렬도이면서 출력 파일 개수이기도 하다. 너무 적으면 한 리듀서에 데이터가 몰려 잡 전체가 그 하나를 기다리고, 너무 많으면 태스크 기동 비용과 작은 파일이 늘어 클러스터와 NameNode 에 부담이 된다. Hive 쿼리에서 태스크 수가 수만 개로 잡혀 진행이 되지 않는 상황도 대개 여기서 온다.
| 현행 이름 | 예전 이름 | 뜻 |
|---|---|---|
mapreduce.job.reduces |
mapred.reduce.tasks |
리듀서 개수 |
mapreduce.input.fileinputformat.split.maxsize |
mapred.max.split.size |
입력 분할 최대 크기 |
예전 이름은 호환을 위해 아직 받아 주지만 사용 중단된 이름이다. 새로 쓰는 설정에는 현행 이름을 쓴다. 인터넷 예제 대부분이 옛 이름이라 섞여 쓰이는데, 설정 파일에서 이름이 뒤섞이면 나중에 어느 쪽이 먹는지 알기 어려워진다.
hadoop jar myjob.jar -D mapreduce.job.reduces=32 /in /out
Hive 는 입력 크기로 리듀서 수를 스스로 계산한다. 계산에 쓰이는 값은 다음과 같다.
| 설정 | 기본값 | 뜻 |
|---|---|---|
hive.exec.reducers.bytes.per.reducer |
256MB 내외(버전별 상이) | 리듀서 하나가 맡을 입력 크기 |
hive.exec.reducers.max |
1009 | 리듀서 수 상한 |
계산은 대략 "입력 크기 / bytes.per.reducer" 이고 상한에서 잘린다.
태스크가 너무 많으면 리듀서 하나가 맡을 크기를 키운다.
SET hive.exec.reducers.bytes.per.reducer=536870912;
반대로 너무 적어 느리면 이 값을 줄인다. mapreduce.job.reduces 를 직접 지정하면 Hive 의 계산을 무시하므로, 데이터 크기가 달라져도 그 값이 고정된다. 일회성 작업이 아니면 권하지 않는다.
ORDER BY 처럼 전역 정렬이 필요한 쿼리는 리듀서가 반드시 1개가 된다. 이 경우 리듀서 수를 늘려도 소용없고, 정렬 범위를 줄이거나 SORT BY 와 DISTRIBUTE BY 로 바꾸는 것이 해법이다.
hdfs dfs -count /path/to/table
EXPLAIN SELECT ...;
SET hive.merge.mapfiles=true;
SET hive.merge.mapredfiles=true;
SET hive.merge.size.per.task=268435456;
SET hive.merge.smallfiles.avgsize=134217728;
SET mapreduce.input.fileinputformat.split.maxsize=268435456;
리듀서 수를 아무리 맞춰도 특정 키에 값이 몰리면 그 리듀서만 오래 걸린다. 다른 리듀서는 다 끝났는데 하나가 몇 시간을 더 도는 형태로 나타난다.
SET hive.groupby.skewindata=true;
SET hive.optimize.skewjoin=true;
이 옵션들은 잡을 두 단계로 나누므로 쏠림이 없는 경우에는 오히려 느려진다. 상시로 켜 두지 않는다.
hive.tez.auto.reducer.parallelism 이 켜져 있으면 실행 중에 다시 계산한다.