Try using eawsy's aws-lambda-go

AWS lambda is popular recently. However, the execution environment is only python, java, node. I came along quite well with python, but recently I've been using go for a long time and I thought it would be nice to be able to run with go.

So, yesterday eawsy/aws-lambda-go <https://github.com/eawsy/aws-lambda-go>` _ so was aware of the library that can be described the lambda in that go, tried . (Hereinafter eawsy is called)

Comparison with apex

feelings say lambda and I want to write in the go is in the past AWS Lambdaで効率的にgoバイナリを実行する that I was writing an article. At this time, lambda_proc that I was using the library, and then come out in various ways, that's recent apex it is famous.

So what is the difference between eawsy and apex? Eawsy runs with Python's C extension.

  • Apex
    • Lambda calls node as runtime, and node calls bin with go with spawn.
    • It's normal binary to run. Can be run as it is on Linux
  • Eawsy
    • the Go -buildmode=c-shared Build as a shared library in
    • Lambda run python. Python reads go as C extension and executes it

In other words, it is only once in eawsy, compared with two processes being generated in apex. Instead, you need the cgo environment for build. However, eawsy offers a Docker container so you do not need to prepare cgo environment.

Try it.

I write maing.go like this.

package main

import (
      "encoding/json"
      "log"
      "time"

      "github.com/eawsy/aws-lambda-go/service/lambda/runtime"
)

func handle(evt json.RawMessage, ctx *runtime.Context) (interface{}, error) {
      ret := make(map[string]string)
      ret["now"] = time.Now().UTC().Format(time.RFC3339)

      return ret, nil
}

func init() {
      runtime.HandleFunc(handle)
}

func main() {}

main in the sky, init to register a handle on. json.RawMessage in will come across entered parameters.

ret is interface{} So can return any type. This will be answered in the form of JSON.

benchmark

I tried to write the same code with apex.

package main

import (
     "encoding/json"
     "time"
     apex "github.com/apex/go-apex"
)

type message struct {
   Time string `json:"time"`
}

func main() {
     apex.HandleFunc(func(event json.RawMessage, ctx *apex.Context) (interface{}, error) {
             var m message
             if err := json.Unmarshal(event, &m); err != nil {
                     return nil, err
             }
             m.Time = time.Now().Format(time.RFC3339)
             return m, nil
     })
}

Run it directly as follows and see the execution time in the CloudWatch log.

eawsy
$ aws lambda invoke --function-name preview-go output.txt
apex
$ apex invoke hello
ベンチマーク
回数 eawsy apex
一回目 16.38 ms 41.11 ms
二回目 0.48 ms 1.21 ms
三回目 0.50 ms 0.64 ms

The first time lambda starts up the container (although it is unknown whether it is) it takes time. It is early because it has been started since the second time. It is the first important thing to say that, apex is about half compared to 40 msec, eawsy is 16 msec. Because it is a troubles I post only one result, but the basic tendency was the same after doing it several times.

Once the activation is completed, it becomes 1 msec or less, both of which are the same.



However, it's just one time when it's quiet, when 40 msec has reached 16 msec. There will also be important workloads, but I do not think it makes much sense. Since lambda's execution time is unstable in the first place, it is feeling that it has gotten faster by several msec.

The advantage of eawsy is not benchmarking, it is possible to call log output and runtime functions. (That, of Reddit Finally vanilla Go on AWS Lambda (no serverless!) startup <5ms author says in.)

Benefits of eawsy

Log output

Apex runs through the runtime of node, so log output is only output to stdout. As a result, it took one hand and it was necessary. In contrast, eawsy can use the standard log package.

log.Printf("Log stream name: %s", ctx.LogStreamName)
log.Printf("Log group name: %s", ctx.LogGroupName)
log.Printf("Request ID: %s", ctx.AWSRequestID)
log.Printf("Mem. limits(MB): %d", ctx.MemoryLimitInMB)
log.Printf("RemainingTime: %d", ctx.RemainingTimeInMillis)

If you do like this like normal log output, it will appear in the CloudWatch log as follows.

13:19:55 START RequestId: 9bf7d852-a0b3-11e6-b64b-7dec169bb683 Version: $LATEST
13:19:55 2016-11-02T04:19:55.919Z     9bf7d852-a0b3-11e6-b64b-7dec169bb683    Log stream name: 2016/11/02/[$LATEST]1e58f3ef77894283988110ea452dc931
13:19:55 2016-11-02T04:19:55.919Z     9bf7d852-a0b3-11e6-b64b-7dec169bb683    Log group name: /aws/lambda/preview-go
13:19:55 2016-11-02T04:19:55.919Z     9bf7d852-a0b3-11e6-b64b-7dec169bb683    Request ID: 9bf7d852-a0b3-11e6-b64b-7dec169bb683
13:19:55 2016-11-02T04:19:55.919Z     9bf7d852-a0b3-11e6-b64b-7dec169bb683    Mem. limits(MB): 128
13:19:55 END RequestId: 9bf7d852-a0b3-11e6-b64b-7dec169bb683
13:19:55 REPORT RequestId: 9bf7d852-a0b3-11e6-b64b-7dec169bb683
Duration: 16.38 ms
Billed Duration: 100 ms Memory Size: 128 MB   Max Memory Used: 8 MB

Fatalf will display an error, Panic will display stacktrace.

error processing

handle and put the error in the return value of the

return ret, fmt.Errorf("Oops")

The following log will be exported to CloudWatch.

Oops: error
Traceback (most recent call last):
File "/var/runtime/awslambda/bootstrap.py", line 204, in handle_event_request
result = request_handler(json_input, context)
error: Oops

You can call the function of runtime

In the approach of apex, since execution is go only, it was impossible to obtain the information provided to the node. However, eawsy can get the information provided for runtime from go.

Examples of the log output of the above ctx.RemainingTimeInMillis There are places to get the rest time that. This is evidence that the information provided in python runtime is available.

Summary

The approach of calling go from Python via C extension was interesting, so I tried using it.

Although it is said that it is not a decisive difference from the benchmark (it is fast from the beginning), it may be nice to call the function of runtime or to use the standard log package, but as a programming model it is too big There is no difference.

apex and that not to golang is, apex deploy from the fact that is also excellent as a management tool and so on, I think the tactics rises towards the apex at the moment.

bonus

proxy.c is it is an entity of the runtime. handle in is called the go.

Since it is normal C extension, the same approach can be done with rust, C ++, etc. It may be interesting to write it with rust.