这段时间在和客户一起优化查询慢的问题,发现大量 SQL的查询性能不达标是因为 HDFS 慢节点的问题。有时候整个 IO 性能会差到,拉 200KB 的数据能花 1分钟,这直接导致一个 OLAP 数据库的性能和 Hive 差不多。
但是有一个奇怪的现象,客户用 Presto 查并没有这个问题,只有用 StarRocks 查询才会遇到,而且整个查询耗时忽快忽慢。当客户事后去复盘慢查询的 SQL时,又基本很难复现,因为那会 HDFS 可能又不拉跨了,这让整个问题定位的过程变得非常棘手。
当然出现慢节点,我们也不能一口气甩锅给客户的环境,毕竟 Presto 不是查的好好的?
慢节点产生的原因
慢节点不是凭空产生的,别全赖用户头上,有时候也得检讨一下自己的问题。
我简单的整理了下出现慢节点的原因:
- 读取数据量多:比如你的谓词下推没有充分利用 ORC、Parquet 的索引,导致数据多读。那数据都读的多了,慢岂不是理所应当。
- IO 次数多:虽然你可能读的数据总量和 Presto 差不多,但是因为你的 IO 次数多,那么连到烂 DataNode 的概率势必也高,也容易出现慢节点。
- 请求的数据范围横跨多个 HDFS Block:比如你请求一个文件的 50MB~150MB 范围的数据,假设 HDFS 是按照 128MB 一个 block 划分,你这个范围的请求会涉及到两个 Block。站在应用层的角度,你以为你只发起了 1 次 IO请求,但是在 HDFS client 的源码实现上,其实你向 DataNode 发起了两次请求,每一个请求分别处理一个 Block。所以你会发现 Trino/Impala 的文件 split 切分算法,都是基于 HDFS 的 Block 来切分的,而不是按照整个文件的大小进行切分。这也是为什么 ORC、Parquet 都会让自己的 Stripe、RowGroup 都按照 HDFS 的 Block 大小进行对齐。
- 就是慢:当你发现读取的数据量和 Presto 差不多,IO 次数自己摸良心也觉得差不多,但还是慢。那这也真没啥办法,就是那会你运气不好,连的 DataNode 拉胯。
上面四点原因中,只有第四点是客户环境的问题,其余的都是自己的问题。下面我们讲讲如何解决“就是慢”的问题。
“就是慢”的解决办法
针对慢节点可以有两个解决办法:
Hedged Read
可以通过在 HDFS Client 客户端开启 hedged read 功能来避免慢节点。Hedged read 的原理很简单,就是当向一个 DataNode 发起的请求在规定时间内没有返回,那就向另外一个 DataNode 发起一个新请求。然后取两次请求中返回快的结果。
Hedged read 由 hdfs-site.xml
里面的 dfs.client.hedged.read.threadpool.size
和 dfs.client.hedged.read.threshold.millis
两个参数控制:
参数 | 说明 |
---|---|
dfs.client.hedged.read.threadpool.size | Hedged read 线程池大小,默认是 0,表示不开启。 你可以配置任意一个大于 0 的数字。 |
dfs.client.hedged.read.threshold.millis | Hedged read 超时阈值,当请求耗时超过这个时间, 则向一个新的 DataNode 发起一个新的请求。 |
不过你以为 hedged read 是万金油?那就大错特错了。
我在之前的文章里面《HDFS Hedged Read 的利弊分析》分析过,hedged read 因为实现上的挫,它保底要消耗多一倍的内存。期间如果超过阈值发起了 hedged read,那就是两倍。
此外你的 hedged read 线程池怎么规划呢?像现在的 OLAP 系统,IO 并发玩的都是大力出奇迹。以 StarRocks 为例,假设一台机器是 64 核,那么其 DOP = 32,然后每个 pipeline 最多有 16 个 IO 线程。也就是说 StarRocks 在单台机器上面,最多同时能发起 512 个 IO 线程。
如果你的 hedged read 线程池不够大,那些进不去线程池的 IO 请求,没有重试机会,该慢还得慢,然后成为整个查询的短板。
线程池的大小计算非常简单,hedged read 的所有请求都是在它的线程池里面进行。比如 StarRocks 同时发起了 512 个 IO 请求,那么此时 hedged read 线程池里面保底就有 512 个线程了。如果有些 IO 请求因为超过了阈值,发起了第二次请求,那么该 IO 请求在 hedged read 线程池里面则占两个位置,也就是理论上你得规划个容量为 1024 的线程池才够用。
判断线程池够不够用很简单,HDFS client 里面的 hedgedReadOpsInCurThread
指标就表示有多少个 IO 请求是没进到 hedged read 线程池的。
此外如果你第一次 IO 请求的 DataNode 慢,然后又连了一个新的 DataNode,还是慢,咋办?没办法,干等,两个矮子里面拔高个。Hedged read 最多只会向两个 DataNode 发起 IO 请求。不过可别忘了,你的 HDFS 可有三副本呢!相当于另外一个副本用不上。
IO 请求快速 timeout
这招是本次在客户那里灵验的一个方法,非常有效果。
既然你的 DataNode 慢,那我就调短和 DataNode 连接的超时时间,你要是一时半会返回不了,就立刻 timeout,然后 HDFS client 会转而向另外一个新的 DataNode 发起请求。
hdfs-site.xml
里面的dfs.client.socket-timeout
参数则控制了 HDFS client 和 DataNode 的通讯超时时间。默认值是 60000
,单位是毫秒。这太大了,在 OLAP 这种要求秒级返回的系统里面,这个 60 秒超时是不可接受的。
那这个值设置成多少合适呢?其实 OLAP 系统一般不会涉及到大 IO 的请求,一次 IO 基本都是在 0~10MB 之间(我个人的经验之谈)。当然 Text 格式除外,因为这个就取决于你的系统实现了。不过 SR Text 格式最大单次 IO 请求也就 16MB,Trino 的 Text 则是 1MB。
所以你自己评估下,一次 IO 拉这么点数据,大概多久就够了呢?我个人觉得一般这个值设置个 5s 就差不多了。
当然你去翻看一下 Trino 的源码,你会发现它还 hard coding 了一些其他的 timeout 参数,不过在客户那里测过,没啥效果。
下面这几个参数是 Trino 额外 hard coding 的,配置在 core-site.xml
里面的参数,仅供参考。主要是控制 Client 和 NameNode,DataNode RPC 请求的参数,大家可以根据自己的心情选择性进行配置。
参数 | 说明 | 默认值 | Trino hard coding 值 |
---|---|---|---|
ipc.client.connect.timeout | Indicates the number of milliseconds a client will wait for the socket to establish a server connection. | 20000 | 500 |
ipc.ping.interval | Timeout on waiting response from server, in milliseconds. The client will send ping when the interval is passed without receiving bytes, if ipc.client.ping is set to true. | 60000 | 10000 |
ipc.client.connect.max.retries | Indicates the number of retries a client will make to establish a server connection. | 10 | 5 |
总结
总的来说,要避免慢节点,核心还是先优化你的代码吧。至于 HDFS client 侧的 dfs.client.socket-timeout
参数,那则是解决问题的最后临门一脚。
最后揭秘一下 Presto 快的原因,因为客户在 Presto 里面配置了 hive.dfs-timeout=5s
,然后这个参数其实就是等同于 hdfs-site.xml
里面的 dfs.client.socket-timeout=5000
,相当于变相修改了 timeout 时间。
关于这个参数,我看了眼 Trino 的 commit 记录,一开始他们是 hard coding 了 10s,不过后面又改回了默认值 60s,具体原因见 commit 链接。
有一说一,你的坑,Trino 早就趟过了,你爸爸终究是你爸爸。每一个不起眼的配置,都是前人的智慧。
原创文章,作者:Smith,如若转载,请注明出处:https://www.inlighting.org/archives/hdfs-slow-datanode-solution
评论列表(3条)
you are truly a just right webmaster The site loading speed is incredible It kind of feels that youre doing any distinctive trick In addition The contents are masterwork you have done a great activity in this matter
@Halle Grady:thks
niubi le smith