WildFly9でHTTP2を試してみる

# はじめに
WildFly9がリリースされてからすでに２ヶ月経ちました。WildFly9の目玉機能の１つとしては、HTTP/2のサポートが挙げられると思います（[リリースノート](http://wildfly.org/news/2015/07/02/WildFly9-Final-Released/)）。HTTP/2では、１コネクション内で複数のリクエスト／レスポンスを同時に処理できるようなりました（HTTP/1.1では基本的に１コネクション＝１リクエスト／レスポンス）。これにより、多くのリソースを必要とするWebページのロード時間を短縮することができます。

本記事では、WildFly9でのHTTP/2の設定方法を解説したのち、実際にHTTP/2とHTTP/1.1のパフォーマンスを検証してみます。

# 検証環境

* OS : OS X Yosemite 10.10.5
* JDK : 8u45
* ブラウザ : Chrome 44

この後でも説明しますが、JDK8以上が必須です。

# WildFlyのセットアップ



## ダウンロード
公式サイトからzipファイルをダウンロードして適当な場所（以下の例では/opt）に解凍します。解凍後のディレクトリ配下をjbossユーザに変更します。

```shell-session
$ cd /opt
$ sudo curl -O http://download.jboss.org/wildfly/9.0.1.Final/wildfly-9.0.1.Final.zip
$ sudo unzip wildfly-9.0.1.Final.zip
$ chown -R jboss wildfly-9.0.1.Final
```

以降、$JBOSS_HOMEは、/opt/wildfly-9.0.1.Final を指すものとします。また、jbossユーザで作業しているものとします。


## ブートクラスパスにALPNを追加
現在、主要なブラウザはTLS（SSL）上でのHTTP/2のみをサポートしています（HTTP/2の仕様上は通常のHTTPも対象）。そのため、HTTP/2を利用するにはサーバ側もTLSに対応する必要があります。ただし、HTTP/2を利用するには、通常のTLSではなく、ALPNと呼ばれるTLS拡張を利用する必要があります。現状、JDK8はネイティブでALPNをサポートしていないため、拡張ライブラリ（jar）をブートクラスパスに追加する必要があります。また、**JDK7より強い暗号方式を持つJDK8が必須です**。

### ALPNのダウンロード
公式サイトよりALPNをダウンロードします。取得するバージョンは実行環境となるJVMのバージョンに依存します。バージョンの対応表は[公式サイト](http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html)にあります。 ダウンロード先は、$JBOSS_HOME/bin とします。

```shell-session
$ cd /opt/wildfly-9.0.1.Final/bin
$ curl -O http://central.maven.org/maven2/org/mortbay/jetty/alpn/alpn-boot/8.1.3.v20150130/alpn-boot-8.1.3.v20150130.jar
```

### standalone.confの設定

$JBOSS_HOME/bin/standalone.conf に以下の行を追加します。これにより、WildFlyの起動時に上記で取得したALPNがブートクラスパスに追加されます。

```text
JAVA_OPTS="$JAVA_OPTS -Xbootclasspath/p:alpn-boot-8.1.3.v20150130.jar"
```

## SSL証明書の作成
JSSEツールのkeytoolコマンドを利用してSSLの証明書を作成します [^1] 。ここではテスト目的なので自己証明書（オレオレ証明書）です。

### 自己証明書の作成
下のコマンドにより、証明書を格納したキーストア $JBOSS_HOME/standalone/configuration/http2test.keystore ファイルが作成されます。

```shell-session
$ keytool -genkeypair -alias http2test -keyalg RSA -keystore /opt/wildfly-9.0.1.Final/standalone/configuration/http2test.keystore -storepass storepass -keypass keypass -dname "cn=localhost, c=JP"
```

## HTTPSコネクタの設定
ダウンロードして解凍したままのWildFlyでは、SSL（HTTPS）を利用することができません。standalone.xmlを編集して、HTTPSコネクタを設定する必要があります。

### standalone.xml の設定

$JBOSS_HOME/standalone/configuration/standalone.xml を編集します。

* ```<security-realms>```セクションに、作成した自己証明書を利用するセキュリティレルムを追加します。

```xml
            <security-realm name="https">
                <server-identities>
                  <ssl>	
                        <!-- この例ではhttp2test.keystore は同一ディレクトリにある -->	    
                        <keystore path="http2test.keystore" relative-to="jboss.server.config.dir" keystore-password="storepass" alias="http2test" key-password="keypass"/>
                    </ssl>
                </server-identities>
            </security-realm>
```
* Web サブシステム（```<subsystem xmlns="urn:jboss:domain:undertow:2.0">``` セクション）に、HTTPSコネクタを追加します。

```xml
                <!-- security-realm属性には、上のsecurity-realmで設定したname属性の値（この例ではhttps）を設定します。-->
                <https-listener name="https" socket-binding="https" security-realm="https" enable-http2="true"/>
```

ちなみに、WildFlyからWebサブシステムが[Undertow](http://undertow.io/)と呼ばれる実装に変わったようです。

## 確認
WildFlyを起動します。

```shell-session
$ /opt/wildfly-9.0.1.Final/bin/standalone.sh
```

ブラウザを立ち上げ、以下のURLを入力します。

```text
https://localhost:8443/
```

自己証明書なので警告が出ますが、トンボみたいなロゴとともに、Welcome to WildFly 9 と表示されればOKです。

# 計測アプリ
計測用のアプリを作成します。計測アプリといっても、WildFlyのロゴを500個表示させるだけの１つのJSPだけです。

## ロゴ
WildFlyのロゴです。トンボに似ている何かです。
[ここ](http://design.jboss.org/wildfly/)から頂きました。。。m(__)m

![wildfly_logomark_64px.png](https://qiita-image-store.s3.amazonaws.com/0/86337/b3b63328-40ec-7972-6ba1-6229e9e7f479.png)

## JSP
```jsp:sample.jsp
<%@ page contentType="text/html;charset=utf-8" pageEncoding="utf-8" %>
<head>
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<title>http2のテストページ</title>
<meta charset="utf-8">
</head> 
<body>
<%
  long current = System.nanoTime();
  for (int i = 0; i < 500; i++) {
%>
	<!-- キャッシュさせないために、パラメータをつけておく -->
	<img src="wildfly_logomark_64px.png?<%=current  + i%>" />
<%
  }
%>
</body>
</html>
```

# 計測結果
HTTP/1.1とHTTP/2のそれぞれで計測用のページを表示した結果は以下の通りになりました。ブラウザはChromeです。

上でも説明していますが、現在の主要ブラウザはSSL（HTTPS）上でのみHTTP/2をサポートしています。そのため、通常のHTTPプロトコルで接続した場合はHTTP/1.1となり、HTTPSで接続した場合はHTTP/2となります。

#### HTTP/1.1
![スクリーンショット 2015-08-16 19.14.36.png](https://qiita-image-store.s3.amazonaws.com/0/86337/812aea5b-5b84-dfe8-0a74-4b8598093f43.png)

#### HTTP/2
![スクリーンショット 2015-08-16 19.14.31.png](https://qiita-image-store.s3.amazonaws.com/0/86337/fe3fada3-23c4-2dfd-a1dc-e98b14dd0505.png)

ページのロード時間は、HTTP/1.1では、約2.9秒。HTTP/2では、約1.3秒となり、HTTP/2の方が2倍以上速度向上していることが分かります。また、Chromeのデベロッパーツールが示すように、HTTP/2では同時に大量の画像をロードしているようです。

# 参考サイト

* WildFly9のリリースノート
http://wildfly.org/news/2015/07/02/WildFly9-Final-Released/
http://www.javadera.com/blog/wildfly-9-final-release-node/ (日本語訳)

* WildFly9でのHTTP2の設定方法
http://undertow.io/blog/2015/03/26/HTTP2-In-Wildfly.html

* WildFlyでのセキュリティレルムの設定方法
https://docs.jboss.org/author/display/WFLY8/Examples

* Keytoolのドキュメント
https://docs.oracle.com/javase/jp/6/technotes/tools/windows/keytool.html

* JettyによるALPNのドキュメント
http://www.eclipse.org/jetty/documentation/current/alpn-chapter.html

* HTTP/2の解説記事
http://codezine.jp/article/detail/8663

* アカマイによるHTTP/2のデモページ
https://http2.akamai.com/demo
HTTP/1.1とHTTP/2のパフォーマンスの差異が視覚的によく分かります。

***

[^1]: OpenSSLを利用する[方法](https://docs.jboss.org/author/pages/viewpage.action?pageId=66322705)もドキュメントに記載されていますが、内容がUndertowの前身のWebサブスシテムのようです。Undertowでの設定方法をご存知の方あれば教えてください。。