整合storm-hdfs过程中源码学习

来源:互联网 发布:sql注入的防御 编辑:程序博客网 时间:2024/05/16 07:27
前一段整合了stomr-hdfs,但是发现在原有的storm-hdfs-0.9.4.jar中的写入数据的逻辑不满足我们的需求,于是乎需要看源码,然后在源码的基础上改写源码,满足自己的需求。

整合storm-hdfs的过程,其实也就是编写storm的拓扑结构,然后调用storm-hdfs-0.9.4.jar中的hdfsBolt,通过配置hdfsBolt的一些与hdfs有关的参数,将数据写入到hdfs中。

配置的参数:

1、RecordFormat:定义字段定界符,你可以使用换行符\n或者制表符\t;

2、SyncPolicy:定义每次写入的tuple的数量;

3、FileRotationPolicy:定义写入的hdfs文件的轮转策略,你可以以时间轮转(TimedRotationPolicy)、大小轮转(FileSizeRotationPolicy)、不轮转(NoRotationPolicy);

4、FileNameFormat:定义写入文件的路径(withPath)和文件名的前后缀(withPrefix、withExtension);

5、withFsUrl:定义hdfs的地址。

hdfsBolt中写数据的源码:

[java] view plain copy
  1. public void execute(Tuple tuple)  
  2.  {  
  3.    try  
  4.    {  
  5.      byte[] bytes = this.format.format(tuple);  //对每一条数据添加定界符  
  6.      synchronized (this.writeLock)  
  7.      {  
  8.        this.out.write(bytes);     //调用输出流写数据  
  9.        this.offset += bytes.length;  //更新写入文件的当前大小  
  10.        if (this.syncPolicy.mark(tuple, this.offset))      //当数据条数满足所配的条数时,写入到hdfs  
  11.        {         
  12.          if ((this.out instanceof HdfsDataOutputStream)) {        
  13.            ((HdfsDataOutputStream)this.out).hsync(EnumSet.of(HdfsDataOutputStream.SyncFlag.UPDATE_LENGTH));  
  14.          } else {  
  15.            this.out.hsync();  
  16.          }  
  17.          this.syncPolicy.reset();  
  18.        }  
  19.      }  
  20.      this.collector.ack(tuple);  
  21.      if (this.rotationPolicy.mark(tuple, this.offset))   //当当前文件大小等于所配轮转文件的大小,则轮转文件,重建新的写入文件  
  22.      {  
  23.        rotateOutputFile();  
  24.        this.offset = 0L;  
  25.        this.rotationPolicy.reset();  
  26.      }  
  27.    }  
  28.    catch (IOException e)  
  29.    {  
  30.      LOG.warn("write/sync failed.", e);  
  31.      this.collector.fail(tuple);  
  32.    }  
  33.  }  


hdfsBolt每次新建文件的方法:

[java] view plain copy
  1. Path createOutputFile()  
  2.     throws IOException  
  3.   {  
  4.     Path path = new Path(this.fileNameFormat.getPath(), this.fileNameFormat.getName(this.rotation, System.currentTimeMillis()));  
  5.     this.out = this.fs.create(path);  //新建一个输出流(对应一个新的文件)  
  6.     return path;   //返回路径  
  7.   }  


轮转文件的方法:

[java] view plain copy
  1. protected void rotateOutputFile()  
  2.     throws IOException  
  3.   {  
  4.     LOG.info("Rotating output file...");  
  5.     long start = System.currentTimeMillis();  
  6.     synchronized (this.writeLock)  
  7.     {  
  8.       closeOutputFile();    //关闭前一个文件的输出流  
  9.       this.rotation += 1;  //轮转数加一(这里的轮转数会反应到文件名上)  
  10.         
  11.       Path newFile = createOutputFile();   //新建一个文件  
  12.       LOG.info("Performing {} file rotation actions.", Integer.valueOf(this.rotationActions.size()));  
  13.       for (RotationAction action : this.rotationActions) {  
  14.         action.execute(this.fs, this.currentFile);  
  15.       }  
  16.       this.currentFile = newFile;  //更新当前写入文件的路径  
  17.     }  
  18.     long time = System.currentTimeMillis() - start;  
  19.     LOG.info("File rotation took {} ms.", Long.valueOf(time));  
  20.   }  



添加字段定界符源码:

[java] view plain copy
  1. public byte[] format(Tuple tuple)  
  2.   {  
  3.     StringBuilder sb = new StringBuilder();  
  4.     Fields fields = this.fields == null ? tuple.getFields() : this.fields;  
  5.     int size = fields.size();  
  6.     for (int i = 0; i < size; i++)  
  7.     {  
  8.       sb.append(tuple.getValueByField(fields.get(i)));  
  9.       if (i != size - 1) {  
  10.         sb.append(this.fieldDelimiter);  
  11.       }  
  12.     }  
  13.     sb.append(this.recordDelimiter);   //添加定界符  
  14.     return sb.toString().getBytes();  
  15.   }  



CountSyncPolicy源码,CountSyncPolicy实现SyncPolicy的接口方法:

[java] view plain copy
  1. public class CountSyncPolicy  
  2.   implements SyncPolicy  
  3. {  
  4.   private int count;       //配置的每次写入tuple数量  
  5.   private int executeCount = 0//当前已经执行的tuple的数量  
  6.     
  7.   public CountSyncPolicy(int count)  
  8.   {  
  9.     this.count = count;  
  10.   }  
  11.     
  12.   public boolean mark(Tuple tuple, long offset)    //判断当前写入输出流缓存中的数量是否超过每次写入数量  
  13.   {  
  14.     this.executeCount += 1;  
  15.     return this.executeCount >= this.count;  
  16.   }  
  17.     
  18.   public void reset()  
  19.   {  
  20.     this.executeCount = 0;    //重置方法,每次写入后,执行重置方法归零  
  21.   }  
  22. }  



FileSizeRotationPolicy的源码(FileSizeRotationPolicy实现FileRotationPolicy的接口方法):

[java] view plain copy
  1. public class FileSizeRotationPolicy  
  2.   implements FileRotationPolicy  
  3. {  
  4.   private static final Logger LOG = LoggerFactory.getLogger(FileSizeRotationPolicy.class);  
  5.   private long maxBytes;  //文件写满的大小  
  6.     
  7.   public static enum Units  
  8.   {                                                                                                                                           //文件切换轮转的大小单位  
  9.     KB(Math.pow(2.0D, 10.0D)),  MB(Math.pow(2.0D, 20.0D)),  GB(Math.pow(2.0D, 30.0D)),  TB(Math.pow(2.0D, 40.0D));  
  10.       
  11.     private long byteCount;  
  12.       
  13.     private Units(long byteCount)  
  14.     {  
  15.       this.byteCount = byteCount;  
  16.     }  
  17.       
  18.     public long getByteCount()  
  19.     {  
  20.       return this.byteCount;  
  21.     }  
  22.   }  
  23.     
  24.   private long lastOffset = 0L;  
  25.   private long currentBytesWritten = 0L;  
  26.     
  27.   public FileSizeRotationPolicy(float count, Units units)  
  28.   {  
  29.     this.maxBytes = ((count * (float)units.getByteCount())); //根据切换文件的单位来计算文件写满该有的大小  
  30.   }  
  31.     
  32.   public boolean mark(Tuple tuple, long offset)   //文件是否切换的判断方法  
  33.   {  
  34.     long diff = offset - this.lastOffset;  
  35.     this.currentBytesWritten += diff;  
  36.     this.lastOffset = offset;  
  37.     return this.currentBytesWritten >= this.maxBytes;  
  38.   }  
  39.     
  40.   public void reset()    //重置方法  
  41.   {  
  42.     this.currentBytesWritten = 0L;  //当前文件已写的大小  
  43.     this.lastOffset = 0L;  //一次写入后的offset值  
  44.   }  
  45. }  


DefaultFileNameFormat的源码(DefaultFileNameFormat实现FileNameFormat的接口方法):

[java] view plain copy
  1. public class DefaultFileNameFormat  
  2.   implements FileNameFormat  
  3. {  
  4.   private String componentId;  
  5.   private int taskId;         //任务名id  
  6.   private String path = "/storm"//写入的目录路径  
  7.   private String prefix = "";   //文件名前缀  
  8.   private String extension = ".txt";//文件名后缀  
  9.     
  10.   public DefaultFileNameFormat withPrefix(String prefix)  
  11.   {  
  12.     this.prefix = prefix;  
  13.     return this;  
  14.   }  
  15.     
  16.   public DefaultFileNameFormat withExtension(String extension)  
  17.   {  
  18.     this.extension = extension;  
  19.     return this;  
  20.   }  
  21.     
  22.   public DefaultFileNameFormat withPath(String path)  
  23.   {  
  24.     this.path = path;  
  25.     return this;  
  26.   }  
  27.     
  28.   public void prepare(Map conf, TopologyContext topologyContext)  
  29.   {  
  30.     this.componentId = topologyContext.getThisComponentId();  
  31.     this.taskId = topologyContext.getThisTaskId();  
  32.   }  
  33.     
  34.   public String getName(long rotation, long timeStamp)  //得到写入文件的文件名  
  35.   {  
  36.     return this.prefix + this.componentId + "-" + this.taskId + "-" + rotation + "-" + timeStamp + this.extension;  
  37.   }  
  38.     
  39.   public String getPath()  
  40.   {  
  41.     return this.path;  
  42.   }  
  43. }  

http://blog.csdn.net/u014039577/article/details/50215913
0 0