Trino是如何调度split的

最近遇到一个性能问题,并发场景下查询性能会有明显下降,根据日志发现同一个split,在不同线程切换之间会有很多时间损耗,比如线程1执行结束这个split, 到线程2开始执行这个split,中间有时会有2秒的空隙,导致这个split的耗时增加,进而导致整个查询的耗时飙升。

因此专门去学习了trino里面调度split的源码,看他是如何运作的。

TaskExecutor

TaskExecutor 里面有一个线程池,专门用来处理split, 每个线程执行一个TaskRunner,而TaskRunner的任务就是一个while循环,不停的尝试从waitingSplits队列里面获取split, 然后执行这个split。这个waitingSplits是一个类,叫做MultilevelSplitQueue,至于split是如何调度的核心逻辑就在这里面。

MultilevelSplitQueue

MultilevelSplitQueue中把所有split分为5个level, 5个level的阈值分别是下面定义的[0, 1, 10, 60, 300]。 含义就是说如果累计运行时间超过1s的任务就会被放到level1,以此类推。然后调用take方法获取split的时候,通过算法计算出目标level,然后从该level中选取优先级最高的split。

levelMinPriority是用来设置不同level之间执行时间分配的,默认是2,意味着level0~level4的时间占比为16:8:4:2:1。levelScheduledTime用来保存每个level的总耗时

take过程

take的核心逻辑如下图,在pollSplit方法中会遍历所有的level,然后根据每个level的总耗时计算出一个比例,选取比例最差的level做为目标level。接着会判断拿出来的这个split优先级是否有更新,如果split的优先级和对应的taskHandle的优先级对不上,那么就会把这个split放回队列再重新take。因为每次split调用process方法后,都会根据调度时间来更新level。

我们尝试打印了每次take时split的优先级,发现跑单个query时,所有的split都在level0, 而4个query并发跑时,就有挺多split在level1和level2,因为这些split的优先级低,被调用的几率更小,因此处理时间也会更长。

Split Run Quanta

这个参数代表每个split每次执行被分配的时间片,默认是1秒。在Driver的process方法中,有个while循环,会判断如果当前split的执行时间超过我们分配的时间,就会跳出循环。

执行结束

split执行结束后,会判断是否finish, 以及是否block, 如果还没结束且没有block, 则重新放入waitingSplits队列中,如果被block了,则需要加一个监听器,当block状态解除时,再放入等待队列。

Split Info

在每个split结束的时候,都会打印对应的split信息,包括这个split的开始时间,执行时间,cpu耗时以及调用了多少次processInternal。对于排查问题还是挺有帮助的,比如有一次查询偶发超时,就是通过这个日志定位到是某个split被卡住,一直没有结束导致查询超时。

相关推荐
失散132 分钟前
分布式专题——46 ElasticSearch高级查询语法Query DSL实战
java·分布式·elasticsearch·架构
程序员鱼皮5 分钟前
为什么下载小电影时,进度总是卡在99%?
java·计算机·程序员·互联网·编程
没有bug.的程序员20 分钟前
分布式链路追踪:微服务可观测性的核心支柱
java·分布式·微服务·架构·wpf
我是华为OD~HR~栗栗呀23 分钟前
华为OD-21届考研-Java面经
java·前端·c++·python·华为od·华为·面试
凤山老林25 分钟前
SpringBoot 启动时执行某些操作的 8 种方式
java·开发语言·spring boot·后端
狼爷41 分钟前
Java 开发必看:UUIDv7 终于标准化了!这次真香🔥(基于 uuid-creator 实战)
java
萤丰信息1 小时前
智慧园区:引领城市未来发展新趋势
大数据·科技·安全·重构·智慧城市·智慧园区
努力搬砖的咸鱼1 小时前
Node.js 和 Java 项目怎么写 Dockerfile
java·开发语言·docker·云原生·容器·node.js
阿无,1 小时前
Java设计模式之装饰者模式
java·开发语言·设计模式
盼哥PyAI实验室1 小时前
序列的力量——Python 内置方法的魔法解密
java·前端·python