ただのアニメ感想ブログ

主にアニメの感想を書いていきます。

GoLangを触ってみた#その3

前回まででGoを使ってAWSを操作することができるところまでは確認出来ました。
今回は、実際にGoを使うとどれくらい早いかを、AWS CLIと比較してみたいと思います。


まずは計測用プログラムのプロトタイプを作成します。

ファイル名:aws.go
package main

import (
    "fmt"
    "strings"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/iam"
)

const (
    debug = true
)

func main() {
    svc := iam.New(session.New(), &aws.Config{})
    
    params := &iam.GetPolicyInput{
        PolicyArn: aws.String("arn:aws:iam::<アカウントID>:policy/AmazonIAM-ReadOnly"),
    }
    
    policy, err := svc.GetPolicy(params)
    if err != nil {
        panic(err)
    }
    
    fmt.Println(policy)
    
    users, err := svc.ListUsers(nil)
    if err != nil {
        panic(err)
    }
    
    for i := 0; i < len(users.Users); i++ {
        if strings.Index(*(users.Users[i].UserName), "TestUser") > 0 {
            if debug {
                fmt.Println("Attach AmazonIAM-ReadOnly Policy to ", *(users.Users[i].UserName))
            }
            
            params := &iam.AttachUserPolicyInput{
                PolicyArn: aws.String("arn:aws:iam::<アカウントID>:policy/AmazonIAM-ReadOnly"),
                UserName:  aws.String(*(users.Users[i].UserName)),
            }
            resp, err := svc.AttachUserPolicy(params)
            if err != nil {
                panic(err)
            }
            
            if debug {
                fmt.Println(resp)
            }
        }
    }
}


このプログラムでやっていることは以下の3つです。
1. AmazonIAM-ReadOnlyポリシーをGetして表示
2. IAMユーザの一覧を取得
3. 2.で取得したユーザのうち、"TestUser"と付くユーザに対してAmazonIAM-ReadOnlyポリシーをアタッチ


で、実行した結果は以下のようになりました。

>go run aws.go
{
  Policy: {
    Arn: "arn:aws:iam::<アカウントID>:policy/AmazonIAM-ReadOnly",
    AttachmentCount: 0,
    CreateDate: 2016-05-04 13:21:14 +0000 UTC,
    DefaultVersionId: "v1",
    IsAttachable: true,
    Path: "/",
    PolicyId: "<ポリシーID>",
    PolicyName: "AmazonIAM-ReadOnly",
    UpdateDate: 2016-05-04 13:21:14 +0000 UTC
  }
}
Attach AmazonIAM-ReadOnly Policy to  TestUser0
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser1
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser2
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser3
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser4
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser5
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser6
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser7
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser8
{

}
Attach AmazonIAM-ReadOnly Policy to  TestUser9
{

}


実際にポリシーがアタッチできているかも確認します。


<実行前>
f:id:triobog:20160505130324j:plain

<実行後>
f:id:triobog:20160505130334j:plain

うん、ちゃんとできていますね。


次に、WindowsコマンドラインAWSコマンドを使うために、以下のURLからインストーラをダウンロードして実行します。
http://docs.aws.amazon.com/cli/latest/userguide/installing.html

>aws configure
AWS Access Key ID [None]: xxxxxxxxxxxxxxxxxxxx
AWS Secret Access Key [None]: xxxxxxxxxxxxxxxxxxxx
Default region name [None]:
Default output format [None]:

>aws iam list-users
{
    "Users": [
        {
            "UserName": "TECRA",
            "Path": "/",
            "CreateDate": "2016-05-04T13:19:28Z",
            "UserId": "<ユーザID>",
            "Arn": "arn:aws:iam::<アカウントID>:user/TECRA"
        }
    ]
}


無事ユーザを取得することが出来たと言うことで、まずはGoで計測用のプログラムを書いてみます。

ファイル名:aws_time.go
package main

import (
    "fmt"
    "strings"
    "time"

    "github.com/aws/aws-sdk-go/aws"
    "github.com/aws/aws-sdk-go/aws/session"
    "github.com/aws/aws-sdk-go/service/iam"
)

const (
    debug = false
    loop = 10
)

func main() {
    svc := iam.New(session.New(), &aws.Config{})
    
    users, err := svc.ListUsers(nil)
    if err != nil {
        panic(err)
    }
    
    t1 := time.Now()
    for count := 0; count < loop; count++ {
        for i := 0; i < len(users.Users); i++ {
            if strings.Index(*(users.Users[i].UserName), "TestUser") > 0 {
                attachUserPolicyInput := &iam.AttachUserPolicyInput{
                    PolicyArn: aws.String("arn:aws:iam::<アカウントID>:policy/AmazonIAM-ReadOnly"),
                    UserName:  aws.String(*(users.Users[i].UserName)),
                }
                attachUserPolicyOutput, err := svc.AttachUserPolicy(attachUserPolicyInput)
                if err != nil {
                    panic(err)
                }
                
                detachUserPolicyInput := &iam.DetachUserPolicyInput{
                    PolicyArn: aws.String("arn:aws:iam::<アカウントID>:policy/AmazonIAM-ReadOnly"),
                    UserName:  aws.String(*(users.Users[i].UserName)),
                }
                detachUserPolicyOutput, err := svc.DetachUserPolicy(detachUserPolicyInput)
                if err != nil {
                    panic(err)
                }
            }
        }
    }
    t2 := time.Now()
    fmt.Println(t2.Sub(t1))
}


やっていることはユーザの一覧を取得して、ユーザ名に"TestUser"が含まれるユーザに対してポリシーを1つアタッチして、デタッチすると言うものになります("TestUser"に限定しているのは、実行用のユーザに影響を及ぼさないためです)。
これをループで回して、実行前後の時間を取得します。


これと比較するバッチファイルは以下のものになります。

@echo off
setlocal ENABLEDELAYEDEXPANSION
set loop=1
set users[0]=TestUser0
set users[1]=TestUser1
set users[2]=TestUser2
set users[3]=TestUser3
set users[4]=TestUser4
set users[5]=TestUser5
set users[6]=TestUser6
set users[7]=TestUser7
set users[8]=TestUser8
set users[9]=TestUser9
set users[10]=TECRA
set policy_arn="arn:aws:iam::<アカウントID>:policy/AmazonIAM-ReadOnly"

echo t1=%time:/=%

for /l %%c in (1, 1, %loop%) do (
    for /l %%i in (0, 1, 10) do (
        echo !users[%%i]! | find "TestUser" 1>nul
        if not ERRORLEVEL 1 (
            rem echo !users[%%i]!
            aws iam attach-user-policy --user-name !users[%%i]! --policy-arn %policy_arn%
            aws iam detach-user-policy --user-name !users[%%i]! --policy-arn %policy_arn%
        )
    )
)

echo t2=%time:/=%


うわ~かっこ悪い。でも幾ら調べても、aws iam list-usersの結果を配列としてusersに格納する方法が分からなかったのです。残念なことに。
そこは速度計測の本質ではないので泣く泣く妥協しました。


ループ回数を1回、5回、10回と変更した上で、それぞれ5回計測した値の平均を取りました。
結果は以下のとおりです(単位はsec)。

素数 1回 5回 10回
AWS CLI 48.73 247.35 492.82
Go 0.00 0.00 0.00


Goが早すぎて計測できていない・・・。
仕方がないのでループ回数を増やして再計測。
1,000,000回実行して0.17秒、100,000,000回実行して15.19秒でした。Go早すぎだろ・・・。


もうちょっと考察をしてみると、今回の計測ではあくまでfor文の前後で時間を計測していたけど、実際にGoのプログラムは実行してから結果が返ってくるまでにラグがあった。
おそらくfor文の前の処理で何か時間がかかっているのだろう。具体的にはアクセスキーによる認証とか。
AWS CLIの場合はGoファイルのiam.Newに相当する部分が無く、直接attach-user-policy等を呼び出している。と言うことは都度認証を行っていて、それに時間がかかるのかな。もしそうだとしたらGoが早いというよりもAWS CLIが遅いのかなぁ。


そんなわけで、今日はこれまで。
それでは、ごきげんよう。