こんにちは検索サービス開発4チームの崔珉秀と申します。
インフラやシステムとの連携や統計のバックエンドを担当しております。
モバイルのウェブ環境はPCのウェブ使用環境とは色々な違いが有ります。
ネットワークの速度だけではなくバッテリーの効率を考えた仕組みなど、PCに比べリソースが十分ではないためモバイルブラウザの動作が異なっていることも有ります。
今回はモバイルのウェブApplicationにおけるSSL関係の性能に関する工夫の内容をQ&A形式で解説していきます。
Q. 何が問題でしたか?
A. モバイルクライアント(iPhone, Android)のアプリケーションからのHTTPリクエストの応答時間に遅延の問題が有ります。
最初はweb access logからのslow response(1秒以上)のHTTPリクエストが結構ありました。
そのHTTPリクエストをprotocol別(http/https)でまとめてみると遅い応答のほとんどがhttps(SSL)のリクエストになっていることがわかりました。
Q. 明確にhttps(SSL)のHTTPリクエストで何が遅いですか?
A. サーバーの方で最初の"accept"から結果を返すまでのタイミング別にログを入れて確認した結果SSLのHandshake段階で数十ミリ秒から数秒まで遅延が発生していることが分かりました。
この図は応答時間が1秒以上のHTTPリクエストのなかで各段階の遅延時間です。

ここから解決策として二つを考えました。
1.SSL handshakeの遅延を減らす。
2.SSL handshakeの回数を減らす。
Q. SSL handshakeの遅延はどうやって減らせますか?
A. モバイルでは通信速度が遅い場合が多くパケットサイズなどに影響を受けることが多いです。
そのため、証明書の発行時のキーのサイズを小さくすることも考えられます。(2048byte → 1024byte)またモバイル機種によって中間機関(chained SSL)の証明書が有無や暗号化方式の選択によって速度の差が有ります。
# SSL2を除くTLSv1とSSLv3だけを使う。
ssl_protocols TLSv1 SSLv3;
# 認証方式の一覧、早いものを先に置いて、 遅い方式またはセキュリティーの問題がある方式を除く
ssl_ciphers RC4:AES128-SHA:TLSv1:SSLv3:!ADH:!aNULL:!DH:!EDH:!eNULL:!LOW:!SSLv2:!EXP:!NULL;
# クライアントよりサーバーの認証方式を優先にする。
ssl_prefer_server_ciphers on;
Q. SSL handshakeの回数はどうやって減らせますか?
A. ここでまた二つを考えましたが、
1."SSL Session cache"を活用する。
2.HTTP 1.1のkeep-aliveを活用する。
まず、"SSL Session cache"を活用することはSSLのやり取りの結果を保存して次のssl接続時再度handshakeしなくてもSSLの通信が出来るようにします。
Q. その機能はApacheやnginxなどのウェブサーバーで既に実装されている機能ですね。
A. そうです。しかし複数のウェブサーバーを運用してLoad balancerを使っているためHTTPリクエストが各サーバーに分散されます。
そのウェブサーバーで具現したcacheは各サーバーのローカルにsessionのcacheを保存するためあるクライアントのHTTPリクエストが横のサーバーに行くと新しくSSL Sessionが生成されることでcacheのhit率がかなり低くなります。
それで各ウェブサーバーがsessionを共有するための装置が必要になりまして、sessionの情報をkey-valueとしての扱うことや揮発性データの特性などを考えてmemcacheDをSSL Session cacheとして導入しました。

Q. Load balancerですが、例えばL4 switchの場合はsticky tagなどであるクライアントのリクエストが同じサーバーに行ってsessionを維持するような仕組みで敢えてsession cacheを共有しなくてもいいかと思いますが。。。
A. もちろんその方法も有りますが、モバイルネットワークの場合は3Gなどの環境だと多数のクライアント通信社の経由で一つのgatewayのアドレスで集まって一つのIPになります。
そのため既存の接続を同じサーバーに行くことにすると多くの接続が一つのサーバーに集中することが起きまして、負荷の分散がうまく出来なくなります。
さらにSoftbankなどから提供している公衆モバイルAPによるNAT環境も同じ現状があります。
Q. memcacheDに問題が有って応答しない場合はどうなりますか?
A. cacheとしてのmemcacheDの接続は、できるだけ短い接続timeoutにして、何回か連続で失敗した場合にsession cacheを使わないようします。
memcacheDが正常の状態に戻ったらウェブサーバーにシグナルをあげて当機能をオンにします。
Q. SSL handshakeの回数を減らすもう一つの方法は何ですか?
A. HTTPのkeep-aliveを活用することです。もうある接続を維持して再利用することでSSLのhandshakeを要請する度にしなくてもよくなります
Q. ウェブサーバーでkeep-aliveをオンにすることだけでいいですね。一番簡単に出来ますね。
A. この場合もモバイル機種別に多様な問題が有りますが、例えばiPhoneの場合は一般的にHTTP接続でよく使われるCocoa frameworkのNSURLの場合は、NSURLConnectionを使ってkeep-aliveの接続をすると2秒ぐらい以上keep-aliveの維持が出来ません。
2秒以上経つとサーバー側のkeep-aliveのtimeoutと関係なくiPhoneのclient側で接続を切ってしまいます。
Q. なぜclientでkeep-aliveのtimeoutを管理しますか?
A. いろいろ理由はあると思いますが、NSURLConnectionの場合は多分接続の負荷によるバッテリーの消耗を考えたことではないかと推測します。
それとともにkeep-aliveがoffになっているとNSURLConnectionではSSL Session cacheも使わないです。
keep-aliveがoffになっているとNSURLConnectionでHTTPSのリクエスト時session cacheのkeyのpacketをサーバーに送ってくれないです。
また、逆にNSURLの場合はkeep-aliveがoffにならないことなどいろいろのOSの制約事項が有ります。
Q. ライブラリ上でその動作について調整はできないですか?
A. NSURLConnectionではその動作について提供しているインターフェースはないです。しかし、ASIHTTPRequestというiPhoneで使えるHTTPのライブラリではclient側のkeep-aliveの維持時間の調整は出来ます。つまり、状況を判断して色々の条件を組み合わせながら確かめることが必要になると思います。
モバイル環境はどんどん改善されてネットワーク環境もモバイルのハードウェアの性能も開発のためのライブラリも豊かになってはいますが、
まだPCの環境と比べて異なる部分が多くあります。その変わった内容をよく把握してそれに合わせてシステムに取り組むことでより良いモバイルのサービスを提供できるかと思います。