When does AWS Lambda create ENI? - amazon-web-services

I know lambda will create ENI (which in turn will create a longer cold start) if it wants to access resources in VPC. However, I wish to know when does the lambda function create ENI?
Is it on the container's initialization? (which the developer has no control of)
or is it when we start a connection (running db.Connect() or something like it) with other resources e.g. RDS

ENI create every cold start.
https://docs.aws.amazon.com/lambda/latest/dg/vpc.html
When a Lambda function is configured to run within a VPC, it incurs an additional ENI start-up penalty. This means address resolution may be delayed when trying to connect to network resources.

Related

Is it possible to connect an AWS Lambda function without a VPC connection to AWS EFS?

I want to connect AWS EFS to my AWS Lambda function, without connecting the Lambda function to VPC. Is it possible to do this?
This is simply No. It's impossible.
EFS file systems are always created within a customer VPC, so Lambda functions using the EFS file system must all reside in the same VPC.
Like stated here (https://aws.amazon.com/blogs/compute/using-amazon-efs-for-aws-lambda-in-your-serverless-applications)
Lambda should be placed within same VPC where EFS is created.
There might be different reasons you didn't like to place your Lambda function in VPC:
Very slow initialization (Creating ENI, Attaching Lambda to it.. This takes long time significantly)
Additional configuration to place in VPC etc..
One solution is to use provisioned concurrency feature of Lambda (It comes with more costing)
In this way, you can get multiple Lambda functions ready to use any time by keeping it warm.
Cheers

How to get ENI attached to lambda using boto3

I understand that lambda attaches itself to an ENI when it is woken up from it's cold state. How do I get a handle on the ENI ( or all the ENIs) attached to the lambda using boto3?
The ENI created by lambda when you put it in a VPC is an AWS lambda-managed ENI.
There is no a single API call to get the ENI associated with a particular lambda function (to my knowledge at least).
Thus you would have to do it yourself. For example using describe_network_interfaces call to get the list of all ENI in a given vpc, and then filter out non-lambda ones.
For the filtering, a description of ENI could be useful. I checked now and the ENI which lambda service creates has the description in the form of:
AWS Lambda VPC <function name>
and the owner is amazon-aws.
I'm not certain if the ENI description is absolutely fixed and unique, but this seems as a good start.
To have Lambda delete the network interface, do the following:
For each unpublished Lambda function (the $LATEST version) that Lambda ENI Finder listed, change the Amazon VPC configuration to use a different subnet and security group. Or, you can disconnect the function from the Amazon VPC entirely.
For each published Lambda function version listed, delete the function version. Published versions can't be edited, so the VPC configuration can't be changed.
Run Lambda ENI Finder again to verify that the network interface is no longer in use. If no other functions or function versions are listed in the output, Lambda deletes the network interface for you within 24 hours.
For more information, you can check the below AWS Link
https://aws.amazon.com/premiumsupport/knowledge-center/lambda-eni-find-delete/
I hope this helps you.

EC2 to Lambda forwarding based on current usage

I am having long cold start times on our Lambda functions. We have tried "pinging" the Lambdas to keep them warm but that can get costly and seems like a poor way to keep performance up. We also have an EC2 instance running 24/7. I could theoretically "mirror" all of our Lambda functions to our EC2 instance to respond with the same data for our API call. Our Lambdas are on https://api.mysite.com and our EC2 is https://dev.mysite.com.
My question is could we "load balance?" traffic between the two. (Create a new subdomain to do the following) To have our dev subdomain (EC2) respond to all requests up until a certain "requests per minute" is hit. Then start to route traffic to our dev subdomain (Lambda) since we have enough traffic coming in to keep the Lambdas hot. Once traffic slows down, we move the traffic back over to our EC2.. Is this possible?
No, you can not do that with AWS Load balancer. What you can do is setup cloudwatch trigger to the lambda function which will map api.mysite.com to the lambda load balancer dns. Similarly, you can add trigger for low traffic which will redo dns entry.
If you are aware of rise in traffic, you can scheduled instances. Else you can also try AWS Fargate.
Hope this helps you.
Cloudwatch allows you to choose the number of triggers you wanna set for a lambda i.e. whenever an API is called, cloudwatch will trigger those many of the lambdas. This is one way you could achieve it. There's no way yet, to load balance between lambdas and instances.
You can configure your API to use Step functions which will orchestrate your lambda.

Connecting Cassandra from AWS Lambda

We are checking the feasibility of migrating one of our application to Amazon Web Services (AWS) . We decide to use AWS API Gateway to expose the services and AWS Lambda (java) for back end data processing. The lambda function has to fetch a large amount of data from our database.
Currently using Cassandra for data storage, which has been set up with in an EC2 instance and it has no public ip.
Can anyone suggest a way to access Cassandra(EC2) from AWS Lambda using the private Ip ( 10.0.x.x)?
Is it a right choice to use AWS Lambda for large scale applications?
Since your Cassandra instance is using private IP, you will need to configure your AWS lambda Network to use a VPC. It could be the VPC you are running Cassandra in, or a VPC you create for the purpose of your lambdas, and that you VPC-peer to your cassandra VPC. A few things to note from the documentation :
when your lambda runs in a VPC, it doesn't have internet access by default, you will need to configure a NAT for that.
There is an additional latency due to the configuration of the ENI (you only pay that penalty on cold start)
You need to make sure your lambda has the right permission to manage the ENI, you should use this role: AWSLambdaVPCAccessExecutionRole
Your plan to use API / AWS lambda has at least 3 potential issues which you need to consider carefully:
Cost. API gateway per request cost is higher than AWS lambda per request cost. Make sure you are familiar with the cost.
cold start. When AWS start an underlying container to execute your lambda, you pay a cold start latency (which get worse when using VPC due to the management of the ENI). If you execute your lambda concurrently, there will be multiple underlying containers. Each of them will have this cold start the first time. AWS tends to keep the underlying containers ready for a warm start, for a few minutes (users report 5 to 40 minutes). You might try to keep your container warm by pinging your aws lambda, obviously if you have multiple container in parallel, it is getting tricky.
Cassandra session. You will probably want to avoid creating and destroying your Cassandra session each time you invoke your lambda (costly). I haven't tried yet, but there are reports of keeping the session alive in a warm container, you might want to check this SO answer.
Having say all that, currently the biggest limitation in using AWS lambda is concurrent execution and cold start latency. For data processing, that's usually fine. For user-facing usage, the percentage of slow cold start might affect your user experience.

How to make a HTTP call reaching all instances behind amazon AWS load balancer?

I have a web app which runs behind Amazon AWS Elastic Load Balancer with 3 instances attached. The app has a /refresh endpoint to reload reference data. It need to be run whenever new data is available, which happens several times a week.
What I have been doing is assigning public address to all instances, and do refresh independently (using ec2-url/refresh). I agree with Michael's answer on a different topic, EC2 instances behind ELB shouldn't allow direct public access. Now my problem is how can I make elb-url/refresh call reaching all instances behind the load balancer?
And it would be nice if I can collect HTTP responses from multiple instances. But I don't mind doing the refresh blindly for now.
one of the way I'd solve this problem is by
writing the data to an AWS s3 bucket
triggering a AWS Lambda function automatically from the s3 write
using AWS SDK to to identify the instances attached to the ELB from the Lambda function e.g. using boto3 from python or AWS Java SDK
call /refresh on individual instances from Lambda
ensuring when a new instance is created (due to autoscaling or deployment), it fetches the data from the s3 bucket during startup
ensuring that the private subnets the instances are in allows traffic from the subnets attached to the Lambda
ensuring that the security groups attached to the instances allow traffic from the security group attached to the Lambda
the key wins of this solution are
the process is fully automated from the instant the data is written to s3,
avoids data inconsistency due to autoscaling/deployment,
simple to maintain (you don't have to hardcode instance ip addresses anywhere),
you don't have to expose instances outside the VPC
highly available (AWS ensures the Lambda is invoked on s3 write, you don't worry about running a script in an instance and ensuring the instance is up and running)
hope this is useful.
While this may not be possible given the constraints of your application & circumstances, its worth noting that best practice application architecture for instances running behind an AWS ELB (particularly if they are part of an AutoScalingGroup) is ensure that the instances are not stateful.
The idea is to make it so that you can scale out by adding new instances, or scale-in by removing instances, without compromising data integrity or performance.
One option would be to change the application to store the results of the reference data reload into an off-instance data store, such as a cache or database (e.g. Elasticache or RDS), instead of in-memory.
If the application was able to do that, then you would only need to hit the refresh endpoint on a single server - it would reload the reference data, do whatever analysis and manipulation is required to store it efficiently in a fit-for-purpose way for the application, store it to the data store, and then all instances would have access to the refreshed data via the shared data store.
While there is a latency increase adding a round-trip to a data store, it is often well worth it for the consistency of the application - under your current model, if one server lags behind the others in refreshing the reference data, if the ELB is not using sticky sessions, requests via the ELB will return inconsistent data depending on which server they are allocated to.
You can't make these requests through the load balancer, So you will have to open up the security group of the instances to allow incoming traffic from source other than the ELB. That doesn't mean you need to open it to all direct traffic though. You could simply whitelist an IP address in the security group to allow requests from your specific computer.
If you don't want to add public IP addresses to these servers then you will need to run something like a curl command on an EC2 instance inside the VPC. In that case you would only need to open the security group to allow traffic from some server (or group of servers) that exist in the VPC.
I solved it differently, without opening up new traffic in security groups or resorting to external resources like S3. It's flexible in that it will dynamically notify instances added through ECS or ASG.
The ELB's Target Group offers a feature of periodic health check to ensure instances behind it are live. This is a URL that your server responds on. The endpoint can include a timestamp parameter of the most recent configuration. Every server in the TG will receive the health check ping within the configured Interval threshold. If the parameter to the ping changes it signals a refresh.
A URL may look like:
/is-alive?last-configuration=2019-08-27T23%3A50%3A23Z
Above I passed a UTC timestamp of 2019-08-27T23:50:23Z
A service receiving the request will check if the in-memory state is at least as recent as the timestamp parameter. If not, it will refresh its state and update the timestamp. The next health-check will result in a no-op since your state was refreshed.
Implementation notes
If refreshing the state can take more time than the interval window or the TG health timeout, you need to offload it to another thread to prevent concurrent updates or outright service disruption as the health-checks need to return promptly. Otherwise the node will be considered off-line.
If you are using traffic port for this purpose, make sure the URL is secured by making it impossible to guess. Anything publicly exposed can be subject to a DoS attack.
As you are using S3 you can automate your task by using the ObjectCreated notification for S3.
https://docs.aws.amazon.com/AmazonS3/latest/dev/NotificationHowTo.html
https://docs.aws.amazon.com/cli/latest/reference/s3api/put-bucket-notification.html
You can install AWS CLI and write a simple Bash script that will monitor that ObjectCreated notification. Start a Cron job that will look for the S3 notification for creation of new object.
Setup a condition in that script file to curl "http: //127.0.0.1/refresh" when the script file detects new object created in S3 it will curl the 127.0.0.1/refresh and done you don't have to do that manually each time.
I personally like the answer by #redoc, but wanted to give another alternative for anyone that is interested, which is a combination of his and the accepted answer. Using SEE object creation events, you can trigger a lambda, but instead of discovering the instances and calling them, which requires the lambda to be in the vpc, you could have the lambda use SSM (aka Systems Manager) to execute commands via a powershell or bash document on EC2 instances that are targeted via tags. The document would then call 127.0.0.1/reload like the accepted answer has. The benefit of this is that your lambda doesn't have to be in the vpc, and your EC2s don't need inbound rules to allow the traffic from lambda. The downside is that it requires the instances to have the SSM agent installed, which sounds like more work than it really is. There's AWS AMIs already optimized with SSM agent stuff, but installing it yourself in the user data is very simple. Another potential downside, depending on your use case, is that it uses an exponential ramp up for simultaneous executions, which means if you're targeting 20 instances, it runs one 1, then 2 at once, then 4 at once, then 8, until they are all done, or it reaches what you set for the max. This is because of the error recovery stuff it has built in. It doesn't want to destroy all your stuff if something is wrong, like slowly putting your weight on some ice.
You could make the call multiple times in rapid succession to call all the instances behind the Load Balancer. This would work because the AWS Load Balancers use round-robin without sticky sessions by default, meaning that each call handled by the Load Balancer is dispatched to the next EC2 Instance in the list of available instances. So if you're making rapid calls, you're likely to hit all the instances.
Another option is that if your EC2 instances are fairly stable, you can create a Target Group for each EC2 Instance, and then create a listener rule on your Load Balancer to target those single instance groups based on some criteria, such as a query argument, URL or header.