在 AWS Lambda 上寫 Go 語言搭配 API Gateway

Snip20180124_2 這應該不是什麼新消息了,就是 AWS Lambda 正式支援 Go 語言,也就是可以將 Go 語言編譯出來的二進制檔案直接放進去 Lambda Function 內,前面可以搭配 API Gateway,後面可以搭配 CloudWatchS3,本文章會教大家如何將 Gin 打包編譯進 Lambda,官網其實也有提供 Library 或範例方便大家實作,大家可以參考看看。

撰寫 Lambda function

如果想搭配 API Gateway 後端 Lambda 可能接 Restful 或 GraphQL API 的話,肯定要 Listen 單一 Http Port,底下是用 Gin 來實現一個簡單的 http 伺服器:
package main

import (
    "log"
    "net/http"
    "os"

    "github.com/gin-gonic/gin"
)

func helloHandler(c *gin.Context) {
    name := c.Param("name")
    c.String(http.StatusOK, "Hello %s", name)
}

func welcomeHandler(c *gin.Context) {
    c.String(http.StatusOK, "Hello World from Go")
}

func rootHandler(c *gin.Context) {
    c.JSON(http.StatusOK, gin.H{
        "text": "Welcome to gin lambda server.",
    })
}

func routerEngine() *gin.Engine {
    // set server mode
    gin.SetMode(gin.DebugMode)

    r := gin.New()

    // Global middleware
    r.Use(gin.Logger())
    r.Use(gin.Recovery())

    r.GET("/welcome", welcomeHandler)
    r.GET("/user/:name", helloHandler)
    r.GET("/", rootHandler)

    return r
}

func main() {
    addr := ":" + os.Getenv("PORT")
    log.Fatal(http.ListenAndServe(addr, routerEngine()))
}

可以很清楚看到在 Gin 內,只要實現 Router 部分,就可以透過 http.ListenAndServe 方式來啟動小型 Web 服務,但是上面的程式碼不能跑在 Lambda 內,這邊就要使用 Go 大神 TJ 所開發的 apex/gateway,只要將 http.ListenAndServe 換成 gateway.ListenAndServe 就可以了
func main() {
    addr := ":" + os.Getenv("PORT")
    log.Fatal(gateway.ListenAndServe(addr, routerEngine()))
}
有沒有簡單到不行?詳細範例可以參考此 GitHub Repo

建立 Lambda function

Snip20180124_3 這邊不詳細說明了,重點是在下拉選單請選擇 Go 1.x 版本即可,不知道官方什麼時候要升級 Node.js 版本 XD

編譯 Go 檔案並上傳

AWS Lambda 只有支援 Linux 架構,所以只需要透過底下指令就可以編譯出來:
$ GOOS=linux go build -o main .
$ zip deployment.zip main
把輸出檔案設定為 main,最後透過 zip 方式打包成 deployment.zip,並且從 AWS Web Console 頁面上傳。 Snip20180124_5 覺得每次都要手動上傳有點麻煩,歡迎大家試試看 drone-lambda,可以透過指令方式更新 Lambda function。下一篇會教大家自動化更新 Lambda $ drone-lambda --region ap-southeast-1 \ --access-key xxxx \ --secret-key xxxx \ --function-name upload-s3 \ --zip-file deployment.zip

API Gateway + Cloud Watch

快速參考底下測試方式 Snip20180124_6 可以看到在網址輸入 /user/appleboy 可以很快速拿到 Response,接著看看 Cloud Watch Snip20180124_7

效能測試 Benchmark

預設 AWS Lambda 使用 128 MB 記憶體,那下面透過 vegeta 來看看 Go 的效能。之後有機會可以跟 Python 或 Node.js 比較看看。底下是 128 MB 記憶體。每秒打 1024 request 並且持續 10 秒
$ vegeta attack -rate=1024 -duration=10s -targets=target2.txt | tee results.bin | vegeta report
Requests      [total, rate]            10240, 1024.10
Duration      [total, attack, wait]    20.335101947s, 9.999018014s, 10.336083933s
Latencies     [mean, 50, 95, 99, max]  6.091282008s, 4.893951645s, 14.508009942s, 17.11847442s, 20.128384389s
Bytes In      [total, mean]            143360, 14.00
Bytes Out     [total, mean]            0, 0.00
Success       [ratio]                  100.00%
Status Codes  [code:count]             200:10240
換 512 MB 每秒打 1024 request 並且持續 10 秒
Requests      [total, rate]            10240, 1024.10
Duration      [total, attack, wait]    11.989730554s, 9.999012371s, 1.990718183s
Latencies     [mean, 50, 95, 99, max]  1.491340336s, 1.114643849s, 4.112241113s, 6.087949237s, 10.107294516s
Bytes In      [total, mean]            143360, 14.00
Bytes Out     [total, mean]            0, 0.00
Success       [ratio]                  100.00%
Status Codes  [code:count]             200:10240
可以看到 128MB Latencies 是 6.091282008s 而 512MB 可以降到 1.491340336s

所有資料請直接參考 gin-lambda

  • Pingback: 自動化更新 AWS Lambda 函數 | 小惡魔 - 電腦技術 - 工作筆記 - AppleBOY()

  • erhu65

    你好,我最近也想開發 Lambda的server,語言想使用 Go,
    之前一覺得Lambda 加node.js的開發方式有個地方很不方便
    它沒辦法像是 node.js的 http server使用IDE(做runtime debug)
    雖然後來有找到serverless(sls) 加上SAM,跑出來一個Docker的 AWS Lambda local環境
    看了你這篇用Go + gin的方式去 portint到 AWS lambda
    突然覺得,我是不是可以先在 locacl 把 gin的server開發好
    等到要上lambda了,我再把apex/gateway套進來,把http轉成gateway的方式,透過這個方式

    一來我可以在 local IDE做runtime debug, 這樣完全不需要SAM的環境
    二來,開發好的server只要改動極少數行(雖然覺的還是不夠直接),就能deploy到aws lambda(我是透過serverless(sls))
    這樣的想法你覺得如何?

  • appleboy48

    如果用 GO,你一行也不用改,就可以在 local 測試了。

    https://github.com/appleboy/gin-lambda

    這裡面的程式碼,可以跑在任何地方,或者是你不想要這樣跑,可以看一下這個 commit

    https://github.com/appleboy/gin-lambda/commit/a1c065a7857d8c7b108428c1742ca323410b0bc6