Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
今できる通信⾼高速化
にトライしたみた	
  
東京Node学園	
  15時限⽬目	
  
Feb	
  10,	
  2015	
  
Yoshiki	
  Shibukawa	
  
GDI	
  
DeNA	
  Co.,	
  Ltd.	
  	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
⾃自⼰己紹介	
  
!  名前:	
  
⁃  渋川よしき	
  (@shibu_̲jp)	
  
!  所属	
  
⁃  DeNAの開発基盤部	
  
⁃  Sphinx-‐‑‒Users.jp,	
  Python温泉	
  
!  好きな⾔言語	
  
⁃  C++,	
  Go,	
  型のある某altJS	
  
!  書いた本・翻訳した本	
  
⁃  つまみぐい勉強法、Mobageを⽀支える技術、
オブジェクト指向JavaScript、スクラム本、
ポモドーロテクニック⼊入⾨門、
エキスパートPythonプログラミング
アート・オブ・コミュニティetc	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
JavaScriptと私	
  
!  2007年年ぐらい	
  
⁃  Prototype.jsよりもMochikit派→⼈人気ないのでjQueryに乗り換え	
  
!  2011年年	
  
⁃  DeNA⼊入社。ngCoreというゲームエンジン上の開発	
  
⁃  オブジェクト指向JavaScript翻訳	
  
!  2012年年	
  
⁃  渡⽶米して引き続きngCore関連の開発	
  
⁃  GUIの開発ツールをQtのJavaScriptバインディングとかJSFLで。	
  
!  2013年年〜~2014年年	
  
⁃  ブラウザで動く全⽂文検索索エンジン(Oktavia)をJSXで作った	
  
⁃  QtのJavaScriptバインディングのJSXバインディング作った	
  
⁃  node.js	
  +	
  MongoDBでモバイルゲームのサーバサイドの実装	
  
!  最近	
  
⁃  Google	
  Apps	
  Scriptぐらい	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
JavaScriptとgoto	
  
!  ラベル付きcontinueを使えば機
械的に変換できます。	
  
!  while⽂文とswitch⽂文の
⼆二段構成+⾏行行先+ジャンプするか
のフラグを保存する変数を⽤用意	
  
!  いったんお尻に⾏行行って、頭に
⾏行行ってから⽬目的地に⾏行行くのが
最初わかりにくく感じますが	
  
!  gistに貼ったよ。	
  #tng15に放流流
したよ	
  
⁃  https://gist.github.com/
shibukawa/
315765020c34f4543665	
  
※Pythonコードも追加	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
謝辞	
  
!  職場でこのアイディアを思いついた時に、話を聞いてくれたり、コメン
トくれたり、いいねと⾔言ってくれた	
  
@uupaa,	
  @damele0n,	
  @yosuke_̲furukawa	
  (特に	
  @uupaaさん)	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
「今できる」とは?	
  
!  Service	
  Workerはまだ実⽤用で使うにはチャレンジすぎる	
  
!  Fetch	
  APIはまだ実⽤用で使うにはチャレンジすぎる	
  
!  今、そこそこ枯れている機能でがんばってみる	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
とある⽇日の発⾒見見	
  
!  LZ4コマンドで遊んでたところ、奇妙な現象に遭遇	
  
JSパーサ(esprima)で⽣生成したJSON(63MB)を	
  
⁃  gzipで圧縮→2.8MB	
  
⁃  lz4で圧縮→3.0MB	
  
⁃  lz4で圧縮した後にgzipで圧縮→1.7MB	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
LZ4とは?	
  
!  圧縮展開速度度重視のアルゴリズム	
  
⁃  ファイル圧縮ではなく、メモリ効率率率や転送速度度アップで利利⽤用される	
  
⁃  MySQLやFreeBSDのZFSのバックエンドでも	
  
⁃  Level	
  DBの裏裏で使われているGoogle	
  Snappyの類似	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
gzipとの組み合わせでファイルサイズがgzip以下に減る	
  
!  主に繰り返しの多いJSONやテキストでこの現象がおきる	
  
!  gzipはウェブのスタンダード	
  
⁃  JavaScriptからは触れられないが、ブラウザ・サーバ間の
転送コスト削減で使われる	
  
⁃  gzipの展開はネイティブで⾏行行われるので⾼高速	
  
!  lz4は⾼高速性の秘訣はシンプルな展開コード	
  
⁃  バイト単位での辞書からのコピー、出⼒力力バッファ内のウインドウの
コピーのみなのでJavaScriptでも実装可能	
  
⁃  (参考)	
  LZ4の速さの秘密に迫ってみる	
  (by@komiya_̲atsushiさん)
http://www.slideshare.net/komiyaatsushi/dsirnlp-‐‑‒3-‐‑‒lz4	
  
!  ユーザにもうれしいはず	
  
⁃  ローカルのファイルサイズも削減(JSONなら1/20以下)	
  
⁃  通信も⾼高速化	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
実装してみた	
  
!  LZ4	
  (展開コードのみ)	
  
⁃  http://github.com/shibukawa/lz4.jsx	
  
!  最速ハッシュのxxhash	
  (lz4のチェックサムで利利⽤用)	
  
⁃  http://github.com/shibukawa/xxhash.jsx	
  
!  LZ4展開機能付きXHR	
  
⁃  http://github.com/shibukawa/lz4-‐‑‒xhr.jsx	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
速度度のための⼯工夫	
  
!  JSX	
  (DeNA製の速度度重視のaltJS)	
  
⁃  さらに積極的にNative構⽂文を駆使	
  
⁃  実装時のメモ:	
  C⾔言語的にJavaScriptを使う	
  (qiita)	
  
•  http://qiita.com/shibukawa/items/9cd0dbb5b5ad512b7c86	
  
!  WebWorker	
  
⁃  通信とLZ4の展開コードは別スレッドで	
  
⁃  ArrayBufferの形式でメインスレッドへ	
  
•  (参考)	
  Transferable	
  Objects	
  Lightning	
  Fast!	
  
⁃  http://updates.html5rocks.com/2011/12/Transferable-‐‑‒Objects-‐‑‒
Lightning-‐‑‒Fast	
  
⁃  メインスレッド側で⽂文字列列へエンコードしてJSONを読む	
  
•  (参考)	
  Easier	
  ArrayBuffer	
  <-‐‑‒>	
  String	
  conversion	
  with	
  the	
  Encoding	
  API	
  	
  
⁃  http://updates.html5rocks.com/2014/08/Easier-‐‑‒ArrayBuffer-‐‑‒-‐‑‒-‐‑‒
String-‐‑‒conversion-‐‑‒with-‐‑‒the-‐‑‒Encoding-‐‑‒API	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
ベンチマーク	
  
!  expressでcompressionミドルウェアを⼊入れて、すべてのファイル
形式に強制的にgzipエンコードがかかるように設定	
  
⁃  デフォルトは1kB以上の,	
  テキストファイルのみ	
  
!  3.4MBぐらいのJSONをテストで⽤用意	
  
!  Apple製のNetwork	
  Link	
  Conditionerを⼊入れて、3G/LTE相当の
通信環境を再現し、⼗十分に早いWifi環境でNexus	
  5からアクセス	
  
⁃  3G:	
  下り	
  780kbps,	
  上り	
  330kbps,	
  遅延100mS/⽚片道	
  
⁃  LTE:	
  下り	
  11Mbps,	
  上り	
  5Mbps,	
  遅延5mS/⽚片道	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
結果	
  
0	
  
500	
  
1000	
  
1500	
  
LZ4+XHR	
   XHR	
   LZ4+XHR	
   XHR	
  
3G	
   LTE	
  
JSONパース	
  
ワーカ終了了	
  
LZ4展開	
  
ダウンロード	
  
ワーカ起動	
  
時間[ミリ秒]	
  
※各5回計測して平均	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
3G	
 LTE	
LZ4+XHR	
 XHR	
 LZ4+XHR	
 XHR	
ワーカ起動	
   2.2	
 0	
 2.8	
 0	
ダウンロード	
   924.4	
 1254.2	
 97.2	
 126.8	
LZ4展開	
   171.4	
 0	
 150.2	
 0	
ワーカ終了了	
   1.4	
 0	
 1	
 0	
JSONパース	
   148.6	
 87.2	
 132	
 65.2	
!  ダウンロードは確かに早くなった。	
  
⁃  サイズ差よりも⼤大きい。サーバ側でのgzip圧縮時間の差?	
  
!  デコードのコストが毎回かかる	
  
⁃  パース前のテキストのデコードもちょっとかかっている	
  
⁃  通信が早いとコストが回収しきれなくなる	
  
!  WebWorkerのコストはほぼタダヽ(=´́▽`̀=)ノ	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
もうちょっと早くなるんじゃ・・・	
  
!  コード展開してループ回数を減らせ、という
偉⼤大な先⼈人の教え	
  
⁃  X68000マシン語プログラミング	
  
!  Uint8Arrayで1バイトずつコピーしていた	
  
⁃  アライメントが揃っている時に、
Uint16Array、Uint32Arrayで⾼高速化!	
  
⁃  https://gist.github.com/shibukawa/18c04fce35eda662edaa	
  
⁃  ⾒見見込み:	
  25%の確率率率で4倍、25%の確率率率で2倍、50%の確率率率で1倍→2倍!	
  
!  実際に組み込むと速度度変わらず	
  orz	
  
⁃  キャッシュもJITもない時代の⾼高速化技法は役に⽴立立たず	
  
	
   	
  	
  
while (srcIndex < endIndex) {
buffer[dstIndex++] = buffer[srcIndex++];
}	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
現状のコードのメリットとデメリット	
  
!  メリット	
  
⁃  通信量量削減は達成できた	
  
•  7GB制限とかある今の時代にはメリット	
  
⁃  WebWorker側で通信しているので、クライアントコード外で
Service	
  Workerのようにフックがいろいろかけられる	
  
•  通信せずにテスト⽤用に静的コンテンツを返したりとか。データ的なDI。	
  
•  キャッシュ。サイズが⼩小さいのでローカルストレージにもやさしい。	
  
!  デメリット	
  
⁃  連続10回とかダウンロードすると発熱が少しある	
  
⁃  トータルのスループットは⼤大幅には変わらない	
  
⁃  そもそもある程度度⼤大きいJSONじゃないとlz4で⼩小さくならない	
  
Copyright	
  (C)	
  DeNA	
  Co.,Ltd.	
  All	
  Rights	
  Reserved.	
  
改善の余地はまだまだ!	
  
!  きちんとブラウザでプロファイリングする	
  
⁃  node.jsで机上のベンチばかりだったので	
  
!  展開コードの⾼高速化	
  
⁃  ECMAScript	
  6にMozillaが⼊入れようとしている
TypedArray.prototype.copyWithinを使う	
  
⁃  チェックサムを無視する(他でチェックできるなら)	
  
⁃  asm.js	
  
!  ウェブアプリでなければネイティブ側で展開	
  
⁃  アプリ内プロキシサーバとか?	
  
⁃  JavaScriptでも100MB/Sぐらいの展開速度度は出るが、公式の
ベンチマークは2GB/Sなので、1/20ぐらい。	
  

東京Node学園 今できる通信高速化にトライしてみた

  • 1.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   今できる通信⾼高速化 にトライしたみた   東京Node学園  15時限⽬目   Feb  10,  2015   Yoshiki  Shibukawa   GDI   DeNA  Co.,  Ltd.    
  • 2.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   ⾃自⼰己紹介   !  名前:   ⁃  渋川よしき  (@shibu_̲jp)   !  所属   ⁃  DeNAの開発基盤部   ⁃  Sphinx-‐‑‒Users.jp,  Python温泉   !  好きな⾔言語   ⁃  C++,  Go,  型のある某altJS   !  書いた本・翻訳した本   ⁃  つまみぐい勉強法、Mobageを⽀支える技術、 オブジェクト指向JavaScript、スクラム本、 ポモドーロテクニック⼊入⾨門、 エキスパートPythonプログラミング アート・オブ・コミュニティetc  
  • 3.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   JavaScriptと私   !  2007年年ぐらい   ⁃  Prototype.jsよりもMochikit派→⼈人気ないのでjQueryに乗り換え   !  2011年年   ⁃  DeNA⼊入社。ngCoreというゲームエンジン上の開発   ⁃  オブジェクト指向JavaScript翻訳   !  2012年年   ⁃  渡⽶米して引き続きngCore関連の開発   ⁃  GUIの開発ツールをQtのJavaScriptバインディングとかJSFLで。   !  2013年年〜~2014年年   ⁃  ブラウザで動く全⽂文検索索エンジン(Oktavia)をJSXで作った   ⁃  QtのJavaScriptバインディングのJSXバインディング作った   ⁃  node.js  +  MongoDBでモバイルゲームのサーバサイドの実装   !  最近   ⁃  Google  Apps  Scriptぐらい  
  • 4.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   JavaScriptとgoto   !  ラベル付きcontinueを使えば機 械的に変換できます。   !  while⽂文とswitch⽂文の ⼆二段構成+⾏行行先+ジャンプするか のフラグを保存する変数を⽤用意   !  いったんお尻に⾏行行って、頭に ⾏行行ってから⽬目的地に⾏行行くのが 最初わかりにくく感じますが   !  gistに貼ったよ。  #tng15に放流流 したよ   ⁃  https://gist.github.com/ shibukawa/ 315765020c34f4543665   ※Pythonコードも追加  
  • 5.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   謝辞   !  職場でこのアイディアを思いついた時に、話を聞いてくれたり、コメン トくれたり、いいねと⾔言ってくれた   @uupaa,  @damele0n,  @yosuke_̲furukawa  (特に  @uupaaさん)  
  • 6.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   「今できる」とは?   !  Service  Workerはまだ実⽤用で使うにはチャレンジすぎる   !  Fetch  APIはまだ実⽤用で使うにはチャレンジすぎる   !  今、そこそこ枯れている機能でがんばってみる  
  • 7.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   とある⽇日の発⾒見見   !  LZ4コマンドで遊んでたところ、奇妙な現象に遭遇   JSパーサ(esprima)で⽣生成したJSON(63MB)を   ⁃  gzipで圧縮→2.8MB   ⁃  lz4で圧縮→3.0MB   ⁃  lz4で圧縮した後にgzipで圧縮→1.7MB  
  • 8.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   LZ4とは?   !  圧縮展開速度度重視のアルゴリズム   ⁃  ファイル圧縮ではなく、メモリ効率率率や転送速度度アップで利利⽤用される   ⁃  MySQLやFreeBSDのZFSのバックエンドでも   ⁃  Level  DBの裏裏で使われているGoogle  Snappyの類似  
  • 9.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   gzipとの組み合わせでファイルサイズがgzip以下に減る   !  主に繰り返しの多いJSONやテキストでこの現象がおきる   !  gzipはウェブのスタンダード   ⁃  JavaScriptからは触れられないが、ブラウザ・サーバ間の 転送コスト削減で使われる   ⁃  gzipの展開はネイティブで⾏行行われるので⾼高速   !  lz4は⾼高速性の秘訣はシンプルな展開コード   ⁃  バイト単位での辞書からのコピー、出⼒力力バッファ内のウインドウの コピーのみなのでJavaScriptでも実装可能   ⁃  (参考)  LZ4の速さの秘密に迫ってみる  (by@komiya_̲atsushiさん) http://www.slideshare.net/komiyaatsushi/dsirnlp-‐‑‒3-‐‑‒lz4   !  ユーザにもうれしいはず   ⁃  ローカルのファイルサイズも削減(JSONなら1/20以下)   ⁃  通信も⾼高速化  
  • 10.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   実装してみた   !  LZ4  (展開コードのみ)   ⁃  http://github.com/shibukawa/lz4.jsx   !  最速ハッシュのxxhash  (lz4のチェックサムで利利⽤用)   ⁃  http://github.com/shibukawa/xxhash.jsx   !  LZ4展開機能付きXHR   ⁃  http://github.com/shibukawa/lz4-‐‑‒xhr.jsx  
  • 11.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   速度度のための⼯工夫   !  JSX  (DeNA製の速度度重視のaltJS)   ⁃  さらに積極的にNative構⽂文を駆使   ⁃  実装時のメモ:  C⾔言語的にJavaScriptを使う  (qiita)   •  http://qiita.com/shibukawa/items/9cd0dbb5b5ad512b7c86   !  WebWorker   ⁃  通信とLZ4の展開コードは別スレッドで   ⁃  ArrayBufferの形式でメインスレッドへ   •  (参考)  Transferable  Objects  Lightning  Fast!   ⁃  http://updates.html5rocks.com/2011/12/Transferable-‐‑‒Objects-‐‑‒ Lightning-‐‑‒Fast   ⁃  メインスレッド側で⽂文字列列へエンコードしてJSONを読む   •  (参考)  Easier  ArrayBuffer  <-‐‑‒>  String  conversion  with  the  Encoding  API     ⁃  http://updates.html5rocks.com/2014/08/Easier-‐‑‒ArrayBuffer-‐‑‒-‐‑‒-‐‑‒ String-‐‑‒conversion-‐‑‒with-‐‑‒the-‐‑‒Encoding-‐‑‒API  
  • 12.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   ベンチマーク   !  expressでcompressionミドルウェアを⼊入れて、すべてのファイル 形式に強制的にgzipエンコードがかかるように設定   ⁃  デフォルトは1kB以上の,  テキストファイルのみ   !  3.4MBぐらいのJSONをテストで⽤用意   !  Apple製のNetwork  Link  Conditionerを⼊入れて、3G/LTE相当の 通信環境を再現し、⼗十分に早いWifi環境でNexus  5からアクセス   ⁃  3G:  下り  780kbps,  上り  330kbps,  遅延100mS/⽚片道   ⁃  LTE:  下り  11Mbps,  上り  5Mbps,  遅延5mS/⽚片道  
  • 13.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   結果   0   500   1000   1500   LZ4+XHR   XHR   LZ4+XHR   XHR   3G   LTE   JSONパース   ワーカ終了了   LZ4展開   ダウンロード   ワーカ起動   時間[ミリ秒]   ※各5回計測して平均  
  • 14.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   3G LTE LZ4+XHR XHR LZ4+XHR XHR ワーカ起動   2.2 0 2.8 0 ダウンロード   924.4 1254.2 97.2 126.8 LZ4展開   171.4 0 150.2 0 ワーカ終了了   1.4 0 1 0 JSONパース   148.6 87.2 132 65.2 !  ダウンロードは確かに早くなった。   ⁃  サイズ差よりも⼤大きい。サーバ側でのgzip圧縮時間の差?   !  デコードのコストが毎回かかる   ⁃  パース前のテキストのデコードもちょっとかかっている   ⁃  通信が早いとコストが回収しきれなくなる   !  WebWorkerのコストはほぼタダヽ(=´́▽`̀=)ノ  
  • 15.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   もうちょっと早くなるんじゃ・・・   !  コード展開してループ回数を減らせ、という 偉⼤大な先⼈人の教え   ⁃  X68000マシン語プログラミング   !  Uint8Arrayで1バイトずつコピーしていた   ⁃  アライメントが揃っている時に、 Uint16Array、Uint32Arrayで⾼高速化!   ⁃  https://gist.github.com/shibukawa/18c04fce35eda662edaa   ⁃  ⾒見見込み:  25%の確率率率で4倍、25%の確率率率で2倍、50%の確率率率で1倍→2倍!   !  実際に組み込むと速度度変わらず  orz   ⁃  キャッシュもJITもない時代の⾼高速化技法は役に⽴立立たず         while (srcIndex < endIndex) { buffer[dstIndex++] = buffer[srcIndex++]; }  
  • 16.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   現状のコードのメリットとデメリット   !  メリット   ⁃  通信量量削減は達成できた   •  7GB制限とかある今の時代にはメリット   ⁃  WebWorker側で通信しているので、クライアントコード外で Service  Workerのようにフックがいろいろかけられる   •  通信せずにテスト⽤用に静的コンテンツを返したりとか。データ的なDI。   •  キャッシュ。サイズが⼩小さいのでローカルストレージにもやさしい。   !  デメリット   ⁃  連続10回とかダウンロードすると発熱が少しある   ⁃  トータルのスループットは⼤大幅には変わらない   ⁃  そもそもある程度度⼤大きいJSONじゃないとlz4で⼩小さくならない  
  • 17.
    Copyright  (C)  DeNA  Co.,Ltd.  All  Rights  Reserved.   改善の余地はまだまだ!   !  きちんとブラウザでプロファイリングする   ⁃  node.jsで机上のベンチばかりだったので   !  展開コードの⾼高速化   ⁃  ECMAScript  6にMozillaが⼊入れようとしている TypedArray.prototype.copyWithinを使う   ⁃  チェックサムを無視する(他でチェックできるなら)   ⁃  asm.js   !  ウェブアプリでなければネイティブ側で展開   ⁃  アプリ内プロキシサーバとか?   ⁃  JavaScriptでも100MB/Sぐらいの展開速度度は出るが、公式の ベンチマークは2GB/Sなので、1/20ぐらい。