问题1:
org.apache.spark.shuffle.MetadataFetchFailedException: Missing an output location for shuffle 5
从堆栈日志中可以看出,是BlockStoreShuffleReader在读取Shuffle到磁盘上的数据的时候发生的错误。从源码中可以看出,MapStauts==null才会跑出这个异常,而MapStatus为什么是null是因为Executor挂了:
Executor挂了的原因可能是因为某些个Partition的太大,导致Task处理需要很长时间,从而引起长时间的GC或者JVM崩溃了。Executor lost会爆出Failed to connect host错误。
解决方法有如下几个:
- 增加Partition数量,本人就是通过这种方式解决了
- 判断下是否是数据倾斜,有条件的话,增加Executor的内存
- 使用一些减少Shuffle的算子
问题2:
Spark 拉取HBase数据时,Executor端报错java.net.socketTimeoutExection:
同时HBase的RegionServer端也报错:lease *** does not exist
这两个问题都是超时问题,解决方法如下:
连接HBase的Configuration设置下面两个参数:
conf.setInt("hbase.rpc.timeout",7200000)
conf.setInt("hbase.client.scanner.timeout.period",7200000)//HBase1.1之前为“hbase.regionserver.lease.period”
下面来解释下这两个参数的含义:
hbase.rpc.timeout:
表示一次RPC请求的超时时间,如果超过这个时间,客户端就会关闭socke,服务端就会抛出一个异常:java.io.IOException:Connection reset by peer。由于个人程序中给Spark配置了很多Core,高并发的读给HBase服务端造成了很大的压力,导致请求无法处理发生超时,默认是60000ms
hbase.client.scanner.timeout.period:
专门给Scan设置的一个超时参数。一个Scan根据setCache(***)会分成多个RPC请求去服务端获取数据,而不像Put等其他请求一样是一次性处理完的,所以HBase服务端会引入一个lease机制(租约机制)。
引入这个机制的原因是RegionServer在收到Scan请求的时候,会生成一个全局唯一的scanId,然后构建整个scan体系(这个可以看之前分析Get请求的那篇文章)。后续同一个Scan的RPC请求只要使用相同的scanId就可以继续获取资源。也就是说在整个Scan的过程中,客户端其实都在占用着服务端的资源。如果客户端崩溃了,那么服务端检测到超过了设置的配置时间之后,就会销毁lease并释放Scan所持有的全部资源,客户端再发送RPC请求来之后,相应的lease已经不存在了,就会抛出leaseExecption。
还有一个hbase.client.operation.timeout:
表示除了Scan以外,其他一次数据操作的总的超时时间,数据操作可以是Get、Put、Delete等等,一次操作也可以包含多个RPC请求。
参考:
https://blog.csdn.net/shenxiaoming77/article/details/17914941(HBase客户端超时分析)