Related
I am trying to develop a serverless application which will use AWS SQS (Simple Queue Service), AWS SES (Simple Email Service) and AWS Lambda. The application will perform these steps:
get some messages in the SQS queue
trigger a Lambda function to handle all these messages
the Lambda will either send an email using AWS SES or an SMS using some 3rd party API, depending on the type of message
To test this out, I created the queue, lambda and configured SES, all manually using the web interface at https://aws.amazon.com . For the Lambda function, I simply typed my code in the web IDE provided at Lambda console. Since it was a very simple POC, it didnt need any testing and I got it to work.
Now, I want to turn this into a production ready application. My requirements:
code this entire application locally on my machine
test it locally in an environment similar to the one at AWS
publish the code to GitLab and then finally deploy it at AWS
all these resources (SQS queue, SES config, Lambda function) to be created automatically through code
Based on what I read online, I could find 3 different options for doing this:
AWS Cloudformation
AWS SAM
Serverless framework
My questions are:
For my use case, are serverless applications the correct technology or do I need something else like AWS SWF or AWS Step Functions? I also read about AWS Lambda applications. Are they something else?
Which is the best option among these in terms of cost, ease of setup and use? I checked that CloudFormation itself doesnt cost anything, you just have to pay for the services (SQS, SES, Lambda) being used but for Serverless, there are some costs involved for using the framework.
Are there some other options as well apart from these?
I will be using NodeJS for the code and only AWS as my cloud platform.
Short answer: yes, this is totally doable with Serverless functions and actually a typical Serverless use case.
Long answer:
It's not necessary to use AWS SWF or AWS Step Functions here. However, you could use Step Functions in case your process gets more complicated (e.g. more external services are involved and you need certain error handling, or you want to improve parallel processing powers).
First of all, CloudFront is not comparable to AWS SAM or Serverless Framework. Did you mean AWS CloudFormation instead? CloudFront is a CDN to serve (and cache) any kind of content whereas CloudFormation is a tool to describe your infrastructure as code.
CloudFormation is the "basis" for AWS SAM and Serverless Framework
because they both translate their template code to CloudFormation
code in the end. However, CloudFormation makes developing Serverless
Functions a bit complicated in my opinion. That's why tools like AWS
SAM or Serverless Framework popped up at some point. AWS SAM is
basically an extension of CloudFormation, i.e. it provides
additional resource types like AWS::Serverless::Function but
everything else is CloudFormation. Serverless Framework also lets
you add CloudFormation resources but has its own syntax for
specifying Serverless Functions.
In terms of costs, CloudFormation, AWS SAM, and Serverless Framework are all
free. However, you can use some premium features of Serverless Framework but you don't have to. However, CloudFront is not free to use - but I believe it wasn't the service you were looking for. Besides that, for SQS, SES and Lambda you only pay for what you use.
I personally prefer AWS SAM because you are closer to CloudFormation code and compared to Serverless Framework, you don't need a plugin for some things to circumvent the abstractions that the Serverless Framework does for you. You'll notice this for 'bigger' projects where you are leaving the standard hello world examples. On the other side, the Serverless Framework is quite popular and hence, there are many resources out there to help you. Up to you what you prefer :)
In terms of infrastructure tooling, you could have a look at AWS CDK (a good starting point is cdkworkshop.com) which is becoming more and more popular.
For local development, you can have a look at Localstack. The free version supports emulating SQS and SES locally, so that should be helpful.
I am developing a "micro-services" application using AWS API Gateway with either Lambda or ECS for compute. The issue now is communication between services are via API calls through the API gateway. This feels inefficient and less secure than it can be. Is there a way to make my microservices talk to each other in a more performant and secure manner? Like somehow talk directly within the private network?
One way I thought of is multiple levels of API gateway.
1 public API gateway
1 private API gateway per microservice. And each microservice can call another microservice "directly" inside the private network
But in this way, I need to "duplicate" my routes in 2 levels of API ... this does not seem ideal. I was thinking maybe use {proxy+}. So anything /payment/{proxy+} goes to payment API gateway and so on - theres still 2 levels of API gateway ... but this seem to be the best I can go?
Maybe there is a better way?
There are going to be many ways to build micro-services. I would start by familiarizing yourself with the whitepaper AWS published: Microservices on AWS, Whitepaper - PDF version.
In your question you stated: "The issue now is communication between services are via API calls through the API gateway. This feels inefficient and less secure than it can be. Is there a way to make my microservices talk to each other in a more performant and secure manner?"
Yes - In fact, the AWS Whitepaper, and API Gateway FAQ reference the API Gateway as a "front door" to your application. The intent of API Gateway is to be used for external services communicating to your AWS services.. not AWS services communicating with each other.
There are several ways AWS resources can communicate with each other to call micro-services. A few are outlined in the whitepaper, and this is another resource I have used: Better Together: Amazon ECS and AWS Lambda. The services you use will be based on the requirements you have.
By breaking monolithic applications into small microservices, the communication overhead increases because microservices have to talk to each other. In many implementations, REST over HTTP is used as a communication protocol. It is a light-weight protocol, but high volumes can cause issues. In some cases, it might make sense to think about consolidating services that send a lot of messages back and forth. If you find yourself in a situation where you consolidate more and more of your services just to reduce chattiness, you should review your problem domains and your domain model.
To my understanding, the root of your problem is routing of requests to micro-services. To maintain the "Characteristics of Microservices" you should choose a single solution to manage routing.
API Gateway
You mentioned using API Gateway as a routing solution. API Gateway can be used for routing... however, if you choose to use API Gateway for routing, you should define your routes explicitly in one level. Why?
Using {proxy+} increases attack surface because it requires routing to be properly handled in another micro-service.
One of the advantages of defining routes in API Gateway is that your API is self documenting. If you have multiple API gateways it will become colluded.
The downside of this is that it will take time, and you may have to change existing API's that have already been defined. But, you may already be making changes to existing code base to follow micro-services best practices.
Lambda or other compute resource
Despite the reasons listed above to use API Gateway for routing, if configured properly another resource can properly handle routing. You can have API Gateway proxy to a Lambda function that has all micro-service routes defined or another resource within your VPC with routes defined.
Result
What you do depends on your requirements and time. If you already have an API defined somewhere and simply want API Gateway to be used to throttle, monitor, secure, and log requests, then you will have API Gateway as a proxy. If you want to fully benefit from API Gateway, explicitly define each route within it. Both approaches can follow micro-service best practices, however, it is my opinion that defining each public API in API Gateway is the best way to align with micro-service architecture. The other answers also do a great job explaining the trade-offs with each approach.
I'm going to assume Lambdas for the solution but they could just as well be ECS instances or ELB's.
Current problem
One important concept to understand about lambdas before jumping into the solution is the decoupling of your application code and an event_source.
An event source is a different way to invoke your application code. You mentioned API Gateway, that is only one method of invoking your lambda (an HTTP REQUEST). Other interesting event sources relevant for your solution are:
Api Gateway (As noticed, not effective for inter service communication)
Direct invocation (via AWS Sdk, can be sync or async)
SNS (pub/sub, eventbus)
There are over 20+ different ways of invoking a lambda. documentation
Use case #1 Sync
So, if your HTTP_RESPONSE depends on one lambda calling another and on that 2nd lambdas result. A direct invoke might be a good enough solution to use, this way you can invoke the lambda in a synchronous way. It also means, that lambda should be subscribed to an API Gateway as an event source and have code to normalize the 2 different types of events. (This is why lambda documentation usually has event as one of the parameters)
Use case #2 Async
If your HTTP response doesn't depend on the other micro services (lambdas) execution. I would highly recommend SNS for this use case, as your original lambda publishes a single event and you can have more than 1 lambda subscribed to that event execute in parallel.
More complicated use cases
For more complicated use cases:
Batch processing, fan-out pattern example #1 example #2
Concurrent execution (one lambda calls next, calls next ...etc) AWS Step functions
There are multiple ways and approaches for doing this besides being bound to your current setup and infrastructure without excluding the flexibility to implement/modify the existing code base.
When trying to communicate between services behind the API Gateway is something that needs to be carefully implemented to avoid loops, exposing your data or even worst, blocking your self, see the "generic" image to get a better understanding:
While using HTTP for communicating between the services it is often common to see traffic going out the current infrastructure and then going back through the same API Gateway, something that could be avoided by just going directly the other service in place instead.
In the previous image for example, when service B needs to communicate with service A it is advisable to do it via the internal (ELB) endpoint instead of going out and going back through the API gateway.
Another approach is to use "only" HTTP in the API Gateway and use other protocols to communicate within your services, for example, gRPC. (not the best alternative in some cases since depends on your architecture and flexibility to modify/adapt existing code)
There are cases in where your infrastructure is more complex and you may not communicate on demand within your containers or the endpoints are just unreachable, in this cases, you could try to implement an event-driven architecture (SQS and AWS Lambda)
I like going asynchronous by using events/queues when possible, from my perspective "scales" better and must of the services become just consumers/workers besides no need to listen for incoming request (no HTTP needed), here is an article, explaining how to use rabbitmq for this purpose communicating microservices within docker
These are just some ideas that hope could help you to find your own "best" way since is something that varies too much and every scenario is unique.
I don't think your question is strictly related to AWS but more like a general way of communication between the services.
API Gateway is used as an edge service which is a service at your backend boundary and accessible by external parties. For communication behind the API Gateway, between your microservices, you don't necessary have to go through the API Gateway again.
There are 2 ways of communication which I'd mention for your case:
HTTP
Messaging
HTTP is the most simplistic way of communication as it's naturally easier to understand and there are tons of libraries which makes it easy to use.
Despite the fact of the advantages, there are a couple of things to look out for.
Failure handling
Circuit breaking in case a service is unavailable to respond
Consistency
Retries
Using service discovery (e.g. Eureka) to make the system more flexible when calling another service
On the messaging side, you have to deal with asynchronous processing, infrastructure problems like setting up the message broker and maintaining it, it's not as easy to use as pure HTTP, but you can solve consistency problems with just being eventually consistent.
Overall, there are tons of things which you have to consider and everything is about trade-offs. If you are just starting with microservices, I think it's best to start with using HTTP for communication and then slowly going to the messaging alternative.
For example in the Java + Spring Cloud Netflix world, you can have Eureka with Feign and with that it's really easy to use logical address to the services which is translated by Eureka to actual IP and ports. Also, if you wanna use Swagger for your REST APIs, you can even generate Feign client stubs from it.
I've had the same question on my mind for a while now and still cannot find a good generic solutions... For what it's worth...
If the communication is one way and the "caller" does not need to wait for a result, I find Kinesis streams very powerful - just post a "task" onto the stream and have the stream trigger a lambda to process it. But obviously, this works in very limited cases...
For the response-reply world, I call the API Gateway endpoints just like an end user would (with the added overhead of marshaling and unmarshaling data to "fit" in the HTTP world, and unnecessary multiple authentications).
In rare cases, I may have a single backend lambda function which gets invoked by both the Gateway API lambda and other microservices directly. This adds an extra "hop" for "end users" (instead of [UI -> Gateway API -> GatewayAPI lambda], now I have [UI -> Gateway API -> GatewayAPI lambda -> Backend lambda]), but makes microservice originated calls faster (since the call and all associated data no longer need to be "tunneled" through an HTTP request). Plus, this makes the architecture more complicated (I no longer have a single official API, but now have a "back channel" direct dependencies).
If i understood the whole concept correctly, the "serverless" architecture assumes that instead of using own servers or containers, one should use bunch of aws services. Usually such architecture includes Amazon API Gateway, bunch of Lambda functions and DynamoDB (or alternative) for storing data and state, as Lambda can't keep state. And such services as EC2 is not participating in all this, well, because this is a virtual server and it diminish all the benefits of serverless architecture.
All this looks really cool, but i feel like i'm missing something important, because right now this seems to be not applicable for such cases as real time applications.
Say, i have 2 users online. One of them performs an action in an app, which triggers changes in database, which in turn, should trigger changes in the second user app.
The conventional way to send some data or command from server to client is websocket connection. But with serverless architecture there seem to be no way to establish and maintain websocket connection. So... where did i misunderstood the concept? Or, if i understood everything correctly, then how do i implement the interactions between 2 users as described above?
where did i misunderstood the concept?
Your observation is correct. It doesn't work out of the box using API Gateway and Lambda.
Applicable solution as described here is to use AWS IoT - yes, another AWS Service.
Serverless isn't just a matter of Lambda, API Gateway and DynamoDB, it's much bigger than that. One of the big advantages to Serverless is the operational burden that it takes off your plate. No more patching, no more capacity planning, no more config management. Those may seem trivial but doing those things well and across a significant fleet of instances is complex, expensive and time consuming. Another benefit is the economics. Public cloud leverages utility billing, meaning you pay for what you run whether or not you actually use it. With AWS most of the billing per service is by hour but with Lambda it's per 100ms. The cheapest EC2 instance running for a full month is about $10/m (double that for redundancy). $20 in Lambda pricing gets you millions of invocations so for most cases serverless is significantly cheaper.
Serverless isn't for everything though, it has it's limitations, for example it's not meant for running binaries. You can't run nginx in Lambda (for example), it's only meant to be a runtime environment for the programming languages that it supports. It's also specifically meant for event based workloads, which is perfect for microservice based architectures. Small independent discrete pieces of compute doing work that when done they send an event to another(s) to do something else and if needed return a response.
To address your concerns about realtime processing, depending on what your code is doing your Lambda function could complete in less than 100ms all the way up to 5 minutes. There are strategies to optimize it's duration time but in general it's for short lived work which is conducive of realtime scenarios.
In your example about the 2 users interacting with the web app and the db, that could very easily be built using serverless technologies with one or 2 functions and a DynamoDB table. The total roundtrip time could be as low as milliseconds if not seconds, it really all depends on your code and what it's doing. These would all be HTTP calls so no websockets needed. Think of a number of APIs calling each other and your Lambda code is the orchestrator.
You might want to look at SNS (simple notification service). In your example, if app user 2 is a a subscriber to an SNS topic, then when app user 1 makes a change that triggers an SNS message, it will be pushed to the subscriber (app user 2). The message can be pushed over several supported protocols (Amazon, Apple, Google, MS, Baidu) in addition to SMTP or SMS. The SNS message can be triggered by a lambda function or directly from a DynamoDB stream after an update (a database trigger). It's up to the app developer to select a message protocol and format. The app only has to receive messages through its native channels. This may not exactly be millisecond-latency 'real-time', but it's fast enough for all but the most latency-sensitive applications.
I've been working on an AWS serverless application for several months now, and am amazed at the variety of services available. The rate of improvement and new features being added is enough to leave you out-of-breath.
I'm working on a new game project at the moment that will consist of a React Native front-end and a Lambda-based back-end. The app requires some real time features such as active user records, geofencing, etc.
I was looking at Firebase's Realtime Database that looks like a really elegant solution for real-time data sync but I don't think AWS has anything quite like it.
The 3 options I could think of for "serverless" realtime using only AWS services are:
Option 1: AWS IoT Messaging over WebSockets
This one is quite obvious, a managed WebSockets connection through the IoT SDK. I was thinking of triggering Lambdas in response to inbound and outbound events and just use WebSockets as the realtime layer, building custom handling logic on the app client as you typically would.
The downside to this, at least compared to Firebase, is that I will have to handle the data in the events myself which will add another layer of management on top of WebSockets and will have to be standardized with the API data layer in the application's stores.
Pros:
Scalable bi-directional realtime connection
Cons:
Only works when the app is open
Message structure needs to be implemented
Multiple transport layers to be managed
Option 2: Push-triggered re-fetch
Another option is to use push notifications as real-time triggers but use a regular HTTP request to API Gateway to actually get the updated payload.
I like this approach because it sticks to only one transport layer and a single source of truth for application state. It will also trigger updates when the app is not open since these are Push Notifications.
The downside is that this is a lot of custom work with potentially difficult mappings between push notifications to the data that needs to be fetched.
Pros:
Push notifications work even when app is closed
Single source of truth, transport layer
Cons:
Most custom solution
Will involve many more HTTP requests overall
Option 3: Cognito Sync
This is newer to me and I'm not sure if it can actually be interfaced with from the server.
Cognito Sync offers user state sync. across devices complete with offline support and is part of the Cognito SDK which I'll be using anyway. It sounds like just what I'm looking for but couldn't find any conclusive evidence as to whether it is possible to modify, or "trigger", updates from AWS and not just from one of the devices.
Pros:
Provides an abstracted real-time data model
Connected to Cognito user records OOTB
Cons:
Not sure if can be modified or updated from Lambdas
I'm wondering if anyone has experience doing real-time on AWS as part of a Lambda-based architecture and if you have an opinion on what is the best way to proceed?
I asked a similar question to the AWS Support, and this was their response.
My question to them:
What's the group of AWS services (if it's possible) to give that same
in-browser real-time DBaaS feel like Firebase?
AWS Cognito seems to be great for user-accounts. Is there anything
similar for the WebSockets / real-time DB part?
Their response:
To your question, Firebase is closest to the AWS service AWS
MobileHub. You can check out more details below about mobilehub from
below link.
https://aws.amazon.com/mobile/details/
https://aws.amazon.com/mobile/getting-started/
"AWS Cognito seems to be great for user-accounts. Is there anything
similar for the WebSockets / real-time DB part?"
Amazon Dynamodb is a fast and flexible NoSQL database service for all
applications that need consistent, single-digit millisecond latency at
any scale. It is a fully managed cloud database and supports both
document and key-value store models. Its flexible data model, reliable
performance, and automatic scaling of throughput capacity, makes it a
great fit for mobile, web, gaming, ad tech, IoT, and many other
applications.
Amazon Dynamodb can be further optimized with Amazon DynamoDB
Accelerator (DAX) which is a fully managed, highly available,
in-memory cache that can reduce Amazon DynamoDB response times from
milliseconds to microseconds, even at millions of requests per second.
For more information, please see below documentation.
https://aws.amazon.com/dynamodb/getting-started/
https://aws.amazon.com/dynamodb/dax/
Should you have any further questions, please do not hesitate to let
me know.
Thanks.
Best regards,
Tayo O. Amazon Web Services
Check out the AWS Support Knowledge Center, a knowledge base of
articles and videos that answer customer questions about AWS services:
https://aws.amazon.com/premiumsupport/knowledge-center/?icmpid=support_email_category
Also while researching this answer I also found this, looks interesting:
https://aws.amazon.com/blogs/database/how-to-build-a-chat-application-with-amazon-elasticache-for-redis/
The comments to that article is interesting as well.
Jacob Wakeem:
What advantage this
approach have over using aws iot? It seems that iot has all these
functionality without writing a single line of code and with
server-less architecture.
Sam Dengler:
The managed PubSub feature in the AWS IoT
service is also a good approach to message-based applications, like
the one demonstrated in the article. With Elasticache (Redis),
customers who use Pub/Sub are typically also using Redis as a data
store for other use cases such as caching, leaderboards, etc. With
that said, you could also use ElastiCache (Redis) with the AWS IoT
service by triggering an AWS Lambda function via the AWS IoT rules
engine. Depending on how the message-based application is architected
and how the data is leveraged, one solution may be a better fit than
the other.
Check out AWS AppSync for some of these realtime and offline features using different data sources, including databases search and compute.
AWS Amplify is AWS's modern answer to Firebase.
Fastest way to build mobile and web applications
AWS Amplify is a development platform for building secure, scalable
mobile and web applications. It makes it easy for you to authenticate
users, securely store data and user metadata, authorize selective
access to data, integrate machine learning, analyze application
metrics, and execute server-side code. Amplify covers the complete
mobile application development workflow from version control, code
testing, to production deployment, and it easily scales with your
business from thousands of users to tens of millions. The Amplify
libraries and CLI, part of the Amplify Framework, are open source and
offer a pluggable interface that enables you to customize and create
your own plugins.
Sounds like AWS Serverless is most suited alternative.
Also wondering: AWS vs Firebase - Is It Even a Fair Fight?
AWS Amplify. You can find more information here: AWS Amplify
You could consider using supabase.
It is opensource and can be installed onto ec2 / docker containers.
https://supabase.com/docs/guides/hosting/docker
I've found the hosted solution / free really poewrful to get up and running quickly. (yet to deploy to aws)
I know this is an old question, but nowadays AWS offers AppSync... a service that destroys Firebase RDB in every aspect
I'm still trying to wrap my mind around the limitations of AWS Lambda, especially now that AWS API Gateway opens up a lot of options for serving REST requests with Lambda.
I'm considering building a web app in Angular with Lambda serving as the back-end.
For simple CRUD stuff it seems straightforward enough, but what about authentication? Would I be able to use something like Passport within Lambda to do user authentication?
Yes, you can do pretty much anything, just store your session on an AWS hosted database (RDS, Dynamo, etc). But be aware exactly you are buying with lambda. It has a lot of trade-offs.
Price: An EC2 server costs a fixed price per month, but lambda has a cost per call. Which is cheaper depends on your usage patterns. Lambda is cheaper when nobody is using your product, EC2 is most likely cheaper as usage increases.
Scale: EC2 can scale (in many ways), but it's more "manual" and "chunky" (you can only run 1 server or 2, not 1.5). Lambda has fine-grained scaling. You don't worry about it, but you also have less control over it.
Performance: Lambda is a certain speed, and you have very little control. It may have huge latencies in some cases, as they spin up new containers to handle traffic. EC2 gives you many more options for performance tuning. (Box size, on-box caches, using the latest node.js, removing un-needed services from the box, being able to run strace, etc) You can pay for excess capacity to ensure low latency.
Code: The way you code will be slightly different in Lambda vs EC2. Lambda forces you to obey some conventions that are mostly best practice. But EC2 allows you to violate them for performance, or just speed of development. Lambda is a "black box" where you have less control and visibility when you need to troubleshoot.
Setup: Lambda is easier to setup and requires less knowledge overall. EC2 requires you to be a sysadmin and understand acronyms like VPC, EBS, VPN, AMI, etc.
Posting this here, since this is the first thread I found when searching for running NodeJS Passport authentication on Lamdba.
Since you can run Express apps on Lamda, you really could run Passport on Lambda directly. However, Passport is really middleware specifically for Express, and if you're designing for Lamda in the first place you probably don't want the bloat of Express (Since the API Gateway basically does all that).
As #Jason has mentioned you can utilizing a custom authorizer. This seems pretty straight-forward, but who wants to build all the possible auth methods? That's one of the advantages of Passport, people have already done this for you.
If you're using the Servlerless Framework, someone has built out the "Serverless-authentication" project. This includes modules for many of the standard auth providers: Facebook, Google, Microsoft. There is also a boilerplate for building out more auth providers.
It took me a good bunch of research to run across all of this, so hopefully it will help someone else out.
but what about authentication?
The most modular approach is to use API Gateway's Custom Authorizers (new since Feb'16) to supply an AWS Lambda function that implement Authentication and Authorization.
I wrote a generic Custom Authorizer that works with Auth0 a the 3rd-party Single-Sign-On service.
See this question also: How to - AWS Rest API Authentication
Would I be able to use something like Passport within Lambda to do user authentication?
Not easily. Passport relies on callback URLs which you would have to create and configure.