最近我们要在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)
...
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.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代码流程图

847

被折叠的 条评论
为什么被折叠?



