首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Spark Core 问题详解(1)

Spark Core 问题详解(1)

背景介绍Apache Spark 是加州大学伯克利分校的 AMP                                Labs 开发的开源分布式轻量级通用计算框架。由于 Spark 基于内存设计,使得它拥有比 Hadoop 更高的性能(极端情况下可以达到 100x),并且对多语言(Scala、Java、Python)提供支持。其一栈式的设计特点使得我们的学习和维护成本大大地减少,而且其提供了很好的容错解决方案。
我们使用 Spark 有超过一年的时间了,现在大部分的批处理任务和机器学习的任务都是运行在 Spark 平台之上。目前生产环境使用的是最新版 Spark1.4.1,运行在 Standalone 模式下,没有运行在 Yarn 上面的原因是希望给机器学习的任务分配更多的内存,用户根据任务需要的 cores 数来抢占机器,避免自己的任务和其他任务运行在同一台机器,有效地隔离任务之间的相互影响。
本文将从 Spark 生产环境中遇到的运维、任务调度、安全的问题出发,分享一下 Master 对 Event                                Log 的管理方式、任务的本地性调度机制、多用户的实现方式以及对 Spark 1.5 的 Tungsten-sort 等的理解。
运维Master 挂掉了,Standby 的 Master 也访问超时升级到 Spark                                1.4.1 之后,发现运行一段时间之后 Master 就会挂掉,而且 Standby 的 Master 也无法访问,一直处于访问超时的状态,最后把 Master 都杀掉,把 zookeeper 里面的状态全部删掉,再启动就好了。通过查看 log,我们发现原来是内存不足导致的。Master 的内存默认配置是 512M 的内存,尝试着把它的内存调大到 2G,发现还是挂,在日志里面发现每次挂的时候,几乎都有同一个任务在跑,仔细观察了一下这个任务,它居然有 300                                多万个 Tasks,在 HDFS 上查看它的 Event log 日志,有好几个 G 的大小。看到这里,果断的把内存调到 10G。
问题倒是解决了,可为什么会是这样呢?从 log 里面它无法完成主从切换的时候,把它杀死最后都是卡在 rebuildUI 这个方法上面了,打开 Master 这个类仔细一看,它会去读取每一行的 event                                log 日志,遇到大任务的时候,这是一个很恐怖的事情。
再继续查看,rebuildUI 方法是在 finishApplication 方法里面调用的,每次有任务完成,它都会把任务的 Event                                log 读到内存当中来,然后在完成列表里面就可以点击看到作业的相关信息,这部分信息原来是保存在 driver 端的。所以需要减少 Master 保存在内存当中的作业的信息,历史任务到 History                                server 当中查看。
对比了 Spark 1.3 的代码,发现 Spark1.3 里也有这个逻辑,为什么 Spark1.3 没有发生这个问题呢?Spark                                1.4 在 UI 上增加了很酷的图表,需要消耗多一点内存也可以理解,但是为什么会多那么多呢?和同事交流得知,升级到 Spark                                1.4 之后,原来的程序在 Shuffle 的时候经常报错,他们就通过调大 partition 数的方法来避免,有的程序一直调整到 10 倍于以前的 partition 数才可以正常运行。partition 数太大还会引发别的问题,Job                                UI 的界面很卡,甚至是打不开,Akka 的线程数也需要调整,默认值是 4。
spark.akka.threads 10
Worker 时不时也会挂掉或者没有心跳,但是出问题的周期要长一点,发现还是内存的原因,把 Worker 的内存调成 1G,并且减少保存在内存当中的 Executor 和 Driver 的信息,默认都是 1000 个。
spark.worker.ui.retainedExecutors 5
spark.worker.ui.retainedDrivers5
当 SQL 遇到 Hive 的 BugSpark 的 jar 包里面自带了一个 Hive 版本,在 Spark                                1.3 版本上遇到 Hive 的 bug,需要把 bug 修改好编译之后才替换掉 Spark 的 jar 包内部的 class 类,非常的痛苦。比如之前遇到一个很严重的问题,在一张分区表上新增列,插入数据之后,发现新增的列查出来全是 NULL,这是 Hive                                0.13 的已知 Bug:

Spark                                1.4 支持使用外置的 Hive 的 Metastore 的 jar 包,这样可以很方便的修改 hive 的代码,而不去影响 Spark 的代码。配置下面的一句就可以使用外置的 hive 的 jar 包了(注意:这里的 jar 包不仅包括 hive 依赖的所有 jar 包,包括 hadoop 的 jar 包。此外还需要把 guava-11.0.2.jar 添加到 SPARK_CLASSPATH 里面)。
spark.sql.hive.metastore.jars=/data/spark-1.4.1/hive/*
由于采用了直接连接 Hive 的元数据库读取元数据的方式,在 Spark1.3 版本上使用 HiveContext 偶尔会发生以下 Hive 的经典问题:
  • DELETEME 表不存在,该问题会导致程序退出。
  • 角色 admin 已存在,该问题会导致程序退出。
  •                                         往 Hive 的元数据库的 Version 表插入一条记录,该问题会导致所有的 Hive 客户端都无法使用!如果该问题发生在夜间,会影响所有的 Hive 例行任务。
在 Spark1.4 版本,上面的问题出现的频率变得很高。这些是 Hive 的问题,但是严重影响了 Spark 的使用。有两种处理方法:
1)采用连接 Hive 的 Metastore 服务的方式读取元数据。
2)修改代码,去掉一些不必要的操作。
  • 修改 ObjectStore 类 verifySchema 的方法,直接返回,禁止它检查 Hive 的版本。
  • 修改 HiveMetaStore 类,删除下面这段代码。
synchronized (HMSHandler.class) {
createDefaultDB(); # 创建默认数据库
createDefaultRoles(); # 创建默认角色
addAdminUsers(); # 创建默认用户
}
3)修改 MetaStoreDirectSql 类的构造方法,删除掉该构造方法里的 120 行之后关于查询数据库的代码。
Streaming 程序已失败,进程不退出用户提交到 Yarn 上的 Spark                                Streaming 程序容易受到别的因素影响而导致程序失败,有时候程序失败之后 driver 进程不退出,这样无法通过监控 driver 的进程来重启 Streaming 程序。推荐将 Streaming 程序运行在 Standalone 模式的集群之上,使用 cluster 部署模式,并启用 supervise 功能。使用这种方式的好处是 Streaming 程序非正常退出之后,Spark 集群会自动重启 Streaming 的程序,无须人为干预。
返回列表