WebWorkerをproductionで使ってる話
shokai.icon @shokai
横浜から京都にリモートワークしてます
右のメニューのStart presentationでスライドになります
https://gyazo.com/ee1523b75c28829451aebf247b1e8538
https://gyazo.com/8668866112b6ce2a5537e20d9afdbf4c
WebWorkerについてのスライド等がググってもぜんぜん見つからなかった
WebWorker使ってる人いるのか?
会場にはいなかった
Cosense.iconでは検索とか推薦とかに使ってる
知見を共有しにきました
WebWorkerとは
ブラウザで使えるマルチスレッドプログラミング環境
UIスレッドをロックしない
別のCPUで実行される
ServiceWorkerとは関係ない
なぜWebWorkerか
無料でスケールする
clientのCPU数はどんどん増えてる
スマホでも4コア6コア
サーバーのCPUを使いたくない事情
IO・帯域・CPU等のバランス見て、ScrapboxではCPUを特に使いたくなかった
だいたいどのブラウザでも動く
https://gyazo.com/d2aeac3790361712695f4197f266b2a0
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の機能
同時編集
他のページへのリンクを書く
双方向リンクになる
ページの下の方に推薦されて色々出てくる
https://gyazo.com/343caf0f14cc565ce656a43e9a02aad2
これが結構重かった
つまりちょっと編集する毎にサーバーで推薦の計算が走ってた
キーボード打つ毎にReactが固まる
同時接続数が増えるとサーバーのCPUが専有される
https://gyazo.com/d487581f31f748e594a067d758880ef6
WebWorkerのおかげで
他の人が今作ったばかりの新しいページが、辞書に即反映されるようになった
差分だけやりとりする
辞書作成はWebWorkerでやる
https://gyazo.com/d9e2d477b2530c43cd466e9cc6ca8da1
リンク記法の補完と同じデータを使っている
https://gyazo.com/c2ff78acbd39bded3c46d3f2512c88aa
リンク先のリンク先までを推薦対象として
何つながりで推薦されているのか(左端)
被リンク数などからスコア計算してソート
重複避け
上の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持ってる
https://gyazo.com/272c076324dc63f19b65ce066f5b74c2
このスライドもサーバーサイドレンダリングしてないけど、Googleに表示される
これまで表示が遅くて気づかなかった不具合
キーボード打つ毎に点滅してた
表示が高速化され、高速に点滅するようになった
https://gyazo.com/28d6adde543384e992c631c181e2e280
worker化すると他にも副作用(実体は気づいてなかったbug)が出ると思う
Universal(Isomorphic) Javascript
Server・UIスレッド・Workerのどこでも実行できるように書いておく
src/share/の下に純粋な関数として実装していく
処理を別の環境にサッと移せるようになる
lambdaに一部分だけ任せるとか
逃げ道があると気が楽になる
WebWorkerの中でもUIスレッドと同様に
Raven.config(conf).install()できる
workerのバグ見たら即直す
何度もWebWorkerに仕事させる
Promiseの多重実行を防ぐ
おわり