Hadoop Streaming 中的数据倾斜坑

Hadoop Streaming 中的数据倾斜坑

1. 背景

最近用 hadoop streaming 跑一个数据集,不算大,每小时150G左右,但是每次耗时特别长,而且基本是卡在了reduce 98%的地方。     

看了下输出,基本上是数据集中到一两个reducer上了,因此每次吐出最后几个reducer耗时特别长。     

处理的数据在mapper输出类似于下面这种形式(真实数据企业敏感度高,就不公开了), 第一列取值范围很小,假设为[0-9],第二列大一些[0-100],第三列[0-1000],第四列[0-10000]。

1   10  100 1000
2   21  211 2110
...
9   10  992 9982

一开始出现数据倾斜的脚本如下,设定了map、reducer的数量、容量、内存上限等。

...省略各种变量定义

${HADOOP_CLIENT_BIN} streaming \
-D mapred.map.tasks=1024 \
-D mapred.reduce.tasks=256 \
-D mapred.job.map.capacity=256 \
-D mapred.job.name="Task_${DATE}_${HOUR}" \
-D mapred.job.priority="HIGH" \
-D stream.memory.limit=8000 \
-D mapred.job.reduce.memory.mb=8000 \
-file Mapper.py \
-file Reducer.py \
-input ${SOURCE_PATH}/*/*.log* \
-output ${OUT_PATH} \
-mapper "python Mapper.py hadoop" \
-reducer "python Reducer.py hadoop"

2. 为什么出现数据倾斜

在Hadoop streaming 中,一次maper后默认会以第一列作为key进行分桶shuffle,将hash到同一个分桶的key放到一个reducer中进行输出。由于我的mapper输出的第一列取值范围很小,而且如果以第一列为key的话,每个key下的数据规模也是不同的。     

我的脚本中指定了256个reducer,而key的取值只有10个,假设每个key被hash到了不同的分桶,那么最多只有10个reducer被合理使用到了,换言之,其他reducer都浪费了。而且,实际上这些key很有可能被hash到少量的几个分桶中甚至同一个分桶,于是就出现了开头的情况:reducer到了98%会执行一个多小时,那么实际150G的数据都是由这一两个reducer写到了HDFS上。

3. 解决方案

明白了出现数据倾斜的原因了,那么就好解决了。hadoop streaming中有个参数叫做stream.num.map.output.key.fields,这个参数的含义是,从左往右以多少列数据作为mapper的key,比如我将该参数设为4,那么整行数据将作为一个key算hash分桶,这样的话,key的取值范围就成了[1 * 100 * 1000 * 10000, 10 * 100 * 1000 * 10000],这样就能有效避免mapper结果shuffle后数据倾斜了。

...省略各种变量定义

${HADOOP_CLIENT_BIN} streaming \
-D mapred.map.tasks=1024 \
-D mapred.reduce.tasks=256 \
-D mapred.job.map.capacity=256 \
-D mapred.job.name="Task_${DATE}_${HOUR}" \
-D mapred.job.priority="HIGH" \
-D stream.memory.limit=8000 \
-D mapred.job.reduce.memory.mb=8000 \
-D stream.num.map.output.key.fields=4 \
-file Mapper.py \
-file Reducer.py \
-input ${SOURCE_PATH}/*/*.log* \
-output ${OUT_PATH} \
-mapper "python Mapper.py hadoop" \
-reducer "python Reducer.py hadoop"

4. 举一反三

相关参数:
1. stream.num.map.output.key.fields,stream.num.reducer.output.key.fields;指定mapper和reducer输出的key的列范围,例如,值为2表示第1、2列一起作为key。
2. stream.map.output.field.separator可以自定义分割符号,比如你希望用\x01分割数据,可以再这里进行指定。
3. mapred.text.key.partitioner.options用来保证指定key后,相同的key被分配到同一个reducer上,设置值为-ki,j,表示从第i到第j列作为分区的key。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值