tnakata's blog

Webエンジニア(2017/01/01~)。プログラミングやWebについて語る。学生時代は航空宇宙工学を専攻してた。

ハイパフォーマンスブラウザネットワーキングを読んでkeep-alive接続を試した

ハイパフォーマンスブラウザネットワーキングを読んで、keep-alive接続を試したくなった。

ハイパフォーマンスブラウザネットワーキングを読んだ - tnakata's blog

keep-alive接続とは、複数のHTTP通信でTCP接続を最初の1回目だけ行い、2回目以降は最初の接続を使いまわすこと。TCP接続の時点でクライアントサーバ間で通信が発生するため、この通信で発生するレイテンシを削減できパフォーマンス改善に有効である。HTTP1.1でConnectionヘッダが追加されたのに伴い利用できるようになった。詳細はハイパフォーマンスブラウザネットワーキングを読むとよくわかる。

自分で作ったtwitterで特定のユーザーのツイートから画像を引っこ抜くツールを使用する。画像のURIをツイートから取得して、URIを元に画像を取得する処理となっている。今回は520件ほど画像を取得するので、(そのままだが)520回HTTP通信することになる。この520回通信するところにkeep-alive通信を適用する。

GitHub - takayukinakata/tiny_twitter: You can get tweet from CLI

以下のパターンを試す。

  • Not keep-alive接続
    • 実装はRubyのopen-uriライブラリを使用する
    • 一回の通信が終わると接続をクローズする
  • keep-alive接続
    • 実装はRubyのnet/httpライブラリを使用する
    • 複数の通信で接続を使いまわすことができる
# Not keep-alive通信
[tiny_twitter tnakata]$ ./bin/tiny_twitter -u mogatanpe -j
I, [2017-07-08T17:17:06.721482 #4986]  INFO -- : Start fetching tweets
I, [2017-07-08T17:17:09.911793 #4986]  INFO -- : Finish fetching tweets
I, [2017-07-08T17:17:09.911855 #4986]  INFO -- : Start downloading images
--------------------------------------------------
                      user     system      total        real
downloading       2.470000   2.280000   4.750000 ( 36.749917)
--------------------------------------------------
I, [2017-07-08T17:17:46.661400 #4986]  INFO -- : Finish downloading images
I, [2017-07-08T17:17:46.661456 #4986]  INFO -- : 520 images downloded!

[tiny_twitter tnakata]$ ./bin/tiny_twitter -u mogatanpe -j
I, [2017-07-08T17:18:03.209045 #5006]  INFO -- : Start fetching tweets
I, [2017-07-08T17:18:06.387328 #5006]  INFO -- : Finish fetching tweets
I, [2017-07-08T17:18:06.387383 #5006]  INFO -- : Start downloading images
--------------------------------------------------
                      user     system      total        real
downloading       2.510000   2.310000   4.820000 ( 35.784499)
--------------------------------------------------
I, [2017-07-08T17:18:42.171433 #5006]  INFO -- : Finish downloading images
I, [2017-07-08T17:18:42.171506 #5006]  INFO -- : 520 images downloded!



# keep-alive接続
[tiny_twitter tnakata]$ ./bin/tiny_twitter -u mogatanpe -j
I, [2017-07-08T17:21:11.115537 #5109]  INFO -- : Start fetching tweets
I, [2017-07-08T17:21:14.530462 #5109]  INFO -- : Finish fetching tweets
I, [2017-07-08T17:21:14.530673 #5109]  INFO -- : Start downloading images
--------------------------------------------------
                      user     system      total        real
downloading       1.590000   1.290000   2.880000 ( 24.081778)
--------------------------------------------------
I, [2017-07-08T17:21:38.612308 #5109]  INFO -- : Finish downloading images
I, [2017-07-08T17:21:38.612355 #5109]  INFO -- : 520 images downloded!

[tiny_twitter tnakata]$ ./bin/tiny_twitter -u mogatanpe -j
I, [2017-07-08T17:21:48.847077 #5128]  INFO -- : Start fetching tweets
I, [2017-07-08T17:21:52.485432 #5128]  INFO -- : Finish fetching tweets
I, [2017-07-08T17:21:52.485492 #5128]  INFO -- : Start downloading images
--------------------------------------------------
                      user     system      total        real
downloading       1.580000   1.300000   2.880000 ( 23.637650)
--------------------------------------------------
I, [2017-07-08T17:22:16.122914 #5128]  INFO -- : Finish downloading images
I, [2017-07-08T17:22:16.122978 #5128]  INFO -- : 520 images downloded!

keep-alive接続だと10秒ほど早くなっていることがわかる。10(s) / 520(回) = 0.019…(s/回) ≒ 20(ms/回) となるので、1回あたりの通信で20msほど速度改善できている。(使っているライブラリが違うので、keep-alive接続以外の面でも速度改善されている可能性はあるが。とはいえ、一応、net/httpライブラリで毎回接続をクローズするように実装してテストしてみたら遅くなったので、keep-alive接続が速度改善に貢献していることは確かなのかなと個人的には納得した。)

# レスポンスヘッダ
# keep-alive接続
access-control-allow-origin : *
access-control-expose-headers : Content-Length
cache-control : max-age=604800, must-revalidate
content-md5 : GZltGvEI5YV91a3h/IdlbQ==
last-modified : Sat, 08 Jul 2017 03:38:33 GMT
x-connection-hash : 63ff4efa83f9d723ac35324e9414065d
x-response-time : 112
content-type : image/jpeg
content-length : 47570
accept-ranges : bytes
date : Sat, 08 Jul 2017 08:26:07 GMT
via : 1.1 varnish
age : 17132
connection : keep-alive
x-served-by : cache-tw-tyo12434-TWTYO3
x-cache : HIT
x-timer : S1499502368.676755,VS0,VE0
expires : Sun, 23 Jul 2017 08:26:07 GMT
x-content-type-options : nosniff

connection : keep-aliveがレスポンスヘッダで返ってきている。

# デバッグ
# keep-alive接続
Conn keep-alive
<- "GET /media/CUQ5rsKUwAA457Q.jpg HTTP/1.1\r\nAccept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\nAccept: */*\r\nUser-Agent: Ruby\r\nHost: pbs.twimg.com\r\n\r\n"
-> "HTTP/1.1 200 OK\r\n"
-> "access-control-allow-origin: *\r\n"
-> "access-control-expose-headers: Content-Length\r\n"
-> "cache-control: max-age=604800, must-revalidate\r\n"
-> "content-md5: Cg9YcoePzQIF0j3UMDL8lg==\r\n"
-> "last-modified: Fri, 20 Nov 2015 15:10:01 GMT\r\n"
-> "x-connection-hash: 64e4cd01cadca36b82d3e1a9decd1234\r\n"
-> "x-response-time: 361\r\n"
-> "Content-Type: image/jpeg\r\n"
-> "Content-Length: 89805\r\n"
-> "Accept-Ranges: bytes\r\n"
-> "Date: Sat, 08 Jul 2017 08:30:22 GMT\r\n"
-> "Via: 1.1 varnish\r\n"
-> "Age: 1087\r\n"
-> "Connection: keep-alive\r\n"
-> "X-Served-By: cache-tw-tyo12427-TWTYO3\r\n"
-> "X-Cache: HIT\r\n"
-> "X-Timer: S1499502623.540782,VS0,VE1\r\n"
-> "Expires: Sun, 23 Jul 2017 08:30:22 GMT\r\n"
-> "X-Content-Type-Options: nosniff\r\n"
-> "\r\n"
reading 89805 bytes...

デバッグで再接続するような記述が出ていなかったので、正しくkeep-alive接続できていることが確認できた。

補足

サーバ側で、最初の接続から一定時間の間しかkeep-alive接続を認めない、という設定ができる。例えば、nginxだと、最初の接続からkeepalive_timeoutに設定した時間(s)を経過した後に再度接続しようとすると、もう一度TCPコネクションを張り直す必要が出てくる。ずっと接続を維持し続けると、その分のメモリを確保したままになってしまうからだと思う。

感想

  • HTTPのヘッダを「読む + 読める」ようになった
  • ブラックボックス気味だったHTTP通信ライブラリ(open-uri, net/http)の使い分けができるようになった
  • 低レイヤーの学習をアプリに生かすことができた