GoogleAppsScript(GAS)でのcacheあれこれ
GASでの悩ましい問題、それは、遅いこと…!
GoogleAppsScript(以下GAS)は非常に便利なサービスであることは間違いありません。
サーバーの用意も不要。
スプレッドシートとの連携も容易。
公開もちょっとした手続きで可能。
と、三拍子そろったイケメンです。
ほれてまうやろー!!
ただし、遅い。
とにかく、遅い。
注意しながらコーディングしないと、すぐにレスポンスタイムがとんでもない事になってしまいます。
たとえば、自分が実装を進めているDQMJ3の配合早見表のアプリケーションでは、 対象のモンスターの配合ツリーを生成するまでにかかる時間はなんと「60秒越え」という 身の毛もよだつようなレスポンスタイムで愕然としました…。
「これじゃ、公開しても、使い物にならんがぜよ…」
遅いなら、キャッシュすればいいじゃない
そう。そんな事は分かっているのです。
なので、今日は、僕の試したキャッシュ方法をいくつか紹介したいと思います。
APIコール回数を減らすためのキャッシュ
まず、GASにおいて、最もボトルネックになる箇所はどこでしょうか? それは、「APIコール」です。
- スプレッドシートの取得
- スプレッドシートからレンジの取得
- レンジからの値の取得
- などなど
これらは、すべて、GAS自体が内部的にAPIをたたき、通信を行い、その結果を返却しているに過ぎません。
ですので、下記のようなコードは効率がわるくなることは分かりますでしょうか?
おそらく内部的にAPIコールが発生していると思われる箇所に、コメントの記載を行ってみましたが、 このコードの何がまずいって、ループ内で、APIコールが毎回発生している事です。
もし、こういうコードを書く際には、こんな感じで、可能な限りAPIコールを減らす心がけができるといいと思います。
これであれば、どんなにシートのデータ量が増えても、APIコールは3回で固定されます。
パフォーマンスがデータ量にうける影響を最小に抑える事ができました。
この考え方は、シートの取得などに関しても同じ事がいえます。
たとえば、シートの取得処理を、異なる関数内で個別に行うのであれば、それは、やはり、何かしら変数の共有方法を考える必要性があるでしょう。
(関数の引数にシートを求める、シートの取得処理をラップしてシングルトン実装にする、グロバール変数を利用する、などなど)
ちなみに、自分はこんな感じでシートに関する処理をラップしています。
これらの、APIコールに関する細やかな気遣いを徹底してみると、60秒かかっていたレスポンスタイムが、なんと…「20秒ほど」になりました!!
ひゃっほい!まだまだ全然遅いぜ!
ちくしょー!
キャッシュサービスを利用する
コーディング上の気遣いで行える、軽量化は、おそらくほとんどやり尽くしたはずです。
無駄なループを取り除き、APIコールを可能な限り節約し、残った手は、「結果のキャッシュ」以外ありません。
幸い、今回、自分が作成しているアプリケーションは「モンスターの配合ツリーを表示する」ためのものなので、特定のモンスターに対する結果は、誰が叩こうが同じです。
そこで目を付けたのが、「Cache Sevice」です。
Cache Seviceとは?
いわゆる、キーバリュータイプの、簡易ストレージキャッシュです。 現在3種類のキャッシュがサポートされています。
- Document Cache: ドキュメントに対するキャッシュ
- Script Cache: スクリプトに対するキャッシュ
- User Cache: ユーザーに対するキャッシュ
それぞれのキャッシュで違うことは、まあ、そのキャッシュの参照スコープの違いです。
たとえば、User Cacheであれば、アクセスしてきたユーザー毎のキャッシュになるので、ユーザー毎に違う結果になるようなデータは、UserCacheを使うとよいでしょう。
使い方はこんな感じです。
これで勝つる…!
と、思いきや…。そんなに甘い話ではありませんでした。
ぐすん。
Cacheの制限
現在、キャッシュサービスで利用するキャッシュにはいくつかの制限があります。
- キーの文字列長は250文字まで
- 各キャッシュの容量は100KBまで
- キャッシュの有効期限は最大6時間まで
今回、致命的だったのは、下二つの制限です。
結果JSONは余裕で100KBを超えているし、キャッシュの有効期限が6時間というのも短すぎます。
なんせ、データにミスがなければ、永遠にキャッシュされてもいいような内容なのです。
それを6時間だなんて…。6時間毎に60秒越えのレスポンスが発生してしまうなんて…。
そんなのってないよ…!!
独自キャッシュシステムを作成
もう万策尽きただろう、そろそろ諦めたらどうだって…?
ちっちっち。
ユー、分かってないよ。
智史之介という男を全然分かってないよ。
智史之介、諦めない、絶対に。
Cache Serviceを利用できないなら、自分でキャッシュ機構を作ってしまえばいいじゃない!
というわけで、作ってみたお
ババーン!!
Cache.gs
実際使う際はこんなかんじ
仕組み的には、スプレッドーシート上にキャッシュ用のシートを作成して、そこにJSONデータをぶち込んでおくような感じです。
キーが数字indexになっているのは、キーの一致判定をいれると、どうしてもデータ量に応じてレスポンス性能が悪くなってしまうため、数字indexで持たせました。
(幸い、DQMJ3のモンスターには「位階」というIDがあり、それに対するAPI結果が一意なので、違和感はありません)
この対応をいれることで、達成できたレスポンスタイムは…なんと「0.4秒」!!
60秒以上かかっていた処理を、1秒以下まで抑える事に成功しました!
ほれていいんやで?
以上!智史之介からでした!