A week ago, I’ve been at one of the best tech conference in my area: Voxxed Days Ticino 2015 (https://voxxeddays.com). The first speach I’ve followed had Simone Bordet (@simonebordet), @JettyProject committe, presenting something relatively new to me: HTTP/2. The new generation king-protocol is quite new but, with my surprise, I discovered it is in use nowadays by some Big of Internet: YouTube, GMail and many other already offer their content over HTTP/2.
I felt quite old-fashioned HTTP/1.1, the sensation of be in late (for I don’t know which reason) started to flow in my brain so I decided to give HTTP/2 a try. More than a try.
I immediately discovered that all technologies I use today do not currently support HTTP/2: neither Tomcat, neither Apache Httpd, neither JBoss (EAS). Currently, only Jetty, Undertow and Netty support HTTP/2 in the Java ecosystem (more info here: https://github.com/http2/http2-spec/wiki/Implementations)
My 99% of work is Magnolia CMS releated, so I decided to see (and to measure) how Magnolia CMS behaves on HTTP/2. So I decided to adopt Jetty, I already used it in ancient 2008, with Magnolia 3.6.8 (STK was a dream and we were used to play with pure JSP!).
The journey is not so easy: Jetty documentation is not so.. exact. Probably Jetty team need to rewrite some tutorial. Even Jetty Maven plugin lacks on documentation, but.. let start!
N.B.: everything is tracked on my Github account: fork it!
The first step is to have a working setup: using Magnolia archetypes, create a new Magnolia project:
mvn archetype:generate -DarchetypeCatalog=https://nexus.magnolia-cms.com/content/groups/public/
follow the on-screen istruction (more info here) and you will end up with a tree like this:
Now lets tune it up a little. We need Java8. Yes, HTTP/2 only works with Java8 because of its internal cypher requirements. And UTF-8, of course. This needs to be changed on parent pom.xml:
We also want to test some Magnolia page, without (lazyness!!) create it. So, we need to enable the bundle webapp (not the empty one) since it is shipped with STK module (templates, pages, apps..). Just update webapp pom.xml, changing the war and pom dependencies:
Now, we want a “stable-but-simple” environment. Magnolia, by default, installs local repository on a filesystem folder inside the webapp itself. If you close Jetty, the webapp will be destroyed, so we need to keep the repository outside. Just create a magnolia.properties file in webapp source files (here: /magnolia-jetty-webapp/src/main/webapp/WEB-INF/config/default/magnolia.properties) and define the following key-property:
Now, we need a little Jetty configuration. We are using Jetty 9.3.0 M2
OK, let’s run Jetty. No way! mvn jetty:run does not work. Exception is “Unable to find repositories.xml”. That’s true! Jetty by default uses .war approach to serve its modules. It means: nothing will be exploded. But Magnolia needs to be exploded, since its Jackrabbit friend need a local filesystem support. So, proceed with mvn jetty:run-exploded. This is critical and will help also later to understand how to deal with HTTP/2. Now we have (we should!) Magnolia running on HTTP1/1 with Jetty in a Maven-based project. What follows is quite experimental and can be summarized in this step-by-step summary:
- Generate a self-signed certificate (keystore). Yes, HTTP/2 requires (it is mandatory) a TLS connection
- Enable ALPN boot: this will support additional classes to be available in Jetty config
- ALPN boot needs to be called as JVM arguments. Jetty, in order to pass arguments to JVM, need to be called with jetty:run-forked. Unfortunately, this mode does not currently support exploded wars, so Magnolia won’t simply start. The only one solution is to force ALPN boot to be run with additional maven parameters
- HTTP/2 must be enabled in Jetty config
I will skip here info on how to generate a self-signed certificate, since it is out of scope. ALPN must be declared as Maven dependency. This will allow Maven to download it locally and to invoce through JVM arguments. Be careful: yuu must choose ALPN version according to your current Java8 version. A mapping table can be found on Jetty documentation, here. As mentioned, Maven must be called with this additional JVM parameter:
NB: if you want to try a simple webapp (HelloWorldHTTP2.war), you can simply use mvn jetty:run-forked adding this as a new configuration entry:
Now what is missing is to enable HTTP/2 on Jetty config. This can be easily done replacing ssl config of the previous installation with HTTP/2 specific settings:
And.. run it! Here an extract from the Maven console log:
Ok, cool. But are we sure we are on HTTP/2? Yes.
And what about performances? Quite hard to tell without a real project: we are in localhost, no network lag in the middle.. but.. lets have a quick closer look:
Demo Project with HTTP1/1: page transferred in 543ms
Demo Project with HTTP2/2: page transferred in 242ms.
I repeatedly tested it and I can confirm, with HTTP/2 we gain from 40% to 60%.
- HTTP/2, with its “tunnels” of streams, will significantly reduce transfer time.
- The protocol of the future is here and since any gained byte is a happier user, we need to start to think about it (migrate existing projects? at what cost?)
- Browser support is limited to Google Chrome 40+ and Firefox 36+.
- Server support is.. embarassing. Only Jetty can be a valid alternative. Tomcat, c’mon! Wake up..
Everything is on Github: again, go and fork it!