**### 介绍
生产者-消费者
模型用于解耦生产者与消费者,平衡两者之间的能力不平衡,该模型广泛应用于各个系统中,Hudi也使用了该模型控制对记录的处理,即记录会被生产者生产至队列中,然后由消费者从队列中消费,更具体一点,对于更新操作,生产者会将文件中老的记录放入队列中等待消费者消费,消费后交由HoodieMergeHandle
处理;对于插入操作,生产者会将新记录放入队列中等待消费者消费,消费后交由HandleCreateHandle
处理。
入口
前面的文章中提到过无论是HoodieCopyOnWriteTable#handleUpdate
处理更新时直接生成了一个SparkBoundedInMemoryExecutor
对象,还是HoodieCopyOnWriteTable#handleInsert
处理插入时生成了一个CopyOnWriteLazyInsertIterable
对象,再迭代时调用该对象的CopyOnWriteLazyInsertIterable#computeNext
方法生成SparkBoundedInMemoryExecutor
对象。最后两者均会调用SparkBoundedInMemoryExecutor#execute
开始记录的处理,该方法核心代码如下
public E execute() {
try {
ExecutorCompletionService<Boolean> producerService = startProducers();
Future<E> future = startConsumer();
// Wait for consumer to be done
return future.get();
} catch (Exception e) {
throw new HoodieException(e);
}
}
该方法会启动所有生产者和单个消费者进行处理。
Hudi定义了BoundedInMemoryQueueProducer
接口表示生产者,其子类实现如下
- FunctionBasedQueueProducer,基于
Function
来生产记录,在合并日志log文件和数据parquet文件时使用,以便提供RealTimeView
。 - IteratorBasedQueueProducer,基于迭代器来生产记录,在插入更新时使用。
定义了BoundedInMemoryQueueConsumer
类表示消费者,其主要子类实现如下
- CopyOnWriteLazyInsertIterable$CopyOnWriteInsertHandler,主要处理
CopyOnWrite
表类型时的插入。- MergeOnReadLazyInsertIterable$MergeOnReadInsertHandler,主要处理
MergeOnRead
- MergeOnReadLazyInsertIterable$MergeOnReadInsertHandler,主要处理
表类型时的插入,其为CopyOnWriteInsertHandler
的子类。
- CopyOnWriteLazyInsertIterable$UpdateHandler,主要处理
CopyOnWrite
表类型时的更新。
整个生产消费相关的类继承结构非常清晰。
对于生产者的启动,startProducers
方法核心代码如下
public ExecutorCompletionService<Boolean> startProducers() {
// Latch to control when and which producer thread will close the queue
final CountDownLatch latch = new CountDownLatch(producers.size());
final ExecutorCompletionService<Boolean> completionService =
new ExecutorCompletionService<Boolean>(executorService);
producers.stream().map(producer -> {
return completionService.submit((