Performance is *way* too slow with pubsub push -> app engine.

293 views
Skip to first unread message

Garrett Hunyadi

unread,
Aug 4, 2016, 3:29:09 PM8/4/16
to Google App Engine

Hi.  I have a requirement to process ~20k calls per second. My system processes lists of ~1M entries and performs multiple jobs for each item.  It is very “bursty” in nature as it isn’t always processing a list.  I added a App Engine flex env (with Rails), using automatic scaling, with an test endpoint to wait 5 seconds and return.   I push to the pubsub topic and a push subscription sends to App Engine.   Running this hits a steady state of 20-30 requests per second.  


I guessed that the problem was the interaction of the pubsub push volume algorithm interacting with the App Engine, but then I ran a second test where I just blasted curl requests as in a loop with multiple processes.  This also ran at 20-30 rps.  


I’m stuck at this point and wondering how to proceed. How can I configure the system for higher performance? I need a performance of three orders of magnitude from what I see.


Thanks so much for helping! 


-garrett

Adam (Cloud Platform Support)

unread,
Aug 8, 2016, 12:24:27 PM8/8/16
to Google App Engine
This seems like a good question to also cross-post to Stack Overflow for more visibility. Please see the main Community Support page for a list of the tags we monitor.

Would you mind sharing the details of your app.yaml configuration as a starting point?

Garrett Hunyadi

unread,
Aug 9, 2016, 1:31:12 PM8/9/16
to Google App Engine
It's pretty trivial.  I'm making the app as simple as possible at this point.  I haven't changed the scaling from autoscaling, though I'm going to run some tests to boost the app engine side to force more capacity and see what that does. 

runtime: ruby
vm: true
entrypoint: bundle exec foreman start --formation "$FORMATION"
env_variables:
  FORMATION: web=1

I'll crosspost as well.

Thanks for following up on this Adam!  I was starting to get lonely and cry. ;)

Adam (Cloud Platform Support)

unread,
Aug 12, 2016, 5:09:47 PM8/12/16
to Google App Engine
Since you're only launching one worker process with foreman requests are essentially being handled serially. Try increasing the number of processes to achieve concurrency eg. web=4 or web=8. The number of processes to use depends generally on how CPU intensive your handler is and the number of cores per instance eg. if most of the time spent is blocking on some kind of I/O you can get away with using a much higher value. 

Adam (Cloud Platform Support)

unread,
Aug 12, 2016, 5:26:59 PM8/12/16
to Google App Engine
Edit: I'll say 'resource' intensive as memory consumption for each process matters too!

As a follow up, the App Engine flexible docs say 'an instance can handle multiple requests concurrently' (see 'How Requests are Handled') but this is also dependent on the app server running on each instance ie. the runtime will send requests concurrently but they can still bottleneck if there is only one process per instance to handle them. The configuration is dependent on the server you use (eg. if you use Unicorn you'd set this as 'worker_processes' in config/unicorn.rb etc.)

Garrett Hunyadi

unread,
Aug 15, 2016, 10:42:30 AM8/15/16
to google-a...@googlegroups.com
Adam.  Thanks for your reply, it makes perfect sense.  I’ve used unicorn in the past, but I’m thinking that moving the workload to a background job should achieve the same result.  The endpoint will just add to the task queue and return.  In this case, adding unicorn (etc) would still be reasonable, but not really necessary.   Do you agree with this take?

-garrett

--
You received this message because you are subscribed to a topic in the Google Groups "Google App Engine" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/google-appengine/mzTdRsU2R3k/unsubscribe.
To unsubscribe from this group and all its topics, send an email to google-appengi...@googlegroups.com.
To post to this group, send email to google-a...@googlegroups.com.
Visit this group at https://groups.google.com/group/google-appengine.
To view this discussion on the web visit https://groups.google.com/d/msgid/google-appengine/62de1077-6528-4750-a4db-9d15df945611%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Adam (Cloud Platform Support)

unread,
Aug 15, 2016, 1:57:11 PM8/15/16
to Google App Engine
I think if all your handlers simply kick off async tasks then using a Rack based server like Unicorn isn't really necessary. I'd stick to Foreman but with at least a few worker processes to handle multiple requests. However there are benefits to using a more robust app server if you plan to start implementing more complex handlers in the future.

The Ruby Runtime docs do mention the use of Rack-based servers like Unicorn and give some configuration examples. Puma is generally recommended over Unicorn due to threading support and resilience to "slow client attacks", although the slow client problem is mostly mitigated by App Engine flex's use of Nginx as a buffering reverse proxy.

On Monday, August 15, 2016 at 10:42:30 AM UTC-4, Garrett Hunyadi wrote:
Adam.  Thanks for your reply, it makes perfect sense.  I’ve used unicorn in the past, but I’m thinking that moving the workload to a background job should achieve the same result.  The endpoint will just add to the task queue and return.  In this case, adding unicorn (etc) would still be reasonable, but not really necessary.   Do you agree with this take?

-garrett

To unsubscribe from this group and all its topics, send an email to google-appengine+unsubscribe@googlegroups.com.
To post to this group, send email to google-appengine@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages