Trino 性能优化之异步加载Split

445 阅读2分钟

在Presto中,一个Split就代表一个数据源。Split在Coordinator中被加载生成,然后被调度到worker上具体执行。在加载到调度这个过程中,如果split的个数特别多,会在这个阶段耗时比较严重且占用较多内存。因此Presto提供了异步加载Split的逻辑,就可以并发的边生成边调度Split, 我们以Hive connector为例来进行分析。

HiveSplitManager

Presto的插件功能就是提供一些接口,然后具体的插件需要去继承这些接口并且实现里面的抽象方法。HiveSplitManager就是继承了ConnectorSplitManager,其中最重要的方法就是getSplits, 所有的插件都是通过这个方法来提供splits。

在getSplits方法中,Hive通过访问HMS拿到一个分区的迭代器,并把他作为入参来构造一个BackgroundHiveSplitLoader对象,这个类就是加载Split的主要类,还有个HiveSplitSource与BackgroundHiveSplitLoader搭配使用,主要是用来存放生成的split并把split提供给调度器。构造Split的开始就是调用BackgroundHiveSplitLoader的start方法

BackgroundHiveSplitLoader

start方法中调用addLoaderIfNecessary方法,首先会判断一下并发度,如果超过了设置的并发度上限,则不会再增加并发构造split的线程数。每个线程会去执行一个HiveSplitLoaderTask image.png

image.png 每一个Task具体执行下面的loadSplits方法,会遍历每个分区下面的所有split,并把这个split添加到hiveSplitSource中,完成生产者的职责,如果发现队列加不进去,可能出现队列已经满了等异常,所以又得把这些splits放回待处理集合中。如果这个分区被遍历完了,则会加载下一个分区。具体加载分区就是通过交互HDFS把分区下每个文件映射成构造一个个Split。可以看到在loadSplits方法里面,也会不断的调用addLoaderIfNecessary方法去增加并发度。

image.png

HiveSplitSource

该类中最重要的函数为getNextBatch,调度器也是通过调用这个接口来获取split然后分发到worker中。上面的BackgroundHiveSplitLoader把原始的InternalHiveSplit放到一个异步队列中,然后getNextBatch从这个异步队列中获取到InternalHiveSplit,并对每个InternalHiveSplit进行切分,保证每个split的size小于设置的最大值。然后把切分后的数据块封装为一个个HiveSplit, 最终封装到一个集合中返回。