面试题答案
一键面试数据倾斜原因
- 数据分布不均:
- 原始数据本身在某些维度(如时间、地域等)上就存在大量集中,导致按照特定规则(如rowkey设计)写入HBase时,部分region负载过高。
- 例如,在以时间戳作为rowkey前缀的场景下,如果业务数据在某个时间段内大量产生,就会使得该时间段对应的region数据量远大于其他region。
- Rowkey设计不合理:
- 若rowkey的前缀具有高度重复性,会导致数据集中在少数几个region。比如使用固定前缀(如“user_”)后再拼接用户ID,当用户ID没有经过打散处理时,数据会集中在少数以“user_”开头的region上。
- 未考虑HBase的region切分机制,没有根据数据量和分布合理设计rowkey,使得region切分不均匀。
MapReduce程序优化措施
- 数据预处理:
- 在Map阶段对数据进行打散处理。例如,可以对具有高度重复性的rowkey前缀进行随机化处理,给每个key加上一个随机数前缀。
public class MapClass extends Mapper<LongWritable, Text, Text, IntWritable> { private final static IntWritable one = new IntWritable(1); private Text word = new Text(); @Override protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException { // 假设原始rowkey在value中 String originalRowkey = value.toString(); // 生成0 - 99的随机数 int randomNum = new Random().nextInt(100); String newRowkey = randomNum + "_" + originalRowkey; word.set(newRowkey); context.write(word, one); } }
- 自定义Partitioner:
- 重写Partitioner类,根据数据的实际分布情况进行分区。比如,如果数据在某个字段上分布相对均匀,可以基于该字段进行分区。
public class CustomPartitioner extends Partitioner<Text, IntWritable> { @Override public int getPartition(Text key, IntWritable value, int numPartitions) { // 假设key格式为“prefix_value”,基于value部分进行分区 String[] parts = key.toString().split("_"); if (parts.length > 1) { int hash = parts[1].hashCode(); return Math.abs(hash) % numPartitions; } return 0; } }
- 在Job配置中设置自定义Partitioner:
Job job = Job.getInstance(conf, "Data Skew Optimization"); job.setPartitionerClass(CustomPartitioner.class);
HBase配置优化措施
- Region预分区:
- 在创建表时,根据数据的预估分布进行预分区。可以使用
HBaseAdmin
工具或者create
命令的SPLITS
参数。 - 例如,使用Java API进行预分区:
HBaseAdmin admin = new HBaseAdmin(conf); byte[][] splits = new byte[][]{Bytes.toBytes("a"), Bytes.toBytes("b"), Bytes.toBytes("c")}; HTableDescriptor tableDesc = new HTableDescriptor(TableName.valueOf("my_table")); admin.createTable(tableDesc, splits);
- 在创建表时,根据数据的预估分布进行预分区。可以使用
- 调整RegionServer负载均衡:
- 调整
hbase.regionserver.regionSplitLimit
参数,合理限制每个RegionServer上的region数量,避免单个RegionServer负载过高。 - 开启自动负载均衡功能,在
hbase - site.xml
中设置hbase.balancer.period
参数,控制负载均衡运行的周期,例如设置为60000(单位毫秒,即60秒)。
<property> <name>hbase.balancer.period</name> <value>60000</value> </property>
- 调整