HBase-put写操作源码分析



Hbase Put流程


1.客户端提起请求
HTable.put();
|-->writeBuffer.add(put);  |刷入内存缓存,可设置实时生效
|-->线程池提交
|-->for (Entry<HRegionLocation, MultiAction<R>> e: actionsByServer.entrySet()) 
          |-->futures.put(e.getKey(), pool.submit(createCallable(e.getKey(), e.getValue(), tableName)));
|-->client调用server.multi(MultiAction<R> multi)


2.RegionServer找到region
|-->Hregionserver.multi()
    |-->for (Map.Entry<byte[], List<Action<R>>> e : multi.actions.entrySet()) |Action对象包括delete,put,get等对象,command模式
    |-->if (action instanceof Delete || action instanceof Put)
           |--> mutations.add(a);
|-->HRegion region = getRegion(regionName);
|-->for (Action<R> a : mutations)
     |--> mutationsWithLocks.add(new Pair<Mutation, Integer>(m, lock));
|-->OperationStatus[] codes = region.batchMutate(mutationsWithLocks.toArray(new Pair[]{}));
     


3.region处理:一个column family对应一个storefile对象,但是flush的时候是整个region下的全部store一起flush
|-->while (lastIndexExclusive < batchOp.operations.length)
     |-->Map<byte[], List<KeyValue>> familyMap = mutation.getFamilyMap();
     |-->for (int i = firstIndex; i < lastIndexExclusive; i++)
     |-->addedSize += applyFamilyMapToMemstore(familyMaps[i], w);
          |-->for (Map.Entry<byte[], List<KeyValue>> e : familyMap.entrySet())
               |-->byte[] family = e.getKey(); |column family名称
               |-->List<KeyValue> edits = e.getValue(); |KeyValue对应的是每一个column的键值对
               |-->for (KeyValue kv: edits)
                    |-->size += store.add(kv);  |添加至store当中
                         |-->this.memstore.add(kv);  |实质为column family对应一个storefile对象里的memsotre内存对象
     |-->flush = isFlushSize(this.addAndGetGlobalMemstoreSize(addedSize)); |判断是否需要flush内存
     -->if (flush)
          |-->requestFlush()


4.requestFlush()
|-->this.rsServices.getFlushRequester().requestFlush(this);
|-->MemStoreFlusher.requestFlush(region); |处理当时region


|-->this.regionsInQueue.put(r, fqe);


                  |-->this.flushQueue.add(fqe);


5.MemStoreFlush()线程持续做flush操作
|--> if (!flushRegion(fre))
     |-->flushRegion(region, false)
          |-->boolean shouldCompact = region.flushcache()
               |-->boolean result = internalFlushcache(status);
                              |-->internalFlushcache(this.log, -1, status);
                                        |-->for (StoreFlusher flusher : storeFlushers) {
                      |-->flusher.prepare(); |构造snapshot
                                        |-->for (StoreFlusher flusher : storeFlushers) {
                      |-->flusher.flushCache(status);  |刷新工作在此进行,完成实质的flush过程
                         |--> Store.this.flushCache()
                              |--> internalFlushCache() |构建memstoreScanner,然后逐步写入hfile当中
|-->for (StoreFlusher flusher : storeFlushers) {
        |-->boolean needsCompaction = flusher.commit(status);
        |-->if (needsCompaction) {
          |-->compactionRequested = true


6.HFile文件写hdfs的结构:以块为单位,HFileBlock
      |-->append(key,value)
     |-->checkBlockBoundary()  |实际的写HDFS操作,条件为满64k
          |-->finishBlock()
               |-->fsBlockWriter.writeHeaderAndData(outputStream); |outputStream的路径为file定义的path路径
                    |-->实质为写入byteArray的数据流
     |-->DataOutputStream out = fsBlockWriter.getUserDataStream();
          |-->out.put(key)
                    |-->out.put(value)
      |-->finishBlock()  |HFileBlock中进行flush()
     |-->userDataStream.flush(); |实质为字节流
     |-->doCompressionAndChecksumming() |压缩字节流




   
          


7.备注:无论是split还是compact都是通过compactSplitThread 启动的
flushCache完成memstore转向hfile文件


7.1 compact目前是针对单个的store也就是column family,下述方法实现compact合并
     StoreFile.Writer writer = compactStore(filesToCompact, cr.isMajor(), maxId);
      compact流程
      |-->server.compactSplitThread.requestCompaction(region, getName());
           |-->requestCompaction(r, s, why, Store.NO_PRIORITY);
        |-->CompactionRequest cr = s.requestCompaction(priority);
           |-->boolean isMajor = (filesToCompact.getFilesToCompact().size() == this.storefiles.size()); |如果StoreFile下所有文件参与,则与majorcompaction,否则为minor compaction
           |-->ret = new CompactionRequest(region, this, filesToCompact, isMajor, pri);
               |-->ThreadPoolExecutor pool = s.throttleCompaction(cr.getSize())? largeCompactions : smallCompactions;  |根据CompactionRequest的大小确定使用大小compaction线程池执行compact操作
  
注意:先根据是否全部storefiles全部compact,如是为major compact,与minor compact区别在于是否会执行delete 
           然后再根据CompactRequest的大小来确定使用large/small 线程程进行处理,线程数不同


7.2 Split操作
      a:获取midkey
      b:生成splittrasaction
      c:创建并生效二个子Region
      d:注册至zookeeper




HFile读写见Hbase4test工程
HFile结构见http://blog.163.com/liaoxiangui@126/blog/static/79569640201212311415217/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值