Thursday, April 16, 2015

HTTP/2 is much faster than SPDY thanks to dependency-based prioritization


HTTP/2 provides two methods to prioritize streams (e.g. files being served).

One method is called weight-based prioritization. In weight-based prioritization, every stream is given a weight, and the value is used by the server to proportionally distribute the bandwidth between the streams.

The other method is dependency-based prioritization. By using the method, web browsers can advise HTTP/2 servers to send the streams that are depended by other streams before sending the other streams. For example, by using dependency-based prioritization web browsers can request the server to send CSS or JavaScript files before sending HTML or image files.

As of this writing, out of the two popular web browsers that implement HTTP/2, only Firefox uses dependency-based prioritization.

Note: the background section has been rewritten due to the fact that the comparison with SPDY turns out to be wrong, as pointed out in the comment. The original version of the section is here. Rest of the blogpost stays in tact.

The case of Mozilla Firefox

The prioritization strategy of Firefox is as follows1:
  • send CSS and JavaScript files in <HEAD> before HTML and/or image files by using dependency-based prioritization
  • HTML streams are given 2.5x bandwidth above image streams (by using weight-based prioritization)
  • script files within <BODY> are in total given about the half bandwidths of the other files2

Below is the network time chart generated by Firefox 37.0.1 when accessing a sample web page3 (given 100ms network latency6) containing a number of CSS, script files, and images. H2O version 1.2.0 was used as the HTTP/2 server for running the benchmark.

By looking at the chart, you can see that many CSS, script files and images are requested in parallel at some time around 320ms, but that the download of files that block rendering (e.g. CSS and script files) complete before any of the images (even the smallest ones) become available. This is due to the fact, as I explained earlier, that Firefox notifies the HTTP/2 server that HTML and image files depend on the CSS and the script files to become rendered; therefore the server is sending the files being depended before sending the dependents. And thanks to the prioritization, all the files that are required to do the initial rendering arrives at the web browser (a.k.a. first-paint time) at around 1.0 seconds from start.

The case of Google Chrome

On the other hand Chrome's prioritization logic only uses the weight-based prioritization; the logic remains mostly same with that used in SPDY. Chrome assigns a predefined weight to each of the stream based on their types.

Table 1. Priority weight values used by Google Chrome4


And here is the timing chart taken using Chrome (version 44.0.2371.0 canary) when accessing the same web page.

Unlike Firefox, CSS and script files are not arriving before the image files. If you look carefully, you will find a vague relationship between the size and the arrive time of the contents independent to their types. This is because each of the files are interleaved into a single TCP stream based on their weights, and because of the fact that the weight between the files do not differ much. Therefore the initial-paint time is as late as 1.5 seconds5.


As shown, dependency-based prioritization introduced in HTTP/2 brings non-negligible benefit in terms of web-site performance. In case of the benchmark, Firefox using dependency-based prioritization was 1.5x faster than Google Chrome only using weight-based prioritization when comparing the first-print timings.

My understanding is that the developers of Chrome is aware of this issue, so hopefully it will be fixed soon. I also hope that other web browser vendors will utilize dependency-based prioritization. As shown, it is clearly the way to go!

PS. And it should also be worth noting that HTTP/2 servers should implement the prioritization logics correctly. In case of H2O, the server both of the prioritization logics are fully implemented using a per-frame weight-based round robin with the frame size of 16Kbytes at maximum.

note 1: ref: HTTP/2 Dependency Prioritization in Firefox 37, Http2Stream.cpp line 1088 of Firefox
note 2: ref: nsScriptLodare.cpp line 306; I am not sure if this is the intended behavior, IMO script tags in BODY should given a priority equiv. to HTML or image files, and it might be the case that the condition of the if statement should be reversed.
note 3: was used for testing the load speed, with the <script> tags at the end of the document moved into <HEAD>
note 4: ref: MapPriorityToWeight function of Chrome
note 5: the network chart of Chrome includes a 0.2 second block before initianting the TCP connection, which has been subtracted from the numbers written in this blog text.
note 6: An Ubuntu 14.04 instance running on VMware Fusion 7.1.1 on top of OS X 10.9.5 was used for running the server. Network latency was given using tc qdisc command. Both the web browsers were run directly on OS X 10.9.5.

Tuesday, April 14, 2015

H2O version 1.2.0 released; bundles LibreSSL by default

This is the release announcement of H2O version 1.2.0. Full list of changes can be found in the Changes. The release includes a fix for a heap-overrun vulnerability in the proxy module; users of prior versions using the H2O as a reverse proxy are urged to upgrade to 1.2.0.

Aside from the bug fixes, we have adjusted the code-base so that no external dependencies would be required when building the standalone server.

One of the hustles while trying to install the older versions of H2O (or any other HTTP/2 server) was that it required the newest version of OpenSSL (version 1.0.2). This is because ALPN, a feature that became only available in version 1.0.2 is essential for the HTTP/2 protocol.

However it is often difficult to upgrade OpenSSL on existing systems, since it is used by other important softwares as well (SSH, etc.).

In H2O version 1.2.0, we have chosen to bundle LibreSSL. LibreSSL is not only considered more stable than OpenSSL; it also support new cipher-suites like chacha20-poly1305, which is the preferred cipher suite of Chrome for Android.

If CMake (the build tool used by H2O) does not detect OpenSSL version 1.0.2 or above, it would instruct the build chain to use LibreSSL being bundled. To enforce the use of libressl being bundled, pass -DWITH_BUNDLED_SSL=on as an argument to CMake (note: you might need to clear the build directory before running cmake). Or set -DWITH_BUNDLED_SSL=off to explicitly disable the use of libressl.

Version 1.2.0 also bundles other dependencies as well, so that the server can be installed as simply as by running cmake, make, and make install.

Have fun!

Tuesday, March 31, 2015





% daifuku dbname tbl1 tbl2 > setup.sql
のように実行すると、指定されたテーブル(ここではtbl1tbl2)にセットすべきトリガや、更新ログを記録するためのテーブル「daifuku_log」を生成するCREATE TABLEステートメントなど、必要なSQL文をsetup.sqlファイルに出力します。

% mysql -u root < setup.sql



mysql> begin;
Query OK, 0 rows affected (0.00 sec)

mysql> call daifuku_begin('');
Query OK, 1 row affected (0.00 sec)

mysql> insert into direct_message (from_user,to_user,body) values (2,1,'WTF!!!');
Query OK, 1 row affected (0.01 sec)

mysql> insert into notification (user,body) values (2,'@yappo sent a new message');
Query OK, 1 row affected (0.00 sec)

mysql> commit;
Query OK, 0 rows affected (0.01 sec)

mysql> select * from daifuku_log\G
*************************** 1. row ***************************
    id: 4
action: [
            "id":        "2",
            "from_user": "2",
            "to_user":   "1",
            "body":      ["V1RGISEh"]
            "id":   "2",
            "user": "2",
            "body": ["QHlhcHBvIHNlbnQgYSBuZXcgbWVzc2FnZQ=="]
1 row in set (0.00 sec)


ってことで、それでは、have fun!


同様の機能をアプリケーションロジックとして、あるいは手書きのトリガとして実装することも不可能ではありませんが、トリガを自動生成する daifuku のアプローチの方が、アプリケーション開発に必要な工数、バグ混入の可能性、データベースのロック時間の極小化等の点において優れていると考えられます。


注1: 名前の由来は大福帳型データベースです。
注2: トランザクション単位のrevertではなくdaifuku_logテーブルに記録されたログを逆順に適用していった際に以前のテーブルの状態に戻ることを保証したい場合は、分離レベルをシリアライザブルに設定しておく必要があります。この点において、更新ログを主、現時点での状態を示すテーブルを従とするアプローチに対し劣位であることは、先の記事でも触れたとおりです。
注3: 文字列型等、制御文字やUTF-8の範囲外の値を含む可能性のある型のデータについては、base64エンコードが行われ、それを示すために配列としてログに記録されます。詳しくはman daifukuをご参照ください。
注4: 操作=トランザクションとは元来リレーションに1対1でマッピングされづらいものなので、過去の操作を取り扱うことが主目的の場合には、無理に正規化を行わない方が都合が良いケースが多いと考えられます。

Thursday, March 26, 2015


論理削除が云々について - mike-neckのブログ」を読んで。










  • データベース設計にあたっては、テーブルを「現在の状態」を表現するものとして設計するか、それとも「immutableなマスタと更新ログ、および現時点の状態を表現するビュー」として設計するかという、2つの選択肢がある
  • 前者は簡潔で性能が高くなるが、過去の情報を参照できないという問題がある
  • 「削除フラグ」というのは、「現在の状態」を表現するテーブルに過去の状態の一部を表現する機能を場当たり的に足したもの(なので筋が悪い)
  • それよりも、過去の情報を参照する要件がある場合(もしくはそのような要件が発生すると想定される場合)は、テーブル単位で「immutableなマスタと更新ログ」という設計を採用しつつ、現在の情報をビューとして表現することを考えた方がよい


追記: Re: 論理削除はなぜ「筋が悪い」か - Blog by Sadayuki Furuhashiで挙げられていた疑問点について


カラムのアクセス権は無停止で変更できませんか? つまり、アプリケーションを拡張した結果として削除フラグの存在が冗長になったのであれば、そのフラグの更新をストアドあるいはトリガで行われるように変更し、書き込み権限をドロップすればいいでしょう。


Tuesday, March 24, 2015

released Server::Starter 0.21; no more external dependencies, easy to fat-pack

I am happy to announce the release of Server-Starter version 0.21.

In the release I have removed dependencies to perl modules not in core (e.g. Proc::Wait3, List::MoreUtils, Scope::Guard).

Without dependencies on XS modules it would now be easier to install the module on any system.

The change also opens the possibility to fat-pack the `start-server` script; it can be accomplished by just running the fatpack-simple script.
$ fatpack-simple start_server
-> perl-strip Server/
-> perl-strip Server/Starter/
-> Successfully created start_server.fatpack

Have fun!

Thursday, March 19, 2015

「技術的負債」は避けるべき? - 割引率を使って考えてみた

「技術的負債」をコントロールする定量評価手法への期待 からの続きです。





表1. 初期開発と維持工数



表2. 初期開発と維持工数(割引率100%)


表3. 初期開発と維持工数(割引率11%)


また、割引率は事業の形態のみならず、ソフトウェアの種類によっても大きく異なります。私個人の経験を振り返っても、サーバサイドの管理用ミドルウェア → データベース等ハードウェアの能力に影響をうけるサーバサイドミドルウェア → クライアントサイドのミドルウェア → アプリケーションの順で割引率が高くなっていく印象があります。


とあるスタートアップを抜け、CTOを辞めた話。 - nobkzのブログ
「「技術的負債」を問いなおす」というタイトルでJAWS DAYS 2014で話してきた #jawsdays - delirious thoughts

注1: 企業の情報システム投資では、初期コストに保守等のコストを加えた「総所有コスト(TCO)」の極小化を目標とするのが有効なアプローチだと考えられています。
注2: ソフトウェアが陳腐化する外的要因は周辺技術の進歩です。その速度は一定であると置くのが妥当ですから、ソフトウェアの保守コストは毎年一定であると考えるのが正しいことになります。「ソフトウェアの保守が時間とともに難しくなる」と感じられるとしても、それは過去の保守投資が過小であった結果だと解釈すれば良い話です。モデルを無駄に複雑化する理由はありません。
注3: つまり、事前に使用年数を見積もることが困難なシステムがあるなら、通常のTCOではなく、保守を続ける年数を確率分布として修正したTCOを用いてコストを予測すれば良いということです。
注4: 割引率は毎年一定になるとは限らないでしょう。たとえば2年間で資金を使い切る前提でサービスを提供している場合には、2年間は割引率が低く、3年目にがくっと上がる形(失敗するサービスが過半であるという前提を置くなら、それこそ100%を超える値)になると思います。

Friday, March 6, 2015

H2O version 1.1.0 released with bug fixes and enhancements in proxy etc.

This is a release announcement of H2O version 1.1.0, the optimized HTTP server with support for HTTP/1 and HTTP/2.

In 1.1.0 we have gone through a major refactor of the proxy implementation, and added three notable features to the H2O standalone server.

Support for x-reproxy-url header #197

With help from @lestrrat, H2O now recognizes the x-reproxy-url header sent by upstream servers, and if found, substitutes the response with the response obtained from the URL specified by the header.

When the feature is activated (by adding the line reproxy: on to the configuration file), any HTTP URL can be served by using the x-reproxy-url header.

There is no support for x-reproxy-file header. Instead, if the authority of the URL matches one of the host entries of the configuration file, then the reproxied request will be handled internally by the handlers of H2O.

Load distribution among upstream servers #208

To resolve the address of the upstream server, H2O calls getaddrinfo each time it needs to connect to the servers. As of version 1.1.0 the call is executed asynchronously (by using dedicated threads for the task), and if multiple entries are returned by the name resolver (e.g. DNS, /etc/hosts, et. al.) then H2O connects to one of them selected at random.

The change neatly constitute as a basis for load balancing. By adjusting the name resolver, you can at any time add or remove an upstream server, or change the selection weight between the servers by using sophisticated DNS servers like

This is only a first step. We plan to polish up the feature for better load balancing.

Directives for tweaking the response headers #204

Following directives have been introduced for mangling the response headers, modeled after those provided by the Apache HTTP server: header.add, header.append, header.merge, header.set, header.setifempty, header.unset.

For more information, a full list of changes with references can be found in the version 1.1.0 changelog; list of configuration directives can be found by running h2o --help.