Knight-Wu / articles

博客
3 stars 1 forks source link

Exception: Spark driver throw CommonTree ClassNotFoundEx, Executor throw block not have enough number of replicas #10

Closed Knight-Wu closed 6 years ago

Knight-Wu commented 6 years ago

记录一下这个排查了挺久的生产hive集群跑批问题, 使用场景是hive on spark, hive版本是2.2, 使用的原生社区的版本, spark版本是1.6, 使用的是cdh的spark. 大致场景是hive on spark每天晚上跑批的时候, 集群高峰时段偶尔会有任务卡主, 然后超时被我们的调度系统杀掉, 影响跑批的进度

  • 现象
    1. yarn logs收集到driver端的日志, 报错是 commonTree classNotFound exception 1 2

然后因为有部分task没有完成, 导致下一个stage没能开始, 这个job就一直卡住了.

  1. 同一时间在executor上面报了如下异常, executor日志如下, 这个日志跟上面driver端的时间不一样, 因为这后面写这篇文章的时候, 截图比较乱了, 没有找到完整一个job的所有异常截图. 图3

因为hdfs写文件的时候, 当client把最后一个block 提交到dn之后, 最后通过 DFSInputStream.close() 去关闭连接, 会轮训请求nn 进行一系列的检查, 包括文件副本最小数必须大于1(默认配置), 否则抛出异常给client. 同时namenode日志如下: 4

  1. datanode的日志还需找下, 记得是同时报了管道破裂等IO错误.
  1. 针对executor写datanode报错, IO层面的异常就比较难排查了, 暂且想到了几个优化集群的方案.

  2. 根据图3的异常, 看了下源码, completeFile的时候会检查block的最小副本数是否达到, 客户端会轮询等待nn, 根据后续block 结束completeFile的时间(大概有二十几秒), 增加了retry次数之后, 后续的达不到最小副本数的异常有所减小, image

但是仍然出现异常, 故想到写pipeline的dn失败时,重试其他dn, 故找到以下配置: image

dfs.client.block.write.replace-datanode-on-failure.policy, 这个配置的解释一开始没看懂n这个参数( let n be the number of existing datanodes), 后面参考了这篇文章, http://blog.cloudera.com/blog/2015/03/understanding-hdfs-recovery-processes-part-2/, 应该是集群中现有的dn的数量,如果是default则按照公式进行计算, 如果是always, 每次都新加一个dn到pipeline中.

dfs.client.block.write.replace-datanode-on-failure.best-effort, 再说一下这个配置, 一开始也是没看懂, 也是根据"understanding-hdfs-recovery-processes-part-2", 这篇文章才理解的, 假设这个参数是false, 如果作为replacement的dn也写失败的话就会直接抛出异常, 终止重试; 如果设为true, 则假设replacement的dn也写失败, 仍然会找新的dn去重试.

所以我们想要的是反复重试新的dn, 直到客户端发起completeFile请求时, 轮询nn超时, 故把dfs.client.block.write.replace-datanode-on-failure.policy设置为always, dfs.client.block.write.replace-datanode-on-failure.best-effort设为true, namenode的block state change的日志级别调成debug, 再观察后续出现写异常的时候是否有重试其他dn.

Knight-Wu commented 6 years ago

用stackEdit直接编译路径中的文章了