Announcing Go Support for AWS Lambda
aws.amazon.com
aws.amazon.com
Last I looked the "fake-aws", specifically "lambda" supported python, not JS/Node, which was not matching my use-case. Go is now on the radar as a usable programming language for this purpose, but what are the chances of being able to also use it with local test deployments?
If using the serverless framework, the serverless-offline plugin[0] supports JS/Node but not Python.
(If you can't get internet on your plane then you might not be able to run tests, but that's the case with the full test suite on a fair few systems anyway)
Many people are saying: "Just mock the AWS parts..." or "Provision from amazon on demand...", but there should be "common" mocks, or ideally "toy mocks" which can be used locally in order to verify the production system works how you expect it to, prior to deployment to that production system.
Basically, I'm uncomfortable making AWS a hard-dependency if I can't get something like it running locally for a "100 record use case"
0. https://github.com/localstack/localstack 1. https://github.com/atlassian/localstack/
https://github.com/awslabs/aws-sam-local
I'm only testing Lambda functions with it, and not really testing APIG + Lambda integrations or anything fancier.
I prep the local db, mock a Lambda event, write the mocked event to a JSON file, then use command line options to run the event against AWS SAM local, then get the response and compare it to the expected response.
Does it have to do with supporting libraries being pre-installed on the Lambda image or something? Couldn't they build a Lambda image that handles any language that can interface to common "C" headers?
Also, there still are other things to take care of. Online code editor support, making sure everything works and there are no bugs, support for compiling the programs edited directly from the browser, etc etc. Also, Lambda support means that the language has access to it's execution context through an API and there is no better way than to implement it in the same language and just pass an object to your handler.
Lambda functions in reality are not one-off CLI commands that boot and terminate fast. They actually spin up a long running service and then the same instance handles multiple requests until the instance is killed off because of being inactive for too long. Having lambda support means AWS implementing a long running server that integrates with your code, handles things like errors, exceptions, logging and provides you with an API to execution context.
For example I need to munge some data somewhat regularly, which is stored as json on S3. I can trigger it, and have about a thousand processes running in a few seconds, and my large chunk of json processed very quickly. I don't need to maintain any systems for this to work and it's cheap enough it's not worth me worrying about.
Though S3 select might supercede a bunch of my use cases.
Am I correct to assume to ideal use case for that is to replace what is typically implemented as a background workers for webservices?
Not perfect for all use cases, although some people do seem to enjoy running as much stuff in lambda as possible, but when it matches what you need it can be a surprisingly simple solution to quite annoying problems.
Seems weird to completely disarm your "thanks" with "somehow".
English is hard.
Would you agree with this statement? => what sets lambda apart is that it boots so fast that it's legit to start one only to call one function, which in turns, thanks to aws infrastructure, allows to massively parallelize short lived tasks.
I see majority of my workloads implemented on top of Lambda + ECS/Fargate/Kubernestes in near future. Lambda for all short running jobs (1-5mins) like image processing, emails, notifications, web services, APIs, glue code, state machines, etc and ECS for long running tasks like data processing, DB syncs, backups, video encoding etc etc.
I mean, a lots of features that natively supported in Go require crates or coding-by-hand in Rust, maybe that's why Go gets supported first.
Honestly the reason why official Rust support may never make sense is that it's so easy to use Neon to build native Node modules with Rust. Not one line of JS is needed and the impedance between the two languages is minimal. Go would require more hacks and copying thanks to both it and Node having their own GC. Basically Rust is flexible enough that official support isn't necessary whereas Go requires official support to avoid ugly hacks.
FWIW, I've never used Lambda to do what I'm suggesting above, but I've done it with GCP's equivalent and it works great.
I suspect the only thing Amazon will care about here is consumer demand, and potentially the ability of consumers to move from other platforms to theirs (e.g. if Google cloud supports <thing> they are more likely to do so in order to convince people to move).
Rust is a cool language, but it's use in HTTP services is not as widespread as Go, and there are a bunch of other languages I'd expect first (PHP, Ruby?)
The only thing that surprised me is that the Body struct element is a String, not an io.Reader. Can we not stream large bodies through API Gateway into a Lambda? Does it always read the whole thing before passing it onto my Lambda? Or what's the reason behind the String? I haven't tried this yet, so I'm curious.
More info here: https://docs.aws.amazon.com/lambda/latest/dg/limits.html
It's literally a method which has a single parameter class, and a single class returned...
Even if you're using node, java, golang, python. Other than the packaging. How is there any lock in?
Unless all of the providers have the same API to deploy functions, they are all trying to lock you in.
So not lock-in at the code level (unless your serverless app talks to S3 or whatever Amazon services), but lock-in of your whole devops process.
It sounds like, no matter what you do, you're locked in. Using Docker? Ah you're locked into Docker. Wrote your app in PHP, on you're locked into PHP now.
I just don't understand this whole 'lock-in' mindset, it's just absurd now.
If you write your application in any language, or use any framework or library, you're locked in, by today's standards.
Nobody cares if they are locked into x86, tcp/ip, and http. If you don't understand this difference as an engineer, you end up causing a big risk to your company (or clients) without even knowing it.
If you don't understand it, then it's probably not absurd.
Look into the whole free software movement and the history behind it (e.g. the evils of Microsoft in the 90s).
If a vendor can change a price on something that forces you to pay up or lose your system, you are locked in.
This isn't just some open source ideology without impacts either. It should be immediately obvious to anyone with any business acumen why making yourself beholden to the decisions of a single vendor is a bad position to be in.
Lambda is for executing individual functions, which implies that the execution environment must be language aware (could get away with JVM dynamic invoke or the .NET equivalent as well maybe). The way parameters are passed in, the concurrency model etc are all language specific.
It would be entirely possible to create a language agnostic Lambda runtime model, be it stdin/out/err, or TCP.
* relatively so
Spawning a process in a container is expensive. Not only do you need to wait for the container to init and mount its filesystems, but you then need to wait for the inner application to boot on every request, on top of that. So, allow containers to linger with applications booted, like Lambda does to save on those starts.
Since we aren't launching a new process for every call, we can't use CGI with its environment variables, etc, so we'll have to describe a new protocol for calling your functions, like... HTTP! The interface could be POST /call with JSON params.
I'm not sure how this model would differ semantically from the fully-managed, in-process system that Lambda uses. The management system can always kill containers that go over their memory limits or seem to be doing suspicious amounts of system calls when they're not executing a function. AWS can still go about providing in-process libraries for "supported" languages that implement these protocols, but if they also describe these protocols, then the community can go ahead and develop libraries for other languages that could eventually be adopted and officially supported.
In fact, the community is already producing libraries that use AWS's supported languages to allow hosting lambdas in other languages, via a CGI-like model! Just look at https://github.com/apex/apex - a NodeJS shim will spawn a command in the language of your choice, and then return the result back to Lambda.
You should time it then, it's incredibly slow these days
$ time docker run busybox /bin/true
.388s total
$ time docker run --net=none busybox /bin/true
.310s total
The above times, of over 300ms, are with docker 17.06 and the overlay2 driver on a powerful computer with an ssd.It's horrifically slow because the entire docker codebase is disgustingly bloated.
It has to fork something like 10 processes and synchronize between them (for everything from network initialization to runc hooks). It has to make ipc calls from docker-cli to dockerd to containerd and back again, allocating and freeing large chunks of memory for grpc along the way.
It's incredibly slow.
On the other hand, just forking and running something with namespacing options is effectively instant:
$ dir=$(mktemp -d)
$ docker run --name bbexport busybox /bin/true
$ cd $dir
$ docker export bbexport | tar x
$ time nsenter --root=$dir /bin/true
0.000s total
This is the reason they don't let you use arbitrary docker containers; docker containers are a ton more than a fork and some options. They're a bloated moving target.What lambda does allows them to optmize much more. In fact, lambda doesn't even have to fork a process sometimes because they can keep the e.g. javascript runtime running and then just add a new request into the existing process directly. They can freeze and thaw environments from known good states for request processing.
But most importantly, by not being compatible in any way with docker, they don't have to deal with the bloated mess that is docker and the ecosystem around it.
They don't have to load 3 daemons measuring 50MB into memory to run 100kb of javascript (which they can currently run more quickly than docker can even start the simpleist container)
$ time docker run alpine:3.6 sh -c exit
docker run alpine:3.6 sh -c exit 0.02s user 0.02s system 3% cpu 1.191 total
$ time sh -c exit
sh -c exit 0.00s user 0.01s system 94% cpu 0.007 total
Then add to that the cost of loading your function's code into memory. For an interpreted language, that is probably going to take a while as the runtime does a bunch of system calls and parses text files. Even for a compiled, statically-linked language like Go, the executable (a random binary I picked was 50MB) needs to be copied into RAM.For this reason, Lambda tries to keep your containers/function-wrapper-applications booted up in RAM: https://aws.amazon.com/blogs/compute/container-reuse-in-lamb...
It doesn't; you've always been able to use any language you want, by embedding it within the runtime of a supported language. This is just announcing proper, official support for it instead of having to rely on a workaround.
So the architecture of Lambda may indeed be a severe mismatch for running arbitrary containers.
Because they can present that as a separate service (Fargate) and bill more for it.
Fargate isn't exactly what you're describing, but it's a close match. It's in Amazon's best interests to charge people based on the amount of "DIY" they're willing to put up with, and that's why they offer a number of overlapping services at different price points.
I previously imagined Go support would arrive with a JSON on stdin/out/err protocol. Instead, your binary runs as a service with RPC endpoints. Unfortunately, it's a bit Go-oriented, so you'd have to implement some Go things (go/rpc, gobs) in your language/framework of choice to use it.
But, you get a (much) lower warm function startup cost because it's just an RPC call, all of which is neatly abstracted away for the Go programmer in the runtime library. Great for Go, bit of a bummer for those of us hoping for something more agnostic.
Yes, Lambda could support "Docker containers", but the more interesting problem to solve is the runtime model and protocol.
If you can imitate the go/rpc protocol, you an run any binary from any language on this, including LLVM based systems.
A version of this is already in play in https://github.com/apex/up
1) there's something about the lambda platform that just doesn't lend itself well to customer provided containers. a lot of people would AT LEAST have issues keeping image size reasonable.
2) they plan to add this. AWS is already investing in serverless container services, take a look at Fargate.
Would love to see stats comparing cold start times etc. for go vs. java/python/js. One would guess that it would be faster, but measurement trumps guessing.
Mind you the go compiler is also pretty damn fast, almost script language speed.
At the time at least (I don't know right now, it's been a long while since I touched a lambda function) it seemed that the bigger RAM share == the more CPU you get, which was not written anywhere in the documetation. And JVM startup times with crappy CPUs are indeed horrible. :)
Side note I think that should be an option for web servers as well for languages with managed memory. Light isolated non-threaded api endpoints shouldn't be interrupted by garbage collection.
I remember reading some discussion in an HN thread about FinTech developers who run Java with 100GB+ heaps and no garbage collector, and then reboot the application after the markets close. I can't find that specific thread, but I did find this which has a few nuggets on the same subject: https://news.ycombinator.com/item?id=6131786
Ive seen applications run and never GC after initial startup until they get bounced to update. Another problem with the big heap is that you still have tlab issues if you keep allocating.
There is a new-ish poc collector called the null collector that literally does nothing, not even instrumentation, i believe, of write barriers.
We always see idiomatic programs benched against each other but I'd really like to see high performance pure java against high performance pure go and others. Some of the low latency Java tricks we use I'm not sure if they can even be copied in other hll (not including c/c++).
Yep. There's a proposal by a couple of folks to get this implemented in the Golang runtime. The feature is aptly named 'Request Oriented GC'.
Ironically, I think that's what CGI did :D
https://making.pusher.com/golangs-real-time-gc-in-theory-and...
https://docs.aws.amazon.com/lambda/latest/dg/running-lambda-...