flume spoolDirectory Source原生代码流程及其拓展

最近我们要在flume的基础上做定制开发。我这块主要的开发是,对zip包中的文件做一定的处理后,以avro方式序列化。整个流程参考了flume的spoolDirectorySource的实现,因为主要是对spooldirectorySource中文件解析的部分进行了参考,所以下面的文章将会着重分析文件的解析部分。


特此声明:该文仅做记录和探讨之用,文中没有涉及任何公司业务相关的部分。


1、  spoolDirectorySource简要介绍

SpoolingDirectorySource可以监控指定目录,如果有有新文件出现在指定目录,source会将这个新文件按照配置中的的序列化类型,将文件序列化成一个个event。在文件中的所有的内容都读取到Channel之后(commit),Spooling Directory Source才会对文件进行重命名或者删除,这样就保证了数据不会丢失,虽然可能有一些冗余,但是是在我们接受范围内的。


2、spoolDirectorySource工作流程


下图是根据代码流程画的一个流程图,可能会有些谬误,仅供参考哈。



2.1、 Function--configure

启动spool directory source第一步,configure方法。通过SpoolZipDirectorySourceConfigurationConstants中定义的那些配置,将context 中的相关配置信息提取出来,比如文件输入路径(SpoolZipDirectory);同时在方法里也对一些不能为空的参数族做判断,保证必须参数的存在。

public synchronized void configure(Context context) {
SpoolZipDirectory= context.getString(SPOOL_ZIP_DIRECTORY);
Preconditions.checkState(SpoolZipDirectory!= null, "Configuration must specify a spooling directory");

completedSuffix= context.getString(SPOOLED_FILE_SUFFIX, DEFAULT_SPOOLED_FILE_SUFFIX);
deletePolicy= context.getString(DELETE_POLICY, DEFAULT_DELETE_POLICY);
fileHeader= context.getBoolean(FILENAME_HEADER,DEFAULT_FILE_HEADER);
……
}


2.2、Function--start

获取配置信息后,就可以执行start方法启动source。


2.2.1、在start方法中,首先通过ReliableSpoolingFileEventReader.java中的builder类创建了一个ReliableSpoolingFileEventReader对象。  

try{
reader = new ReliableSpoolingFileEventReader.Builder()
      .spoolDirectory(directory)
      .completedSuffix(completedSuffix)
      .includePattern(includePattern)
      .ignorePattern(ignorePattern)
      .trackerDirPath(trackerDirPath)
...

2.2.2、再创建一个SpoolZipDirectoryRunnable对象,用定时任务启动runnable对象线程。

Runnable runner = new SpoolZipDirectoryRunnable(reader, sourceCounter);
executor.scheduleWithFixedDelay(runner, 0, pollDelay, TimeUnit.MILLISECONDS);

2.3、Thread--run

在线程方法run中,执行ReliableSpoolingFileEventReader对象reader的readEvents方法。批量读取reader中获取的event(在这里,一行数据组织成一个event)。

public void run() {
intbackoffInterval = 250;
try {
while (!Thread.interrupted()) {
      List<Event> events = reader.readEvents(batchSize);
if (events.isEmpty()) {
break;
      }
......

2.4、Funtion--readEvents

在ReliableSpoolingFileEventReader.java的readEvents方法中,主要是获取currentFile,并且通过EventDeserializerFactory(事件并行转换器工厂)选择所需的并行转换类型(LINE或者AVRO或者自定义),将文件中的每行数据并行转换成event list提供读取。

2.4.1、获取当前文件(currentFile),通过getNextFile方法获取当前文件。在getNextFile方法中,主要是通过getCandidateFiles方法获取需要处理的文件列表,根据规则(读取最新/最旧/随机文件),将文件列表中的一个文件作为当前文件(currentFile)来处理。
 
2.4.2、在getCandidateFiles方法中,主要利用了java.nio.files.File.walkFileTree方法,程序不断访问目录,一旦有新文件出现在该目录下,就触发执行visitFile方法,将文件加入文件列表,并返回。

public FileVisitResultvisitFile(Path candidate, BasicFileAttributesattrs) throws IOException {
    String fileName = candidate.getFileName().toString();
if(!fileName.endsWith(ReliableSpoolingFileEventReader.this.completedSuffix) && !fileName.startsWith(".") &&ReliableSpoolingFileEventReader.this.includePattern.matcher(fileName).matches() && !ReliableSpoolingFileEventReader.this.ignorePattern.matcher(fileName).matches()) {
            candidateFiles.add(candidate.toFile());
}
            return FileVisitResult.CONTINUE;
}

2.5、Function--openFile

获取到当前文件(cuurentFile)之后,执行openFile方法。在openFile方法中,首先把文件作为参数,创建了ResettableFileInputStream对象in,这个对象主要保存文件的输入流以及文件读取标记。再把in和deserializerType作为参数,创建了EventDeserializer对象deserializer,deserializer根据传入的deserializerType的类型(LINE/AVRO/OTHER),将文件并行序列化为List<Event>,最终调用readEvents读取。


private Optional<ReliableSpoolingFileEventReader.FileInfo>openFile(File file) {
……
Preconditions.checkState(tracker.getTarget().equals(e), "Tracker target %s does not equal expected filename %s", new Object[]{tracker.getTarget(), e});
ResettableFileInputStream in = new ResettableFileInputStream(file, tracker, 16384, this.inputCharset, this.decodeErrorPolicy);
EventDeserializerdeserializer = EventDeserializerFactory.getInstance(this.deserializerType, this.deserializerContext, in);
return Optional.of(new ReliableSpoolingFileEventReader.FileInfo(file, deserializer));
……


publicenumEventDeserializerType {
    LINE(Builder.class),
    AVRO(org.apache.flume.serialization.AvroEventDeserializer.Builder.class),
    OTHER((Class)null);
private final Class<? extends org.apache.flume.serialization.EventDeserializer.Builder>builderClass;


public class LineDeserializerimplements EventDeserializer {
public Event readEvent() throws IOException {
this.ensureOpen();
        String line = this.readLine();
return line == null?null:EventBuilder.withBody(line, this.outputCharset);
    }
public List<Event>readEvents(intnumEvents) throws IOException {
this.ensureOpen();
LinkedList events = Lists.newLinkedList();

for(inti = 0; i<numEvents; ++i) {
            Event event = this.readEvent();
if(event == null) {
break; }
	events.add(event);
        }
return events;
    }


3、定制开发ZipSource代码流程图

参考了上述的spoolDirectorySource的流程,我重写了一个zipSource。主要实现的功能是,将zip包中的文件,在zip流中做相应处理后,落地成avsc File, 然后再序列化成一个个event。主要的流程图如下。










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值