Tuesday, December 8, 2009

Request performance in Java

If you've been following the App Engine Java runtime group, you may have noticed some discussions about performance of the Java runtime. Many of you have complained about hard-to-predict DeadlineExceededExceptions, or unexpectedly slow requests that use a high amount of CPU. These issues often have the same root cause: App Engine is preparing a new instance of your code to respond an incoming request. We call this occurrence a "loading request". Since App Engine provides server resources on demand, there are several reasons why you might experience a loading request:
  1. You just uploaded a new version of your application.
  2. Your application may have gotten no traffic recently.
  3. Your traffic has become high enough to need another JVM to scale.
You can expect that during the course of developing your application, you will often experience the first two scenarios. In comparison, for a production app receiving even a very small but steady amount of traffic, loading requests are relatively infrequent.

As an application developer, you can influence the length of your loading requests by controlling the amount of work done initializing your application and its dependencies. The App Engine team has also been working diligently on the Java runtime to reduce the time spent in loading requests.

First, we're introducing a new class-loading optimization in 1.2.8 called precompilation. Precompilation makes loading requests faster by doing class-loading work ahead of time in the App Engine environment. We've seen significant improvements with precompilation, but we've left it opt-in by default for 1.2.8. You can enable it for your application by adding precompilation-enabled to your appengine-web.xml:
<precompilation-enabled>true</precompilation-enabled>
Second, we've been profiling applications with longer loading requests. Often they include large dependencies like Groovy and JRuby. We're working directly with those teams to improve startup by spotting and reducing unnecessary initialization.

Finally, we're continuing to work on additional startup improvements we hope to unleash on the Java runtime in the future, and make it easier to identify loading requests in application logs. We will continue to pay close attention to performance issues that both Java and Python developers see, both through changes to our APIs and to our service.

For more information on how to understand the performance of your Java applications, check out the set of frequently asked questions we've collected and answered about performance characteristics of the Java runtime. Also check out Max Ross's recent post on the performance of the new != and IN filters in JDO and JPA.

No comments: