-
Notifications
You must be signed in to change notification settings - Fork 6
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Collections API: Use Futures #70
Conversation
By using Futures instead of immediate values we can fetch tiles for multiple layers in parallel, thus speeding up the entire operation as the IO is the most expensive part. This should also help with handling multiple large requests as they are deferred appropriately.
About to take a look at this. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Curious about how the slowdown of 4 parallel requests for the Future-ized version and the previous version. I would guess that you'd still see an increase in performance for the changes in this PR.
That's a curiosity, I'm 👍 on this.
For reference here is and with: Here is and with: These are the files I'm testing with: pr70-futures-sample-requests.zip Most clearly, the initial heavy load time of fetching tiles is significantly reduced, which is great for cold requests, the kind we're likely to have most often. |
Need to review how to use execution contexts for this.
After talking with some of the GT team, I need to learn a bit more about how to properly use Execution Contexts in this setting (based on some painful work on the Raster Foundry team around their tiler). I'll give a report here when I sort things out. |
Ran this script with the nlcd-soils-request-huc8 simultaneously in 4 tmux panes: #!/usr/bin/env ruby
input = ARGV[0].to_s
10.times do
system("/usr/bin/time -p http --timeout=90 :8090/run < #{input} 2>&1 > /dev/null | grep real")
end Here are the results from
And here's this branch:
Seems like this branch is generally faster. The VisualVM output was also pretty interesting -- let me see if I can make a gif of it. |
+1 from me. One thing this doesn't include is the "blocking-dispatcher" suggestion made here http://doc.akka.io/docs/akka-http/10.0.9/scala/http/handling-blocking-operations-in-akka-http-routes.html I think we could probably delay thinking about those changes until we see how this performs without them? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1
I tried the blocking dispatcher stuff like this: diff --git a/api/src/main/resources/application.conf b/api/src/main/resources/application.conf
index e3de9fd..b3f93d2 100644
--- a/api/src/main/resources/application.conf
+++ b/api/src/main/resources/application.conf
@@ -1,3 +1,12 @@
+mmw-dispatcher {
+ type = Dispatcher
+ executor = "thread-pool-executor"
+ thread-pool-executor {
+ fixed-pool-size = 32
+ }
+ throughput = 500
+}
+
geoprocessing {
port = 8090
hostname = "0.0.0.0"
diff --git a/api/src/main/scala/WebServer.scala b/api/src/main/scala/WebServer.scala
index 7a6814c..503e990 100644
--- a/api/src/main/scala/WebServer.scala
+++ b/api/src/main/scala/WebServer.scala
@@ -1,10 +1,10 @@
package org.wikiwatershed.mmw.geoprocessing
+import akka.dispatch.MessageDispatcher
import akka.http.scaladsl.unmarshalling.Unmarshaller._
-import akka.http.scaladsl.server.{ HttpApp, Route }
+import akka.http.scaladsl.server.{HttpApp, Route}
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json._
-
import com.typesafe.config.ConfigFactory
import com.typesafe.scalalogging.LazyLogging
@@ -42,16 +42,21 @@ object WebServer extends HttpApp with App with LazyLogging with Geoprocessing {
} ~
post {
path("run") {
- entity(as[PostRequest]) { data =>
- data.input.operationType match {
- case "RasterGroupedCount" =>
- complete(getRasterGroupedCount(data.input))
- case "RasterGroupedAverage" =>
- complete(getRasterGroupedAverage(data.input))
- case "RasterLinesJoin" =>
- complete(getRasterLinesJoin(data.input))
- case _ =>
- throw new Exception(s"Unknown operationType: ${data.input.operationType}")
+ extractActorSystem { system =>
+ implicit val blockingDispatcher:MessageDispatcher =
+ system.dispatchers.lookup("mmw-dispatcher")
+
+ entity(as[PostRequest]) { data =>
+ data.input.operationType match {
+ case "RasterGroupedCount" =>
+ complete(getRasterGroupedCount(data.input))
+ case "RasterGroupedAverage" =>
+ complete(getRasterGroupedAverage(data.input))
+ case "RasterLinesJoin" =>
+ complete(getRasterLinesJoin(data.input))
+ case _ =>
+ throw new Exception(s"Unknown operationType: ${data.input.operationType}")
+ }
}
}
} and tweaking the configuration with different numbers. Here are the results:
All the numbers seem worse than the default performance. Tweaking them may be useful in certain contexts, but as we don't have a good enough understanding of the different types of dispatchers available and how their parameters affect runtime, I'd lean towards forgoing this for now. I will however wait for @lossyrob to comment on the wisdom of using global ExecutionContext. |
I'm getting caught up in other things, and I don't want to be a blocker. Since this is +1 given that there may be optimizations, perhaps we merge this and write an issue to investigate potential optimizations around EC usage? |
Sounds good to me. I'll make a new release and create the corresponding MMW PR. |
Overview
By using Futures instead of immediate values we can fetch tiles for multiple layers in parallel, thus speeding up the entire operation as the IO is the most expensive part.
Tagging @lossyrob for code review.
Connects #67
Demo
Here are some recorded run times when running a RasterGroupedCount operation for HUC-08 in isolation:
So using the Futures is clearly faster. The total speed is slower when servicing multiple requests though:
Notes
I tested with
nlcd-soils-request-huc8.json
and withnlcd-streams-request.json
and got correct results. Running many of them in parallel took longer, but everything came through in the end:Note that these times are from my local, and not within the VM, which is likely to be a little slower.
I could not reproduce the original issue in #67, wherein a single request "blocked" the machine from accepting others. If there are any recommendations for reproducing it, I can try them, otherwise I think we should proceed with what we have and make a new card if that behavior returns.
Testing Instructions
server