cognition.run+jsPsych+Data URI schemeでサーバに優しいオンライン実験
オンライン実験では、実験室では発生しない問題が色々とあります。そのひとつがサーバ負荷の問題です。大量の人が同時に実験サイト(今回はcognition.run)にアクセスするとサーバの動作が不安定になります。
先日、ひとつの実験で画像(1枚1枚は軽量で数十キロバイト程度)を240枚読み込む必要がある実験を行いました。この場合は画像1枚につき1度、Webサーバにリクエストを送ることになります。トータルのトラフィック(いわゆるギガ)はせいぜい10メガ程度で現在のネットワーク環境を考えればたいしたことはないのですが、リクエストのたびにWebサーバはそれなりの処理をする必要があります。これが相当負荷が高く、実験を実施したところサーバの動作が非常に不安定になり、実験を開始できないという事態が頻発しました。この実験に協力していただいた方には大変ご迷惑をおかけしました。申し訳ございません。
そこで回避策をあれこれ考えていたのですが、最終的にData URI schemeを使って画像データをベタ書きという技を使ってサーバ負荷軽減に成功し、無事に実験を完了することができました。その方法を少し解説します。
Data URI schemeというのは、何らかのデータ(画像でも何でも)をbase64 encodingという方法でテキストに変換し、それをHTML/CSS/javascriptファイルにベタ書きしておくというものです。使うときにはそのテキストを元のデータ形式に変換して使います。
太古の昔、ish形式と呼ばれるファイルをテキストに変換する技があったのですが、あれの現代版みたいなものです。
細かい説明は置いておきますが、以下のようなステップで複数の画像ファイルを一つのファイルにまとめて、実験実施時にはその一つのファイルから複数の画像ファイルを読み出すことができます。こうすることで、サーバに対するリクエストは1回にまとめられるため、トラフィックは変わらなくてもサーバ負荷は大きく軽減します。
1. 画像ファイルをData URIエンコードして1つのファイルにまとめる
やりかたはいろいろありますが、シェルスクリプトが一番楽だと思います。
以下のコマンドは
imgsディレクトリにある全てのpngファイルをData URIエンコードして
Data URIテキストをjavascriptの変数(変数名はファイル名から拡張子を除いたもの)として定義するコードを生成して
画像ファイルの数だけ変数が定義されるimages.jsというjavascriptファイルを生成します。
画像がペグジェイ(jpeg)の場合には、.pngを.jpgに、data:image/pngをdata:image/jpegに変更します。
code:bash
echo "" > images.js
for f in imgs/*.png; do
out=$(echo "const $(basename $f .png)=""\"data:image/png;base64,")$(base64 $f)"\";"
echo $out >> images.js
done
images.jsはこんな感じです。
code:js
const img_path_001="data:image/png;base64,iVBORwAi/pNAixoPjfr...(略)...0KGgoAAAANSUhE";
const img_path_002="data:image/png;base64,Je8DlDjD0pEuG5EPjfr...(略)...HyVcqtCLnYhAAA";
const img_path_003="data:image/png;base64,TflgMFboGfV7a25j9Ma...(略)...TAAAsd0lEQVR42";
...
2. cognition.runにアップロードする
cognition.runのExternal JS/CSSにimage.jsをアップロードします。なお、ここにアップロードしたコンテンツはcdn.cogntion.runから読み込まれるため、(多分)Stimuliにおくよりもウェブサーバへの負担が軽くなるのではないかと想像してます。
3. Task Code内で使う
Task codeの中ではすでに変数としてアクセスできます。例えば変数img_path_001にはData URIエンコードされたテキストが入っています。画像を扱うプラグインのstimulusにこのテキストを入れれば、それだけで画像として扱うことができます。
サンプル(jsPsych 7.0)
これをcognition.runのExternal JS/CSSにアップロードします。
おわりに
サーバ負荷軽減のために、ネットワークトラフィックだけでなくリクエスト数を減らすことを検討しましょう。
執筆:高橋(2021年11月12日)