Skip to content

Commit f7beae6

Browse files
ajbozarthTom Graves
authored andcommitted
[SPARK-17243][WEB UI] Spark 2.0 History Server won't load with very large application history
## What changes were proposed in this pull request? With the new History Server the summary page loads the application list via the the REST API, this makes it very slow to impossible to load with large (10K+) application history. This pr fixes this by adding the `spark.history.ui.maxApplications` conf to limit the number of applications the History Server displays. This is accomplished using a new optional `limit` param for the `applications` api. (Note this only applies to what the summary page displays, all the Application UI's are still accessible if the user knows the App ID and goes to the Application UI directly.) I've also added a new test for the `limit` param in `HistoryServerSuite.scala` ## How was this patch tested? Manual testing and dev/run-tests Author: Alex Bozarth <[email protected]> Closes #14835 from ajbozarth/spark17243.
1 parent 02ac379 commit f7beae6

File tree

8 files changed

+106
-7
lines changed

8 files changed

+106
-7
lines changed

core/src/main/resources/org/apache/spark/ui/static/historypage.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
* limitations under the License.
1616
*/
1717

18+
var appLimit = -1;
19+
20+
function setAppLimit(val) {
21+
appLimit = val;
22+
}
23+
1824
function makeIdNumeric(id) {
1925
var strs = id.split("_");
2026
if (strs.length < 3) {
@@ -89,7 +95,7 @@ $(document).ready(function() {
8995
requestedIncomplete = getParameterByName("showIncomplete", searchString);
9096
requestedIncomplete = (requestedIncomplete == "true" ? true : false);
9197

92-
$.getJSON("api/v1/applications", function(response,status,jqXHR) {
98+
$.getJSON("api/v1/applications?limit=" + appLimit, function(response,status,jqXHR) {
9399
var array = [];
94100
var hasMultipleAttempts = false;
95101
for (i in response) {

core/src/main/scala/org/apache/spark/deploy/history/HistoryPage.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ private[history] class HistoryPage(parent: HistoryServer) extends WebUIPage("")
4545
<script src={UIUtils.prependBaseUri("/static/dataTables.rowsGroup.js")}></script> ++
4646
<div id="history-summary" class="span12 pagination"></div> ++
4747
<script src={UIUtils.prependBaseUri("/static/utils.js")}></script> ++
48-
<script src={UIUtils.prependBaseUri("/static/historypage.js")}></script>
48+
<script src={UIUtils.prependBaseUri("/static/historypage.js")}></script> ++
49+
<script>setAppLimit({parent.maxApplications})</script>
4950
} else if (requestedIncomplete) {
5051
<h4>No incomplete applications found!</h4>
5152
} else {

core/src/main/scala/org/apache/spark/deploy/history/HistoryServer.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import org.eclipse.jetty.servlet.{ServletContextHandler, ServletHolder}
2828
import org.apache.spark.{SecurityManager, SparkConf}
2929
import org.apache.spark.deploy.SparkHadoopUtil
3030
import org.apache.spark.internal.Logging
31+
import org.apache.spark.internal.config._
3132
import org.apache.spark.status.api.v1.{ApiRootResource, ApplicationInfo, ApplicationsListResource, UIRoot}
3233
import org.apache.spark.ui.{SparkUI, UIUtils, WebUI}
3334
import org.apache.spark.ui.JettyUtils._
@@ -55,6 +56,9 @@ class HistoryServer(
5556
// How many applications to retain
5657
private val retainedApplications = conf.getInt("spark.history.retainedApplications", 50)
5758

59+
// How many applications the summary ui displays
60+
private[history] val maxApplications = conf.get(HISTORY_UI_MAX_APPS);
61+
5862
// application
5963
private val appCache = new ApplicationCache(this, retainedApplications, new SystemClock())
6064

core/src/main/scala/org/apache/spark/internal/config/package.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ package object config {
120120
.intConf
121121
.createWithDefault(100000)
122122

123+
// To limit how many applications are shown in the History Server summary ui
124+
private[spark] val HISTORY_UI_MAX_APPS =
125+
ConfigBuilder("spark.history.ui.maxApplications").intConf.createWithDefault(Integer.MAX_VALUE)
126+
123127
private[spark] val IO_ENCRYPTION_ENABLED = ConfigBuilder("spark.io.encryption.enabled")
124128
.booleanConf
125129
.createWithDefault(false)

core/src/main/scala/org/apache/spark/status/api/v1/ApplicationListResource.scala

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ private[v1] class ApplicationListResource(uiRoot: UIRoot) {
2929
def appList(
3030
@QueryParam("status") status: JList[ApplicationStatus],
3131
@DefaultValue("2010-01-01") @QueryParam("minDate") minDate: SimpleDateParam,
32-
@DefaultValue("3000-01-01") @QueryParam("maxDate") maxDate: SimpleDateParam)
32+
@DefaultValue("3000-01-01") @QueryParam("maxDate") maxDate: SimpleDateParam,
33+
@QueryParam("limit") limit: Integer)
3334
: Iterator[ApplicationInfo] = {
3435
val allApps = uiRoot.getApplicationInfoList
3536
val adjStatus = {
@@ -41,7 +42,7 @@ private[v1] class ApplicationListResource(uiRoot: UIRoot) {
4142
}
4243
val includeCompleted = adjStatus.contains(ApplicationStatus.COMPLETED)
4344
val includeRunning = adjStatus.contains(ApplicationStatus.RUNNING)
44-
allApps.filter { app =>
45+
val appList = allApps.filter { app =>
4546
val anyRunning = app.attempts.exists(!_.completed)
4647
// if any attempt is still running, we consider the app to also still be running
4748
val statusOk = (!anyRunning && includeCompleted) ||
@@ -53,6 +54,11 @@ private[v1] class ApplicationListResource(uiRoot: UIRoot) {
5354
}
5455
statusOk && dateOk
5556
}
57+
if (limit != null) {
58+
appList.take(limit)
59+
} else {
60+
appList
61+
}
5662
}
5763
}
5864

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
[ {
2+
"id" : "local-1430917381534",
3+
"name" : "Spark shell",
4+
"attempts" : [ {
5+
"startTime" : "2015-05-06T13:03:00.893GMT",
6+
"endTime" : "2015-05-06T13:03:11.398GMT",
7+
"lastUpdated" : "",
8+
"duration" : 10505,
9+
"sparkUser" : "irashid",
10+
"completed" : true,
11+
"startTimeEpoch" : 1430917380893,
12+
"endTimeEpoch" : 1430917391398,
13+
"lastUpdatedEpoch" : 0
14+
} ]
15+
}, {
16+
"id" : "local-1430917381535",
17+
"name" : "Spark shell",
18+
"attempts" : [ {
19+
"attemptId" : "2",
20+
"startTime" : "2015-05-06T13:03:00.893GMT",
21+
"endTime" : "2015-05-06T13:03:00.950GMT",
22+
"lastUpdated" : "",
23+
"duration" : 57,
24+
"sparkUser" : "irashid",
25+
"completed" : true,
26+
"startTimeEpoch" : 1430917380893,
27+
"endTimeEpoch" : 1430917380950,
28+
"lastUpdatedEpoch" : 0
29+
}, {
30+
"attemptId" : "1",
31+
"startTime" : "2015-05-06T13:03:00.880GMT",
32+
"endTime" : "2015-05-06T13:03:00.890GMT",
33+
"lastUpdated" : "",
34+
"duration" : 10,
35+
"sparkUser" : "irashid",
36+
"completed" : true,
37+
"startTimeEpoch" : 1430917380880,
38+
"endTimeEpoch" : 1430917380890,
39+
"lastUpdatedEpoch" : 0
40+
} ]
41+
}, {
42+
"id" : "local-1426533911241",
43+
"name" : "Spark shell",
44+
"attempts" : [ {
45+
"attemptId" : "2",
46+
"startTime" : "2015-03-17T23:11:50.242GMT",
47+
"endTime" : "2015-03-17T23:12:25.177GMT",
48+
"lastUpdated" : "",
49+
"duration" : 34935,
50+
"sparkUser" : "irashid",
51+
"completed" : true,
52+
"startTimeEpoch" : 1426633910242,
53+
"endTimeEpoch" : 1426633945177,
54+
"lastUpdatedEpoch" : 0
55+
}, {
56+
"attemptId" : "1",
57+
"startTime" : "2015-03-16T19:25:10.242GMT",
58+
"endTime" : "2015-03-16T19:25:45.177GMT",
59+
"lastUpdated" : "",
60+
"duration" : 34935,
61+
"sparkUser" : "irashid",
62+
"completed" : true,
63+
"startTimeEpoch" : 1426533910242,
64+
"endTimeEpoch" : 1426533945177,
65+
"lastUpdatedEpoch" : 0
66+
} ]
67+
} ]

core/src/test/scala/org/apache/spark/deploy/history/HistoryServerSuite.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ class HistoryServerSuite extends SparkFunSuite with BeforeAndAfter with Matchers
100100
"minDate app list json" -> "applications?minDate=2015-02-10",
101101
"maxDate app list json" -> "applications?maxDate=2015-02-10",
102102
"maxDate2 app list json" -> "applications?maxDate=2015-02-03T16:42:40.000GMT",
103+
"limit app list json" -> "applications?limit=3",
103104
"one app json" -> "applications/local-1422981780767",
104105
"one app multi-attempt json" -> "applications/local-1426533911241",
105106
"job list json" -> "applications/local-1422981780767/jobs",

docs/monitoring.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,17 @@ The history server can be configured as follows:
114114
<td>spark.history.retainedApplications</td>
115115
<td>50</td>
116116
<td>
117-
The number of application UIs to retain. If this cap is exceeded, then the oldest
118-
applications will be removed.
117+
The number of applications to retain UI data for in the cache. If this cap is exceeded, then
118+
the oldest applications will be removed from the cache. If an application is not in the cache,
119+
it will have to be loaded from disk if its accessed from the UI.
120+
</td>
121+
</tr>
122+
<tr>
123+
<td>spark.history.ui.maxApplications</td>
124+
<td>Int.MaxValue</td>
125+
<td>
126+
The number of applications to display on the history summary page. Application UIs are still
127+
available by accessing their URLs directly even if they are not displayed on the history summary page.
119128
</td>
120129
</tr>
121130
<tr>
@@ -242,7 +251,8 @@ can be identified by their `[attempt-id]`. In the API listed below, when running
242251
<br>Examples:
243252
<br><code>?minDate=2015-02-10</code>
244253
<br><code>?minDate=2015-02-03T16:42:40.000GMT</code>
245-
<br><code>?maxDate=[date]</code> latest date/time to list; uses same format as <code>minDate</code>.</td>
254+
<br><code>?maxDate=[date]</code> latest date/time to list; uses same format as <code>minDate</code>.
255+
<br><code>?limit=[limit]</code> limits the number of applications listed.</td>
246256
</tr>
247257
<tr>
248258
<td><code>/applications/[app-id]/jobs</code></td>

0 commit comments

Comments
 (0)