インテージテクノスフィア技術ブログ

株式会社インテージテクノスフィアの社員達がシステム開発や仕事に関する技術情報を随時掲載いたします

AWSでAPIをサーバーレスに構築してみようか

皆さまこんにちは。インテージテクノスフィアのアイダです。2回目はリサーチテクノロジー本部の SさんによるAWSを使った事例紹介です。当社は2010年頃からAWSを業務適用し始め、今では全社で積極的に利用しております。Sさんも長年AWS利用されている方ですが最近初めてサーバレスアーキテクチャを使ったそうで、今回その知見を書いていただきました。ではSさんお願いします!

はじめに

とある業務で手掛けたAWSでのサーバーレスアーキテクチャの事例のご紹介です。

私もサーバレスが初めてだったこともあり、いろいろと苦戦しました。

API開発これからやるという方、AWSのサーバレスアーキテクチャよく知らないという方、なんとなく興味ある方にちょっとでも参考になればと思います。

まずお話の前提として要求時点でのこれ(A)が、最終的にこれ(B)になりました。

(A)

f:id:intage-tech:20200127182353p:plain:w500

(B)

f:id:intage-tech:20200127182321p:plain:w500

上記過程でいろいろ工夫したり、ハマった点をお話したいとおもいます。

1. Redshiftは集計系関数があまりサポートされてない!(Athena -> Redshift Spectrum)

今回、データ分析業務における人的作業の負荷が上がってきたことから、API化(処理化)し、人的作業を減らすことが目的の1つでした。

かつ要件として各自が分析で利用していたAthenaをDB化する前提があり、運用やパフォーマンス検討の結果Redshift Spectrumを採用して開発を進めました。

Redshift Spectrumをご存じない方向けに簡単に言うと、S3にあるファイルをインポートせずにそのままRedshiftの外部テーブル化する仕組みです。

(Athenaとの違いは省略します)

で、Athenaで使っていたクエリをRedshift Spectrumへ移行したのですが、

Redshift(Spectrum含む)は集計や分析用途のクセに集計系関数があまりサポートされてない

ということに途中で気づきました。

具体的に言うと、Athenaでは集計時に小計を算出するためのGroup by句にROLLUPオプションを使っていたのですが、Redshiftではこれがないと。もちろん全部の組み合わせの小計を出すCUBEオプションもない。

Redshift

https://docs.aws.amazon.com/ja_jp/redshift/latest/dg/c_Aggregate_Functions.html

 →RedshiftはオープンソースのPostgreSQLがベース。

  新しめのPostgreSQLにはROLLUPはあるのだが、Redshiftのベースとなっているバージョンには入ってない。

Athena 

https://docs.aws.amazon.com/ja_jp/athena/latest/ug/select.html

 →AthenaはFacebookがオープンソース化したPrestoがベース

まあ、移行あるあるっちゃあその通りなんですが。

で、どうしたかって?

SQLを改修しサブクエリで小計を計算してUNION句でつなぎました。

え?処理性能悪くなるって??だってしょうがないじゃないですか・・・

ちなみにAthenaは多重度には弱いのですが、ビッグデータ系の単発クエリ処理性能だけならノーチューンでRedshiftより断然速いです

こういった分析業務の処理化は結構、事例として頻度は高いのではないでしょうか。その場合、もしアプリケーション的にリクエストの多重性を制御できる、もしくはサービスのSLA(Service Level Agreemen))を鑑みて処理失敗してもクリティカルな影響が少ない状況であれば、分析用に使っていたAthenaのままAPI化したほうが開発コストも処理時間も削減できる可能性があります。是非あたまの片隅にでも置いといてください。

2. 30秒以上のAPI GatewayはStep Functionsをかますべし

同期処理と非同期処理の違い、みなさんご存じですか?

Webアプリケーションの場合、いろいろなところのタイムアウトを気にする必要がでてくるのですが、AWSでよくやる

API Gateway + Lambda

の構成で、時間的に最もネックになるのはAPI Gatewayの タイムアウト(リファレンスでは「統合のタイムアウト」という制限値)です。

現時点で、この値が最大29秒までしかサポートされていません

https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/limits.html

リソースまたはオペレーション デフォルトの制限 引き上げることができる
統合のタイムアウト Lambda、Lambda プロキシ、HTTP、HTTP プロキシ、AWS 統合など、すべての統合タイプで 50 ミリ秒~29 秒 下限または上限には適用外

もちろん設計段階で同期にすべきか非同期にすべきかは悩んではいました。しかし、依頼側よりできれば同期にしたいとのことで作りながら考えようという形で進めたのですが、結果的に処理時間が読めない案件であった時点で非同期構成にすべきだった(少し遠回りした)ということですね。

したがって、『応答の完了が確実に30秒未満に終わると断言できるものではない限り、非同期処理として

API Gateway + Step Functions + Lambda

の構成を意識すべきです。

事例はすぐ探せます(みんな大好きクラスメソッドさんの事例)

https://dev.classmethod.jp/cloud/aws/apigateway-stepfunctions-asynchronous/

Step Functionsを使う分リクエスト用とレスポンス用の2つのメソッドを用意することにはなるのですが。

あと応答の完了で次に問題になるのは、Lambdaのタイムアウト900秒(15分)という制限あたりです。

3. API Gatewayのアクセス制限設定の罠に注意

API GatewayでAPIを作る場合、セキュリティを考慮してアクセス経路を適切に設定しますよね。みなさん、この設定でハマりませんでしたか?なかなかうまく制限ができない・・・みたいな。

通常アクセス制限はリソースポリシーで設定するかとおもいますが、アクセス許可させる対象となるAPI Gatewayのメソッドやプロパティのリソースを指すARNがマネジメントコンソール上のどこからも取得できないという・・・

ひどい!

f:id:intage-tech:20200127183633p:plain

f:id:intage-tech:20200127183646p:plain

設定を行いたい方は、この辺のドキュメントを見ながら設定をすることになります。

意外とネット上にこの辺のアクセス制限の事例も少ないので、ハマった方はいるのではとおもいます。とりあえずあらかじめ注意してください。

https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/list_amazonapigateway.html

4. Cognitoのいけてないところ

Cognito、使ったことある人少ないと思いますが、ユーザー認証用のディレクトリサービスです。

https://aws.amazon.com/jp/cognito/

簡単に言うなら、社内のActive Directory(通称:AD)と同じような仕組みと考えてください。

この仕組みと社内のADを連携させれば(注:システム管理者に要相談!)社内のログインアカウントを利用してシングルサインオン認証ができるはずです。

で、このCognito。

もちろん任意のユーザーを登録することができるので、アプリケーション等でユーザーを個別、グループ単位で認証認可をさせたい場合は重宝します。

ただ、登録したユーザーを有効化するためにはマネジメントコンソールではできず、boto3等の純正ライブラリもしくはAWS CLI等のコマンドを使わなければいけないんです。つまりこちらもめんどくさいから気を付けてください。

5. serverless frameworkでLambdaのデプロイを簡単に

今回の記事で一番伝えたかったことです。

皆さん、Lambdaってどうやってデプロイしてますか?

そりゃーライブラリをなにも使わないような簡単な処理であればマネジメントコンソールに直接ゴリゴリ書いてもいいでしょうが、かなり複雑な処理を組み込んだLambda関数をまさかライブラリも含めて自分でzipに固めてアップロードしてませんよね?今後も維持保守していくんですよ、誰がそれ引き継いでやるんですか??

というわけで、そのあたり改修⇔デプロイの多いアジャイル的な開発をPythonで行うのであれば、こちらのフレームワーク+プラグインの導入をお勧めします

serverless framework + serverless-python-requirementsプラグイン

f:id:intage-tech:20200127184158p:plain

純正のPythonコードだけであればプラグインは不要だけど、だいたいはpipで外部モジュールいれるとおもうので、その場合にはこのプラグインを入れて設定ファイルに記載しておくとデプロイ時同梱してくれます。

インストールの前提条件 はこんな感じです。

  • python3.7がインストールされている
  • node.jsのv4以上がインストールされている
  • AWS CLIがインストールされている
  • docker がインストールされている

ymlにデプロイ先の環境情報を記載して、外部モジュールリストを置くだけ。

一度設定できてしまえば、

$ sls deploy

だけでデプロイしてくれちゃいます。

いやー、システムテストで数十回もバグ改修(泣)。これなかったら超めんどくさかった。いくつかこういったフレームワークはあるみたいなのですが、

何がいいってインストールも設定もシンプルだし動きが軽い、そしてなんかかっこいい

この仕組み、裏でうごいているのはCloudFormationなので、CloudFormationでできることはおそらくほぼできるはすです。

私は「にわか」使いだったのですが、もっと便利な使い方がいっぱいあるようで、なんならすでにあるある構成のymlテンプレが用意されているので、これを使うと楽ちんぽい。下記あたりが参考になるでしょうか。

ちなみにAWS謹製の似たようなデプロイ用のフレームワークであるAWS SAMというものもありカバー範囲は広そうですが、すべてをこのフレームワークでのデプロイに任せる必要はないし、そもそもカジュアルではなさそうなので

今のところserverless framework一択でよかろう

これからAPIを開発しようとしている方、ぜひとも何かのきっかけになれば幸いです。