2016年8月11日木曜日

API-gateway + Lambdaの連携で多少込み入った処理をやる

Api gatewayとLambdaの連携でどの程度のAPIをサーバレスにできるか調べました。 Lambdaをチェーンすれば、いろいろとできる反面、AWS依存がさらに高まります。

メリット

インフラコストカット 管理コストカット(ノウハウが蓄積したのち)

デメリット

導入コストアップ ベンダーロックイン

実際にどの程度使えるか?

Lambda単発だと実行時間等制限があるが、チェーンすることで混みいった処理が可能。

  • 外向きのAPIは、受け取ったデータをシンプルに保存。
  • Lambdaを入れて、ここでちょっとした処理はできる。基本その場でステータスを返す
  • 保存イベント(もしくは、定期的に)から別のLambdaを起動。
  • これは、Dynamoもしくは、/tmpを使いながらanother apiを叩く。
  • ログやエラー処理をちゃんと見直す必要がある。

    api gateway -> Lambda(1) -> DynamoDB(or s3) -> Lambda(2) -> DynamoDB(or s3 or local /tmp) -> another api server
  • Javaは立ち上がりの遅さがネック(外部連携などだとタイムアウト発生する可能性)
  • Lambdaのプログラミングモデルに合わせる必要があるため、既存コード流用はライブラリ設計が汎用的になってないと厳しい。
  • また、LambdaのNode->バイナリ呼び出しも可能。
  • 処理内容によるが、NodeやPythonで書き直したほうがいいケースが多そう。

参考

【新機能】Amazon DynamoDB Triggersを使ってDynamoDB StreamsとAWS Lambdaを連携する

DynamoDB

API Gateway と Lambdaの連携

サンプルコード

API-gateway と Lambda のサンプルを改造。

dynamo streamをトリガーにしたLambda

from __future__ import print_function

import json
import boto3

print('Loading function')


def lambda_handler(event, context):
    
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('calc_table_log')
   
    #print("Received event: " + json.dumps(event, indent=2))
    for record in event['Records']:
        print(record['eventID'])
        print(record['eventName'])
        print("DynamoDB Record: " + json.dumps(record['dynamodb'], indent=2))

        table.put_item(Item={
            "Id": record['dynamodb']['NewImage']['id']['N'],
            "ans": record['dynamodb']['NewImage']['ans']['N']})

    return 'Successfully processed {} records.'.format(len(event['Records']))

API-gateway から呼び出されるLambda

import boto3
import random

def my_handler(event, context):
    
    dynamodb = boto3.resource('dynamodb')
    table = dynamodb.Table('calc_table')

    res = {}
    res['a'] = int(event['a'])
    res['b'] = int(event['b'])
    
    if event['op'] == 'add':
        res['op'] = '+'
        res['c'] = res['a'] + res['b']
        try:
          id = random.randint(1,100)
          table.put_item(Item={
              'id': id,
              'ans':res['c']
              })
          res['dynamo_id'] = id
        except Exception, e:
            print (e)
    else:
        res['op'] = 'na'
        res['c'] = 0
        
    return res

今後の検討点など

サーバーレスにしても、権限など管理は残る。 これらをどうやって管理・運用するのか?

また、複数サービスの連携を一元的に管理する方法については、まだまだノウハウが少ない。(ここを管理するサーバーレスフレームワークがあるがまだまだこれから)

それらに伴う運用変更コストと、新しい運用の経験値の蓄積が必要。

また、開発における導入コスト。 テストなどまた新しいノウハウが必要。

上記に加えて、ベンダーロックイン。

数年続くかわからないものか、数年で全書き換え(するくらいコストかけても問題ないくらいのところ)一回書いたら、そのまま、使い続けたいものには向かなそう。

0 件のコメント:

コメントを投稿