WebWorkerをproductionで使ってる話
@shokai
横浜から京都にリモートワークしてます
右のメニューの Start presentation
でスライドになります
WebWorkerについてのスライド等がググってもぜんぜん見つからなかった
WebWorker使ってる人いるのか?
会場にはいなかった
では検索とか推薦とかに使ってる
知見を共有しにきました
WebWorkerとは
ブラウザで使えるマルチスレッドプログラミング環境
UIスレッドをロックしない
別のCPUで実行される
ServiceWorkerとは関係ない
なぜWebWorkerか
無料でスケールする
clientのCPU数はどんどん増えてる
スマホでも4コア6コア
サーバーのCPUを使いたくない事情
IO・帯域・CPU等のバランス見て、ScrapboxではCPUを特に使いたくなかった
だいたいどのブラウザでも動く
Workerの使い方
UIスレッドで作る
const worker = new Worker(url)
仕事投げる
worker.postMessage(data)
objectそのまま投げれる
結果を受け取る
worker.onmessage(callback)
worker.onerror(callback)
Worker側
仕事受け取る
グローバルに function onmessage (data)
を宣言しておく
UIスレッドに返す
グローバルにある postMessage(data)
を呼ぶ
Scrapboxの機能
同時編集
他のページへのリンクを書く
双方向リンクになる
ページの下の方に推薦されて色々出てくる
これが結構重かった
つまりちょっと編集する毎にサーバーで推薦の計算が走ってた
キーボード打つ毎にReactが固まる
同時接続数が増えるとサーバーのCPUが専有される
WebWorkerのおかげで
他の人が今作ったばかりの新しいページが、辞書に即反映されるようになった
差分だけやりとりする
辞書作成はWebWorkerでやる
リンク記法の補完と同じデータを使っている
リンク先のリンク先までを推薦対象として
何つながりで推薦されているのか(左端)
被リンク数などからスコア計算してソート
重複避け
上の3つを全部serverでやって、CPUを専有していた(最悪25秒)
他人が同時編集したら関連ページリストもリアルタイムに更新しなければならない
clientの数だけCPU負荷がサーバーにかかっていた
WebWorkerのおかげで
全部clientにやらせて、負荷軽減した
ちょっと大きいJSONやりとりするだけで良くなった
実装
serverは「何を表示するか」を返す
session見てアクセス権限だけ確認し、大きめの
JSONをドカッと返す
JSONを小さくする為の重複よけとかはしない
DBにquery投げて結果をそのままclientにスルーしちゃう
「どう表示するか」はclientのUIスレッドとworkerが担当する
Reactのレンダリングのタイミングで最終計算する
やってみてわかった事
ページとリンクのリストなので、完全一致する文字列が多い
[ {title: "タイトル1", links: ["リンク先1", "リンク先2", "リンク先3"] }, {title, links}, {title, links} ]
1/4ぐらいになった
new Worker(url)
すると毎回GETリクエストが飛ぶ
Worker呼ぶ直前に作ると遅い
事前に作ってworkerを使いまわす
Worker複数作る
並行実行したい処理の数だけ new Worker(url)
する
それぞれ別のCPUで実行される
new Worker(url)
サーバーが301 not modifyを返せばcacheが使われる
app初期化時に必要な数だけ new Worker(url)
しておく
1つのWorkerに複数の機能入れちゃう
UIスレッドとコード共有もできる
DOMが無い
scriptタグが書けないので、CDNにライブラリを任せられない
ファイルサイズに注意
Google BotはWebWorker持ってる
このスライドもサーバーサイドレンダリングしてないけど、Googleに表示される
これまで表示が遅くて気づかなかった不具合
キーボード打つ毎に点滅してた
表示が高速化され、高速に点滅するようになった
worker化すると他にも副作用(実体は気づいてなかったbug)が出ると思う
Universal(Isomorphic) Javascript
Server・UIスレッド・Workerのどこでも実行できるように書いておく
src/share/
の下に純粋な関数として実装していく
処理を別の環境にサッと移せるようになる
lambdaに一部分だけ任せるとか
逃げ道があると気が楽になる
WebWorkerの中でもUIスレッドと同様に
Raven.config(conf).install()
できる
workerのバグ見たら即直す
何度もWebWorkerに仕事させる
Promiseの多重実行を防ぐ
おわり