目次


Weather Underground でのサーバーレス・アプローチ

Intellicast レーダー・マップに Cloud Functions と Composer プログラミング・モデルを適用する

Comments

レガシー・アプリケーションのモダナイズを考えていて、インフラストラクチャーには手を付けずにアプリケーションだけに専念したいとお望みの場合、この記事はまさにあなたのためにあります。次のプロジェクトの開発と運用にかかるコストを削減したいとしたら、サーバーレス・アーキテクチャーの採用を検討してください。

サーバーレス・アーキテクチャーは、クラウド・コンピューティングの実行モデルをベースに、イベントによって駆動されます。このアーキテクチャーでのリソースは動的に管理され、クラウド・プロバイダーによって自動的にスケーリングされます。また、サーバーレス・フレームワークは開発者の時間を解放する可能性もあります。それは、独自のインフラストラクチャーを保守、デバッグ、モニタリングする必要がないためです。

前提条件

この記事では、読者に JavaScript を実際に使用した経験と、クラウド・テクノロジーの知識があることを前提としています。

所要時間

この記事を読むには 5 分から 10 分あれば十分です。サーバーレス・アーキテクチャーに実際に取り組もうと思ったら、ここで使用しているツールのうち、採用したいものがあるか詳しく調べて、さらに時間をかけてください。

Weather Underground での課題

テクノロジーの進歩に伴って常に対処しなければならない技術的負担があるのは、どの企業でも同じことです。サイトの改良であるか、アプリケーションのリファクタリングや最適化であるか、あるいは新機能の追加であるかに関わらず、企業は常に、新しい、より効率的な改善方法を探し求めています。The Weather Company にしても、その例外ではありません。私たちは今年の大半を Weather Underground Web サイトの近代化に費やしてきました。

Wunderground.com は独特のオーディエンスを対象とするサイトです。このサイトのユーザーはデータ視覚化や気象学に深い関心を寄せる人々であり、ユーザー基盤は開発者から学生、教育機関、DIY 愛好家、科学者、政府機関、一般市民、そして博識なユーザーにまで及びます。Intellicast で新しいスタックへの移行の必要に迫られていたレガシー製品のうちの 1 つは、レーダー・マップ機能です。Intellicast 製品スイートは 1996 年以降、気象に精通した賢いユーザーに専門的な気象情報を提供してきました。Wunderground.com サイト固有の気象予測システムには、現在世界で最も先進的なテクノロジーが採用されています。私たちはこのシステムを使用して、米国のみならず世界中の 60,000 か所を対象に、詳細な現地の気象予報から、ハリケーンの進路、悪天候に関する警告、国際的な気象状況に至るまで、さまざまな情報を配信しています。アクティブな気象ツールを集結した Intellicast は、ビジネスの専門家やアウトドア・アクティビティーの愛好家たちが気象情報の情報源として頼りにアクセスすることから、インターネット上でトップ 5 に数えられる気象サイトとなっています。

Web 対応の Intellicast 製品で採用されているミドルウェアは、2018 年までに使用の廃止が予定されています。既存のシステムを新しいシステムで置き換えるにあたって、システムを構築してデプロイする方法と場所については次の選択肢がありました。

  • 選択肢 1: 従来型のホスティング
  • 選択肢 2: クラウド・ホスティング
  • 選択肢 3: サーバーレス・コンピューティング:

各種のマップ生成物の画像は定期的に、(生成物のタイプに応じて) それぞれ異なる間隔で収集されます。したがって、ミドルウェアには主に次の役割があります。

  • 現在のレーダーやウィンドストリームなどの地理的な位置に基づいて、Web クライアントが異なるマップ生成物を使用できるエンドポイントを提供すること。
  • リクエストと場所の設定に基づき、該当するリクエストに適切なアセットを Amazon S3 から取得してパッケージ化すること (間もなく Amazon S3 から IBM Cloud Object Storage に移行する予定)。そのパッケージからサムネイルとアニメーション化した gif を生成し、サーバー側でレンダリングする HTML を Web クライアントに返します。

選択肢 1 と 2 には、どちらも DevOps 作業が必要となり、インスタンス・サーバーは年中無休で稼働しなければなりません。一方、各マップ生成物のパッケージ化は定期的に行うだけでよいので、この特定の要件には選択肢 3 が最適でした。サーバーレス・アプローチに従えば、サーバーをセットアップしてデプロイする時間は必要ありません。インスタンス・サーバーを 1 日 24 時間稼働中の状態にする必要がないことも、この選択肢の利点です。私たちが作成したサーバーレス関数の複合体は、1 つのコンポーザー (intellicast-composer.js) と、同等のプロセスを行う 2 つのアクション (intellicast-action.jsintellicast-animate-action.js) からなります。以降のセクションで、この 2 つのアクションの違いと、いずれか一方のアクションを使用する場合、両方のアクションを使用する場合について説明します。

Intellicast レーダー・マップ向けソリューション

サーバーレス・コンポーネントは次のように編成しました。

  • アセットを S3 バケットに配信してからタイプ、領域、日付ごとに各生成物をグループ化するための方法を再編成しました。アセットの編成は、radar/usa/20181222/ といったディレクトリーとして考えることができます。前述のように、アセットは生成物のタイプごとに異なる間隔で収集されます。したがってアセットを日付別にグループ化すれば、処理するにも維持するにもより効率的です。
  • 従来のようなサーバー/エンドポイントを作成するのではなく、コンポーザーとアクションを作成しました。S3 バケットをトラバースするため、そして生成物タイプごとに各領域で最新のアセット・ファイルを参照する JSON ファイルを生成するために、アクションを定期的にトリガーします。生成された JSON ファイルを、S3 バケット内のそれぞれに対応するパス (ある意味、ディレクトリー) にアップロードします。アップロードされた JSON ファイルは、ブラウザーがクライアント側でページ・ビューを組み立てるのに適切なアセットを取り込むために使用します。このアクションはこのプロセスで、生成された各 JSON ファイルと対にする thumbnail.gif ファイルも生成します。アクションが呼び出されるたびに、(JSON と GIF 両方の) 合わせて 1,200 個を超えるファイルが生成されて S3 にアップロードされます。

この事例でトリガーとしてセットアップしたのは、cron ジョブです。cron ジョブを 10 分間隔で実行してアクションを呼び出します。アクションを呼び出して完了するまでの所要時間は約 15 秒と、かなり驚異的な速度です。ここまでの処理でまだ対応していないのはアニメーション化された GIF ファイルです。マップ生成物の約半分はアニメーションを提供します。つまり、約 300 個のアニメーション化された GIF (7 フレームから 24 フレームまでの範囲) を生成しなければならないということです。

最初は、すべての処理をこの同じアクションに詰め込もうとしましたが、瞬く間にメモリー制限に達してしまいました。デフォルトでは、アクションは 256MB のメモリー割り当て量を指定してセットアップされます。そこで、メモリー不足のエラーが出ないよう、2048MB までメモリー量を増やしました。それによって、今度は時間の制限に突き当たりました。許容されている 600,000 ミリ秒のしきい値を超えてしまうのです。

そこで採用したのが、Composer プログラミング・モデルです。このプログラミング・モデルでは、アクションを小さいサブタスク (複数のアクション) に分割し、Composer をオーケストレーション手段として、特定のアクションの実行タイミングを調整することができます。Composer に同梱されている一連の API を使用すれば、複数のアクションを 1 つの包括的アプリケーションに編成できます。

このことから、アニメーション・プロセスを同じアクションに詰め込むのではなく、2 番目のアクション intellicast-animate-action を作成しました。メインのアクションは引き続きそのタスクを実行し、タスクを完了した時点でオブジェクトの配列を返します。この配列は、各生成物をアニメーション化するための画像の参照からなります。私が最初に試みたのは、intellicast-animate-actioncomposer.while ループ内で実行することでした。また、以下のサンプル・コードに示されている while アクションも作成しました。このアクションによって、intellicast-animate-action の各呼び出しの前にパラメーターを設定します。

while-action.js 内のコード:

        function main(params) {
            params.start++;
           if (params.start < params.items.length) {
                params.value = [params.items[params.start]];
                return { value: true };
           }
           return { value: false };
}

composer index.js 内のコード:

        module.exports = composer.sequence(
            composer.let(
              {items: [], thumbnails: [], start: -1, params: {}},
              composer.try(
                    // generate and upload json files and thumbnails by walking directories
            'tools/intellicast-action',
                  args => ({result: 'something went wrong'})
              ),
              x => {items = x.body.result.animate, thumbnails = x.body.result.thumbnail,
params = x.body.params},
              composer.while(tools/while-action,
                    'tools/intellicast-animate-action'
              )
          )  
         )

次のフロー図に、このアクション複合体のプロセス全体を図解しています。

サーバーレス Intellicast アーキテクチャーのフロー図
サーバーレス Intellicast アーキテクチャーのフロー図

intellicast-animate-action の各呼び出しは同期的に行われるため、このアクション複合体はすべての処理を完了しきることができませんでした。各アクションは 10 分に制限されています。そこで必要となったのは、各呼び出しを並行して処理する方法です。多少の調査と、IBM Cloud Functions チームに投稿したいくつかの質問により、composer.async がこのニーズを満たすことがわかりました。composer.async を上記のコードに適用し、少々リファクタリングを行った後のサンプル・コードは次のようになっています。

module.exports = composer.sequence(
  composer.let(
    {items: [], thumbnails: [], start: -1, params: {}, batch: 1},
    // generate and upload json files and thumbnails by walking directories
    composer.try(
      'tools/intellicast-action',
      args => ({result: 'something went wrong'})
    ),
    x => {items = x.body.result.animate, thumbnails = x.body.result.thumbnail, params = x.body.params},
    composer.while(() => ++start < items.length,
      composer.async(
        x => (Object.assign(params, {value: items.slice(start, start+batch)})),
        'tools/intellicast-animate-action'
      )
    )
  )
)

composer.asynccomposer.while を介して intellicast-animate-action を実行 (呼び出しごとに 1 つのアニメーションを生成) することで、プロセス全体 (必要なすべての JSON ファイルの生成を含む) を 1 分未満で完了できるようになりました。

次のフロー図に、omposer.asynccomposer.while ループを使用したアクション複合体のプロセス全体を図解しています。

サーバーレスのフロー図
サーバーレスのフロー図
サーバーレスのフロー図
サーバーレスのフロー図

完成版の生成物は、www.wunderground.com/maps にアクセスすると確認できます。

intellicast-animate-action の呼び出しごとにバッチで処理する数を調整して実行してみたところ、それでも最大許容時間の制限を超えることはありませんでした。呼び出しごとに 30 個のアニメーションを処理するプロセスは、約 8 分で完了します。

呼び出し数を増やす (呼び出しごとに 1 つのアニメーション) のと、呼び出し数を減らす (呼び出しごとに例えば 30 個のアニメーション) のとでは、どちらがコスト効果の高い方法になるかについては、まだ判断し兼ねています。答えを知っている方がいましたら、ぜひ私にご連絡ください

まとめ

全体的に見て、サーバーレスの方法をとったことから、主に次の 3 つのメリットがもたらされました。

  • 開発コストの削減
  • 運用コストの削減
  • 自動水平スケーリング

この移行の次のフェーズは、S3 から IBM Cloud Object Storage に移行することです。


ダウンロード可能なリソース


コメント

コメントを登録するにはサインインあるいは登録してください。

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Cloud computing
ArticleID=1066424
ArticleTitle=Weather Underground でのサーバーレス・アプローチ
publish-date=08082019