Servlet 4.0 で始める HTTP/2 日本オラクル株式会社クラウド テクノロジー事業統括 Fusion Middleware 事業本部セールスコンサルタント柳原伸弥 Java Day Tokyo 2017 2017 年 5 月 17 日
Safe Harbor Statement The following is intended to outline our general product direction. It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, and timing of any features or functionality described for Oracle s products remains at the sole discretion of Oracle. 2
アジェンダ 1 2 3 4 5 Servlet 振り返り Servlet 4.0 概要 Servlet 4.0 Server Push API Server Push 利用時のネットワーク状況 Server Push ユースケース 3
アジェンダ 1 2 3 4 5 Servlet 振り返り Servlet 4.0 概要 Servlet 4.0 Server Push API Server Push 利用時のネットワーク状況 Server Push ユースケース 4
Servlet Servletの基本 サーバサイドで動作するJava Webコンテナにより呼び出されるクラス javax.servlet.http.httpservlet HTTPリクエストにより処理を実施 (GET/POST/ ) Controller としての役割 計算処理やデータベースアクセス等 画面描画用のデータを生成 HTTPリクエスト GET/POST/ HTTPレスポンス HTML/XML/ サーバサイド Java Servlet 5
Servlet History Servlet の機能拡張の変遷 バージョンリリースプラットフォーム内容 2.3 2001/8 J2EE 1.3 Filter 機能 2.4 2003/11 J2EE 1.4 web.xml への XML Schema 利用 2.5 2005/9 JavaEE 5 Annotation サポート ( リソース注入 ) 3.0 2009/12 JavaEE 6 非同期 Servlet, Annotation 利用によるEoD, プラガビリティ 3.1 2013/5 JavaEE 7 ノンブロッキング I/O API, プロトコルアップグレード (WebSocket) 4.0 2017/7 予定 * JavaEE 8 HTTP/2 対応 * Servlet 4.0 現状 2017/4/20 5/20 : パブリックレビュー 2017/5/23 6/5 : パブリックレビュー投票 [JSR-000369 Java Servlet 4.0 Specification] https://jcp.org/aboutjava/communityprocess/pr/jsr369/index.html 6
HTTP/2 概要通信効率を向上するHTTPの新規格 リリースバージョン内容 1991 年 HTTP/0.9 GET のみ ヘッダ / レスポンスコードの規定もなし 1996 年 HTTP/1.0 RFC1945: POST 等のメソッド追加 レスポンスヘッダの追加 1999 年 HTTP/1.1 RFC2068: Keep-Alive やパイプライン化をサポート 2015 年 HTTP/2.0 RFC7540: HTTP/1.1 との互換性保持 通信効率向上の機能サポート HTTP/1.1 TCP コネクション HTTP/2 TCP コネクション リクエスト レスポンス ストリーム 7
HTTP/1.1の欠点とHTTP/2の特長 Web 高速化のための機能 HTTP/1.1 の欠点 原則として 1 つのリクエストの完了を待ってから 次のリクエストを送信 HTTP パイプラインを使用する場合の Head-of-Line Blocking の発生 HTTP/1.1 の Web 高速化の取り組み CSS スプライト インライン イメージ ドメイン シャーディング Blocking HTTP/2 の特長 ストリーム ( リクエスト / レスポンス ) の多重化 ストリーム優先度 Server Push ヘッダー圧縮 バイナリー フレーム 1 TCP 接続 push 8
Servlet 4.0 HTTP/2 対応 Server Push クライアント リクエストを待たないサーバ レスポンス プロトコルネゴシエーション ALPN (Application-Layer Protocol Negotiation) JDK 8 による ALPN サポート HTTPリクエスト GET/POST/ Push Push Push HTTPレスポンス HTML/XML/ Servlet 4.0 9
アジェンダ 1 2 3 4 5 Servlet 振り返り Servlet 4.0 概要 Servlet 4.0 Server Push API Server Push 利用時のネットワーク状況 Server Push ユースケース 10
Server Push 処理 API PushBuilder インターフェース <interface> HttpServletRequest + newpushbuilder(): PushBuilder : PushBuilder pushbuilder = request.newpushbuilder(); <interface> PushBuilder + method(string method): PushBuilder + querystring(string querystring): PushBuilder + sessionid(string sessionid): PushBuilder + setheader(string name, String value): PushBuilder + addheader(string name, String value): PushBuilder + removeheader(string name): PushBuilder + path(string path): PushBuilder + push(): void + getmethod(): String + getquerystring(): String + getsessionid(): String + getheadernames(): Set + getheader(string name): String + getpath(): String 11
Server Push 基本シーケンス一般的な処理フロー 1. ServletPath へリクエスト 2. HTTP リクエストから PushBuilder を取得 3. index.html が参照するリソースを PushBuilderに設定 4. pushを起動 5. 3. と4. を必要に応じて繰り返す Client 1 GET /index bootstrap.css Servlet :PushBuilder 2 request.newpushbuilder() 3 path( bootstrap.css ) push() 4 path( bootstrap.js ) 5 push() 6. HTTP レスポンスを返す bootstrap.js Index.html 6 12
Servlet 4.0 Server Push コードサンプル (1/3) 基本的な Server Push 実装例 @WebServlet(name = "ServerPush", urlpatterns = {"/index"}) public class ServerPush extends HttpServlet { @Override protected void doget(httpservletrequest request, HttpServletResponse response) throws ServletException, IOException { PushBuilder pushbuilder = request.newpushbuilder(); Server Push の宛先対象となるリクエストから PushBuilder オブジェクトを取得 13
Servlet 4.0 Server Push コードサンプル (2/3) 基本的な Server Push 実装例 if (pushbuilder!= null) { } pushbuilder Server Push 対象のリソースを示す URI を指定.path("bootstrap/css/bootstrap.min.css").push(); Server Push を invoke pushbuilder : PushBuilder オブジェクトは.push(); 再利用可能 14
Servlet 4.0 Server Push コードサンプル (3/3) 基本的な Server Push 実装例 response.setcontenttype("text/html;charset=utf-8"); RequestDispatcher disp = request.getrequestdispatcher("index.html"); disp.forward(request, response); } Server Push とは非同期に index.html へフォワード 15
アジェンダ 1 2 3 4 5 Servlet 振り返り Servlet 4.0 概要 Servlet 4.0 Server Push API Server Push 利用時のネットワーク状況 Server Push ユースケース 16
Servlet 4.0 Server Push API 説明 PushBuilder PushBuilder 説明事前リクエストに関連するレスポンスを先行送信する予約リクエストを作成する PUSH_PROMISE: Pushするための予約リクエストヘッダと レスポンスのためのストリームを予約予約リクエストは キャッシュ可能 かつ 安全 なメソッドとして定義 RFC 7540: Hypertext Transfer Protocol Version 2 (HTTP/2) 8.2. Server Push 初期化時は以下の状態となり キャッシュ可能 かつ 安全 な状態メソッド : GET リクエストヘッダから以下を除去 Conditional headers : [If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since], Range headers, Expect headers, Authorization headers, Referrer headers 17
Servlet 4.0 Server Push API 説明 HttpServletRequest.newPushBuilder newpushbuilder default PushBuilder newpushbuilder() 説明 HTTPリクエストからPushBuilder インスタンスを生成次のServer Push を利用できない場合に null を返す現在のコネクションがServer Push をサポートしていない場合クライアントがHTTP/2 SETTINGS フレームでSETTINGS_ENABLE_PUSH の値を0で設定している場合リターン PushBuilder オブジェクト又は null 18
Servlet 4.0 Server Push API 説明 PushBuilder.path path PushBuilder path(string path) 説明 Pushする対象のURIを設定するパラメータ path: push 対象のリソースを示すURI / から始めた場合は 絶対パスとして処理 / から始めない場合は 事前リクエストのコンテキストパスに対する相対パスとして処理リターンこの PushBuilder オブジェクト 19
Servlet 4.0 Server Push API 説明 PushBuilder.addHeader addheader PushBuilder addheader(string name, String value) 説明 Pushする対象のリクエストヘッダを追加するパラメータ name: ヘッダ名 value: ヘッダ値リターンこの PushBuilder オブジェクト 20
Servlet 4.0 Server Push API 説明 PushBuilder.push push void push() 説明設定されたリソースをPushする クライアントがHTTP/2 によるPush 配信を拒否できるため リソースが実際にPushされるかは保証しない push メソッド実行後 設定したリソースのURIと Conditional Header はクリアされる それ以外の設定は維持されるため 別のPush 実行に再利用できる path() によるURI 設定は push メソッド実行前に必須である 設定のない場合 IllegalStateException が発生する 21
Servlet 4.0 Server Push API 説明 PushBuilder.method method PushBuilder method(string method) 説明 Pushする際のHTTP メソッドを設定するパラメータ method: HTTP メソッド PushBuilder 生成時にGETが設定されているため 特に設定する必要はないまた キャッシュ不可かつ非安全なメソッド [POST, PUT, DELETE, CONNECT, OPTION, TRACE] を設定したり 空設定の場合は IllegalArgumentException が発生するリターンこの PushBuilder オブジェクト 22
Servlet 4.0 Server Push API 説明 PushBuilder.queryString querystring PushBuilder querystring(string querystring) 説明 path(string) で設定したURIに対してクエリ文字列を追加する path(string) でクエリ文字列を追加したURIを設定している場合は実施しなくてもよい Push 対象のリソースがCache Busting 対応されているような場合などに利用パラメータ querystring: push 対象のリソースURIに対して追加するクエリ文字列リターンこの PushBuilder オブジェクト 23
アジェンダ 1 2 3 4 5 Servlet 振り返り Servlet 4.0 概要 Servlet 4.0 Server Push API Server Push 利用時のネットワーク状況 Server Push ユースケース 24
HTTP/1.1 及び HTTP/2 のネットワーク状況確認一般的なコンテンツアクセス時のネットワーク クライアント サーバ リクエスト レスポンス HTML CSS JS 25
ネットワーク状況確認 (HTTP/1.1) 従来 (HTTP/1.1) の一般的なページ表示 オレンジ色の箇所は TCP 接続の確立 複数個所で TCP 接続フェーズが発生 26
ネットワーク状況確認 (HTTP/2) Server Push なしの HTTP/2 アクセス オレンジ色の箇所は TCP 接続の確立紫色の箇所は SSL の確立 同時にリソース要求が発生 27
ネットワーク状況確認 (HTTP/2) Server Push を実施した HTTP/2 アクセス 非同期に指定リソースが Server Push される 28
HTTP/1.1 及び HTTP/2 のネットワーク状況確認一般的なコンテンツアクセス時のネットワーク クライアントフロントサーババックエンドサーバ リクエスト リクエスト レスポンス レスポンス HTML CSS バックエンド処理 JS 29
ネットワーク状況確認 (HTTP/1.1) サーバ内処理時間 : 1000ms バックエンド処理終了後に受信したレスポンスからリソース取得要求 バックエンド処理実施中が終了した後に リソース要求が発生 ページのレンダリングに遅延が発生する 30
ネットワーク状況確認 (HTTP/2) サーバ内処理時間 : 1000ms DOM ツリー組み立て前にリソース取得済み バックエンド処理実施中に指定したリソースが Server Push されている ページのレンダリングを行う際にはリソース取得済みの状態 31
アジェンダ 1 2 3 4 5 Servlet 振り返り Servlet 4.0 概要 Servlet 4.0 Server Push API Server Push 利用時のネットワーク状況 Server Push ユースケース 32
スタイルシート /JavaScript CSS や JavaScript の連結ファイル準備の軽減 HTTP/1.1 CSS/JavaScript ファイル数削減による HTTP リクエスト数の削減 複数のスタイルシートを単一ファイル化 複数の JavaScript を単一ファイル化 課題 単一ファイル化に要する作業 モノリシック化による再利用性の低下 HTTP/2 複数の CSS / JavaScript をプッシュ PUSH PUSH CSS CSSCSS CSS CSS CSS CSS JS JS JS JS 連結ファイルの準備が必要 HTTP/2 JS JSJS Web ページ要求時にプッシュ 33
画像ファイル CSS スプライトからの代用 HTTP/1.1 画像ファイル数削減による HTTP リクエスト数の削減 複数の画像ファイルを連結 CSS を利用した座標指定による表示 課題 画像ファイルの連結に要する作業 CSS による Position 指定の複雑さ 画像ファイルの更新 HTTP/2 個別の画像ファイルをプッシュ CSS.item a { display: block; width: 240px; height: 40px; background-image: url('sprite.png');}.item01 a {background-position: 0px 0px;}.item01 a:hover {background-position: 0px -40px;}.item01 a:active {background-position: 0px -80px;}.item01.current a {background-position: 0px -120px;} : HTTP/2 PUSH PUSH 連結した画像ファイル CSS スプライトの工夫が必要 個別ファイルをプッシュ 34
画像ファイルインラインイメージからの代用 HTTP/1.1 画像ファイルインライン可による HTTP リクエスト数の削減 data URI scheme (data:) による画像指定 Base64 エンコードによる画像の文字列化 課題 data URI scheme の画像はキャッシュ不可 Base64 エンコードによるサイズ増加 画像ファイルの変更時のデータ差し替え HTTP/2 Server Push した画像はキャッシュ可 HTML <img src= "data:image/png;base64,ivborw0kggoaaaa NSUhEUgAAAeAAAAHgCAIAAADytinCAAAAYX puwhrsyxcgchjvzmlszsb0exbliglwdgmaahj apyq7eyawdmv6t8ei+cjpzjhcaogo2p8ifeinctl 53dO2j57Wk8bgKCx " /> HTML 内に Base64 エンコードした画像を埋め込み HTTP/2 PUSH Server Push により画像ファイルのキャッシュ利用可 35
JSP サーバ内処理時間中の Server Push サーバ内処理時間 DBアクセスなどのバックエンド処理 プリコンパイルを行わない場合のサーブレット変換及び初期化処理 待機時間を利用したServer Push サーバ内処理中に表示対象の JSPが利用するリソースをプッシュ リクエスト PUSH PUSH PUSH レスポンス サーバ内処理時間 Servlet RequestDispatcher.forward() JSP バックエンド処理 Servlet 変換初期化 jspinit() 36
JSP Include JSP でインクルードする部品の Server Push JSP Include JSP は Include 機能を利用した部品の再利用が可能 インクルード対象の Server Push 親 JSP が Include する対象の JSP や HTML が参照するリソースを事前にプッシュ PUSH PUSH Servlet CSS JSP インクルードしている部品が参照するリソースを事前にプッシュ JS CSS JS JSP HTML <jsp:include page= parts.jsp" flush="true" /> <jsp:include page= parts.html" flush="true" /> 37
Servlet Filter 複数 Servlet に共通するリソースの Server Push Servlet Filter Servlet リクエスト時の事前処理として利用 複数の Servlet へのマッピング可能 複数 Servlet に共通のリソースを Server Push Servlet Filter を経由して呼び出される Servlet に共通するリソースをプッシュ Fliter で実装する事で Server Push 処理の共通化が可能 PUSH Servlet Filter Servlet Servlet Servlet @WebFilter(dispatcherTypes = { DispatcherType.REQUEST }, urlpatterns = { "/*" }) public class ServerPushFilter extends Filter { @Override protected void dofilter(httpservletrequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { PushBuilder pushbuilder = request.newpushbuilder(); 38
JSF フレームワーク内部でのServer Push ExternalContextの拡張 ExternalContext.encodeResourceURL() によるマークアップ処理を拡張 <h:outputstylesheet> <h:outputscript> <h:outputlink> ExternalContextFactory 及び ExternalContextWrapperの拡張 faces-config.xmlへの設定追加 JSFタグによる外部リソース参照を Server Push リクエスト PUSH レスポンス JSF <h:outputstylesheet> <h:outputscript> encoderesourceurl() externalcontext.getrequest().newpushbuilder().push() CSS JS External Context <link href= /> <script src= /> 39
JSF 実装例 JSFを拡張したServer Push 実装イメージ Public class PushExternalContextFactory extends ExternalContextFactory { ExternalContextFactory 継承クラス private ExternalContextFactory externalcontextfactory; @Override public ExternalContext getexternalcontext(object context, Object request, Object response) throws FacesException { return PushExternalContext(externalContextFactory.getExternalContext(context, request, response));}} Public class PushExternalContext extends ExternalContextWrapper { ExternalContext 実装クラス private ExternalContext externalcontext; @Override public String encoderesourceurl(string url) { ((HTTPServletRequest) externalcontext.getrequest()).newpushbuilder().path(url).push(); return super. encoderesourceurl(url);}} <factory> <external-context-factory> PushExternalContextFactory </external-context-factory> </factory> faces-config.xml 1. ExternalContext を生成するファクトリークラスを作成 : ExtenalConextFactory を継承実装 2. ExternalContext を実装 : 実装クラスである ExternalContextWrapper を継承実装 3. JSF 設定ファイル (faces-config.xml) に登録 40
フレームワークフレームワーク依存リソースのServer Push 各種フレームワーク内部での利用 自社開発フレームワークの内部で Servlet が利用されるもの多数存在 フレームワークで制御する画面は依存する外部リソースが明確 クリティカル レンダリングパスを最適化するフレームワーク 画面描画の高速化を意識した Server Push 利用をフレームワーク化 フレームワーク内での Server Push リクエスト PUSH レスポンス Servlet フレームワーク CSS クリティカル レンダリングパスの最適化 リクエストページ GET html PUSH ビルド DOM PUSH リソース 実行 JS ビルド CSS OM レスポンス JS レンダリングツリー レイアウト / ペイント 41
Servlet 4.0 で始める HTTP/2 Wrap up 42
HTTP/2 時代の Web ページ高速化 Server Push の活用のメリットと考慮点 適用効果 標準化された実装により Web ページ高速化の取り組みの容易化 先行してロードさせるリソースの Programmatic な制御が可能 考慮点 Web ページの構成に応じた適切なプッシュ対象の選別が必要 ブラウザ毎の挙動の差異 活用に向けて Web サイト高速化に関する技術の理解 Servlet 4.0 Server Push 利用のベスト プラクティスの検討 43
参考 : 動作検証環境 JDK Java HotSpot(TM) 64-Bit Server VM (build 25.131-b11, mixed mode) GlassFish glassfish-5.0-b06-05_03_2017.zip Servlet javax.servlet-api: 4.0.0-b05 Browser Google Chrome: 59.0.3071.47 44
45