AWS IoTの利用状況を可視化するCloudwatchカスタムメトリクスを作る

  • 0
    Like
  • 0
    Comment

    AWS IoTのカスタムメトリクス

    AWS IoTのコンソール画面が変更され、dashボードが表示されるようになりました。が、thing単位での通信状況はわからないので、rule engineからLambdaへ送り、通信状況をcloudwatchのカスタムメトリクスで表示できるようにしてみました。
    マルチテナント型で使う、や、想定外にメッセージが多いときにどのthingがどの位使っているかがわかれば解析が楽になるかなと思います。

    現状のdashbordで見れる情報は、アカウント全体の利用状況で以下のように見えます。
    スクリーンショット 2017-01-09 9.02.10.png

    では、カスタムメトリクス対応を作ってみましょう。

    AWS操作

    IAM

    Lambdaから、cloudwatch からput_metric_dataを使うので、以下2つの権限を持った role を作成してください
    AWSLambdaBasicExecutionRole
    CloudWatchFullAccess

    AWS Lambda

    イベントトリガはAWS IoTから作成するので関数だけ作っておいてください。
    Lambda から "create a lambda function" -> "configure function"

    Name:任意 (ここでは IoT-payload-cal)
    Description:任意
    Runtime: Python2.7
    として以下のコードを利用してください。

    前提として dataは jsonで thingNameとしてthingの情報が上がってくるものとします。
    例えば以下のようなjsonを想定しています。

    example_event.json
    {
        "thingName": "xxxx",
        <任意>
    }
    

    Lambdaの説明
    AWS IoTの課金は、512byteを1-messageとしているのでmessage部分を 512byteで割って小数点を繰り上げしています。これで大まかには詳細利用状況が可視化できるかと思います。floatでcastしているのは、intのままだと小数点が切り捨てられるためです。

    コードにはつけてないですが、通信量を見たい場合は、取得したbyte数を同様にカスタムメトリクスにputしてもらえれば、byte数で見ることができると思います。こちらは例えばSIMなどを使ってSIMのコストの概算をみるのによいかと思います。

    import json
    import math
    import datetime
    import boto3
    
    CLW = boto3.client('cloudwatch')
    
    def put_cloudwatch(thingName, value):
        try:
            now = datetime.datetime.now()
            CLW.put_metric_data(
                Namespace  = "IoT_count",
                MetricData = [{
                    "MetricName" : thingName,
                    "Timestamp" : now,
                    "Value" : value,
                    "Unit" : "Count"
                }]
            )
        except Exception as e:
            print e.message
            raise
    
    
    def lambda_handler(event, context):
    
        thingName = event['thingName']
        #JSON to String, and count string bytes
        str_event = json.dumps(event)
        byte_len = len(str_event)
        #count message, AWS IoT 1-message = 512byte
        msg_cnt = float(byte_len)/512
    
        try:
            put_cloudwatch(thingName, math.ceil(msg_cnt))
        except Exception as e:
            raise
    
        return 
    

    roleはここで作った role を選択してください。

    AWS IoT

    AWS IoTから Rules => create

    Name:任意 (ここでは、aws_iot_cal)
    Description:任意
    Using SQL version:beta

    すべてのメッセージを通すので、
    Attribute:*
    Topic filter:#
    とします。

    Add Actionから、Invoke a Lambda function passing the message data
    を選択configure actionから、先ほど作成したLambdaを指定します。

    テスト

    Lambdaからtest用jsonを作成して実行、もしくはAWS IoTへデータを送ります。
    Lambdaのプログラムでも説明したましたが、jsonの中に thingName の情報を必ず入れてください。
    lambdaのみで実行確認するには、例えば以下のようなjsonで確認出来ます。

    test.json
    {
      "thingName": "testThing-1",
      "key3": "value3",
      "key2": "value2",
      "key1": "value1"
    }
    

    testThing-1でメトリクスが作成されます。時間単位の積算データはcloudwatchのsumで見てください。
    スクリーンショット 2017-01-09 9.40.26.png

    1つのNamespaceに複数のthingからputすると以下のようになります。
    スクリーンショット 2017-01-09 9.53.16.png

    最後に

    マルチテナント型や工場/設置場所別で分けたい場合はAWS IoTでtopicとrule enginによる打ち分けで、lambdaを分けて、namespaceを分けるなどすると、良いかもしれません。
    大規模なthing登録の場合、全イベントでlambdaが発火されるので、lambdaの同時起動数などは注意が必要です。
    lambdaの同時起動数が気になる場合にはlambdaの前段にkinesisを挟むつまり、AWS IoT -> kinesis streams -> Lambda とするとよいかと思います。
    同じくcloudwatchのlimitも意識しておいたほうが良いでしょう。
    また、カスタムメトリクスもメトリクス単位で少額ですが、課金が発生します。

    免責

    本投稿は、個人の意見で、所属する企業や団体は関係ありません。
    また掲載しているsampleプログラムの動作に関しても保障いたしませんので、参考程度にしてください。