hbase bulk load相关源码简析之HFileOutputFormat、LoadIncrementalHFiles

来源:互联网 发布:媒体的作用 知乎 编辑:程序博客网 时间:2024/06/01 09:20

转载请注明出处: http://blog.csdn.net/lonelytrooper/article/details/17040895

PutSortReducer:

[java] view plain copy
  1. // 对map阶段传递过来的puts中的KVs做排序,并将有序的KVs写到输出流(最终写的类是HFileWriterV1或HFileWriterV2的append方法)...  
  2. public class PutSortReducer extends  
  3.         Reducer<ImmutableBytesWritable, Put, ImmutableBytesWritable, KeyValue> {  
  4.   
  5.     @Override  
  6.     protected void reduce(ImmutableBytesWritable row, java.lang.Iterable<Put> puts,  
  7.             Reducer<ImmutableBytesWritable, Put, ImmutableBytesWritable, KeyValue>.Context context)  
  8.             throws java.io.IOException, InterruptedException {  
  9.         // although reduce() is called per-row, handle pathological case  
  10.         // 设定一个RAM的阀值,用于应对非常规的情况.. 默认值2L * (1 << 30)为Integer.MAX_VALUE+1  
  11.         long threshold = context.getConfiguration().getLong("putsortreducer.row.threshold",  
  12.                 2L * (1 << 30));  
  13.         Iterator<Put> iter = puts.iterator();  
  14.         while (iter.hasNext()) {  
  15.             TreeSet<KeyValue> map = new TreeSet<KeyValue>(KeyValue.COMPARATOR); // KVComparator  
  16.             long curSize = 0;  
  17.             // stop at the end or the RAM threshold  
  18.             // 用curSize累计当前puts的size,但这个size不能超过threshold...  
  19.             while (iter.hasNext() && curSize < threshold) {  
  20.                 Put p = iter.next();  
  21.                 for (List<KeyValue> kvs : p.getFamilyMap().values()) {  
  22.                     for (KeyValue kv : kvs) {  
  23.                         map.add(kv);  
  24.                         curSize += kv.getLength();  
  25.                     }  
  26.                 }  
  27.             }  
  28.             // 记录已读取的map中的KV的个数,并将curSize转成易读的KB,MB,GB..  
  29.             context.setStatus("Read " + map.size() + " entries of " + map.getClass() + "("  
  30.                     + StringUtils.humanReadableInt(curSize) + ")");  
  31.             int index = 0;  
  32.             // 将当前有序的KV写到输出流..  
  33.             for (KeyValue kv : map) {  
  34.                 context.write(row, kv);  
  35.                 if (index > 0 && index % 100 == 0// 记录进度,每100个记录一次..  
  36.                     context.setStatus("Wrote " + index);  
  37.             }  
  38.   
  39.             // if we have more entries to process  
  40.             //如果居然还有put没处理完..我们会通过context.write(null, null)强刷.. 这会关闭当前的Writer(StoreFile.Writer),并形成了一个StoreFile。  
  41.             //在外层的下次循环中,会继续处理余下的数据,并创建新的StoreFile的Writer。 换言之,这种情况下相同rowkey的数据会被写到不同的StoreFile中...  
  42.             //细节部分可以看下HFileOutputFormat下RecordWriter类下的write方法..  
  43.             if (iter.hasNext()) {  
  44.                 // force flush because we cannot guarantee intra-row sorted  
  45.                 // order  
  46.                 context.write(nullnull);  
  47.             }  
  48.         }  
  49.     }  
  50. }  

KeyValueSortReducer:
[java] view plain copy
  1. // 类比PutSortReducer,对map传递过来的KVs进行排序,并将有序的KVs写到输出流...  
  2. // 如果一行包含的列非常多的话,有oom的风险..  
  3. public class KeyValueSortReducer extends Reducer<ImmutableBytesWritable, KeyValue, ImmutableBytesWritable, KeyValue> {  
  4.   protected void reduce(ImmutableBytesWritable row, java.lang.Iterable<KeyValue> kvs,  
  5.       org.apache.hadoop.mapreduce.Reducer<ImmutableBytesWritable, KeyValue, ImmutableBytesWritable, KeyValue>.Context context)  
  6.   throws java.io.IOException, InterruptedException {  
  7.     TreeSet<KeyValue> map = new TreeSet<KeyValue>(KeyValue.COMPARATOR);  
  8.     for (KeyValue kv: kvs) {  
  9.       map.add(kv.clone());  
  10.     }  
  11.     context.setStatus("Read " + map.getClass());  
  12.     int index = 0;  
  13.     for (KeyValue kv: map) {  
  14.       context.write(row, kv);  
  15.       if (index > 0 && index % 100 == 0) context.setStatus("Wrote " + index);  
  16.     }  
  17.   }  
  18. }  

简单说下TotalOrderPartitioner和SimpleTotalOrderPartitioner:

TotalOrderPartitioner:

做全排序的东东,Hbase中的TOP其实就是Hadoop中TOP的直接拷贝,通过从外部文件中读取分区点来实现。 在bulk load中,这个外部文件即为从HTable中获取的region的startKeys处理之后得到的split points,这个split points文件被写到了路径Path partitionsPath = new Path(job.getWorkingDirectory(), "partitions_" + UUID.randomUUID())。

SimpleTotalOrderPartitioner:

简单的做全排序的东东,原则是根据输入的startkey和endkey进行均分,区间是左闭右开。