Go
AWS
lambda

lambda を go で動かし、X-Rayでtraceするまで


このページについて

lambda を go で書き、実行途中のtraceをX-Rayに預けるまでの作業が書いてあります(2019/05時点)


開発環境

$ go version

go version go1.12.5 darwin/amd64


手順


関数作成

コンソールからlambdaを作成しましょう

後にX-Rayでlambdaのtrace結果を見たいので下記を有効にしておきます

lambda関数作成後の設定画面にあります

自動的にX-Rayと連携するための権限作成してくれるなんて親切ですね

(必ず画面上部に出る保存ボタン押しとくこと)

スクリーンショット 2019-05-15 13.32.19.png


lambda を書く


hello.go

package main

import (
"context"
"fmt"
"io/ioutil"

"github.com/aws/aws-lambda-go/lambda"
)

var (
appName = ""
version = ""
revision = ""
)

type MyEvent struct {
Name string `json:"name"`
}

func HandleRequest(ctx context.Context, evt MyEvent) (string, error) {
return fmt.Sprintf("%s-%s-%s, Hello %s!", appName, version, revision, evt.Name), nil
}

func main() {
lambda.Start(HandleRequest)
}


一応プロダクションを意識しておきたいので、gitのrevisionとか入れてます(loggingは後々ちゃんとやる想定)


build -> deploy -> 実行

Makefileからbuild行います


Makefile

# if tag doesnt exists, show revision

VERSION=$(shell git describe --tags --abbrev=7 --always)
REVISION=$(shell git rev-parse --short HEAD)

ifeq ($(VERSION),$(REVISION))
VERSION=v0.0.0
endif

NAME=hello

.PHONY: \
init \
build

init:
tfenv install

build:
GO111MODULE=on GOOS=linux go build -v -ldflags "-X main.version=$(VERSION) -X main.revision=$(REVISION) -X main.appName=$(NAME)" -o build/${NAME} *.go
cd build && zip $(NAME).zip $(NAME)


$ make build

できあがった、hello.zipをコンソールからアップロードします

受け取るjsonを修正しておきましょう

下記nameEventのとこから編集できます

スクリーンショット 2019-05-15 19.35.19.png



スクリーンショット 2019-05-15 17.42.57.png

そして、実行。。

スクリーンショット 2019-05-15 17.42.43.png

うん、動いてますねよかった。


X-Ray, CloudWatchで様子を見る

lambda管理画面のモニタリングタブでCloudWatchログ見てみましょう

スクリーンショット 2019-05-15 19.52.32.png

ざっくりパフォーマンスはわかりますが、lambdaの中で他のサービスにアクセスするとなると

各サービスアクセスの時間が知りたくなったりしますよね?

例えば、s3にアクセスしたあと、あるapiにpost行い、また別のapiにpostするとします

このとき、全体の実行時間はCloudWatchみればわかりますが、どこがボトルネックかはapi側のログと照らし合わせたり

lambdaの中で計測ログを落とす必要があると思います

しかし、そんな面倒なことをせずとも、先ほど設定したX-Rayと連携するようにしてあげれば前述の問題は解決されます

X-Rayのサンプルにあったようにlambdaの中でawsにgetリクエストを送り、その内容をトレースしてみたいと思います。

これを行うとこのようにtrace結果が見れます

スクリーンショット 2019-05-15 20.00.31.png

スクリーンショット 2019-05-15 20.01.17.png

さっそくlambdaを書き換えてみます


hello.go

package main

import (
"context"
"fmt"
"io/ioutil"

"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-xray-sdk-go/xray"
"golang.org/x/net/context/ctxhttp"
)

var (
appName = ""
version = ""
revision = ""
)

type MyEvent struct {
Name string `json:"name"`
}

func init() {
xray.Configure(xray.Config{
LogLevel: "info",
ServiceVersion: "1.2.3",
})
}

func HandleRequest(ctx context.Context, evt MyEvent) (string, error) {
// Start a segment
ctx, seg := xray.BeginSegment(context.Background(), "api-request")
_, err := getExample(ctx)
if err != nil {
fmt.Println(err)
return "", err
}
// Close the segment
seg.Close(nil)
return fmt.Sprintf("%s-%s-%s, Hello %s!", appName, version, revision, evt.Name), nil
}

func getExample(ctx context.Context) ([]byte, error) {
resp, err := ctxhttp.Get(ctx, xray.Client(nil), "https://aws.amazon.com/")
if err != nil {
return nil, err
}
return ioutil.ReadAll(resp.Body)
}

func main() {
lambda.Start(HandleRequest)
}


$ make build

zipをアップロードして、実行し、成功するはずなのでX-Rayのコンソールで確認してみてください

スクリーンショット 2019-05-15 20.06.08.png


この次

毎回手動アップロードはしんどいので、terraformなりで構成管理してみようと思います


参考