前面一篇讲到了将数据从kafka读到hdfs使用了开源工具camus,既然用到了开源的代码,免不了研究一下实现过程。所以这里分享一下阅读camus代码了解到的一些细节。
前置知识
在讲camus之前,需要提一下hadoop的一些知识。
关于inputFormat
inputFormat类的原型如下:
public interface InputFormat<K, V> {
InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;
RecordReader<K, V> getRecordReader(InputSplit split,JobConf job,Reporter reporter) throws IOException;
}
hadoop job调用setInputFormat
来设置InputFormat类,通过getSplits函数,hadoop可以将输入分割为InputSplit,每个map分配到InputSplit后,再通过getRecordReader获取reader,逐条读取输入文件中Key-Value。hadoop本身提供了一些InputFormat类的实现,如TextInputFormat,KeyValueTextInputFormat,SequenceFileInputFormat等;
除了使用hadoop本身提供的这些类以外,hadoop允许自定义InputFormat类,只需要实现相应的getSplits函数和RecoderReader类即可。
关于OutputFormat 和 OutputCommitter
OutputFormat类用于写入记录,原型如下:
public abstract class OutputFormat<K, V> {
//创建一个写入器
public abstract RecordWriter<K, V> getRecordWriter(TaskAttemptContext context) throws IOException, InterruptedException;
// 检查结果输出的存储空间是否有效
public abstract void checkOutputSpecs(JobContext context) throws IOException, InterruptedException;
//创建一个任务提交器
public abstract OutputCommitter getOutputCommitter(TaskAttemptContext context) throws IOException, InterruptedException;
}
getRecordWriter和checkOutputSpecs都很好理解,前置就是将Mapper或Reducer传来的key-value写入到文件里面,写入的姿势由它来决定。而checkOutputSpecs一般就是用来检查输出规范,判断输出文件是否存在,如果已经存在,则抛出异常。
OutputCommitter稍稍难理解一点,里面定义了这几个方法:
//Job开始被执行之前,框架会调用setupJob()为Job创建一个输出路径
void setupJob(JobContext jobContext);
//如果Job成功完成,框架会调用commitJob()提交Job的输出
void commitJob(JobContext jobContext);
//如果Job失败,框架会调用OutputCommitter.abortJob()撤销Job的输出
void abortJob(JobContext jobContext, JobStatus.State state);
//Task执行前的准备工作,类似setupJob
void setupTask(TaskAttemptContext taskContext);
//Task可能没有输出,也就不需要提交,通过needsTaskCommit()来判断
boolean needsTaskCommit(TaskAttemptContext taskContext);
//Task成功执行,提交输出
void commitTask(TaskAttemptContext taskContext);