Serverless Strangler Pattern on AWS
AWS re:Invent hasn’t even arrived, yet AWS has already started churning out several new features ahead of the conference, as announced by the CEO of AWS a few weeks ago:
I want to focus in on a few key new features in the serverless realm that I believe will enable developers to apply the Strangler Pattern with AWS Lambda’s to existing API’s. Ultimately, this is what I believe the FaaS world has needed to get existing software solutions using FaaS implementations to problems instead of continuing to roll new features inside of a monolith or as new services in a microservice system.
The strangler pattern was probably best highlighted by a post from Martin Fowler back in 2004. Recently however, we have seen a lot of talk about this pattern in the microservices realm for ways to choke out monolithic applications. In a microservices based approach — particularly for one that is based on HTTP traffic to a monolith, the idea is fairly simple. You put a facade in place that receives all of the traffic originally destined to the monolith, and the facade can either act as a basic Layer 7 router for HTTP traffic, or it may do more complex interactions between the monolith and the new set of microservices. Microsoft has a good short post on this pattern.
Ok, I get that — I’ve heard of the strangler pattern, and I’ve heard of how it applies to monoliths and how folks are doing it with Docker, Kubernetes, AWS ECS, and the like…and I’ve seen how the AWS Application Load Balancer can be used for path-based routing to split up monoliths on HTTP routing to different EC2 or ECS services, but how do I implement a Serverless Strangler Pattern?
No matter where you are in your journey — a monolith or you have already split up your monolith into a nicely defined set of microservices with an API Gateway in front of it (I’m not talking about an AWS API Gateway, but rather the microservices architectural pattern) — the problem of how to apply FaaS in both of these environments is the same. Now you are at a critical junction — your end goal (via the strangler) is that you don’t have servers to manage (including that “API Gateway” that you rolled when you did your microservices based approach the first time.) This is where the Serverless FaaS problem gets interesting…how do you put serverless technology all the way out front, yet still have a high degree of control?
To properly apply a strangler pattern using Serverless FaaS (henceforth just called Lambda) — you would need all traffic first routing through something where you don’t manage the servers. You really only had one solid option until earlier this week and that was using AWS API Gateway as your strangler facade. AWS API Gateway is becoming a great product, but it has/had some limitations. Binary content and HTTP Proxying (to a public HTTP service only, no VPC support — yet) didn’t used to be supported until last year, but probably the larger downside was that API Gateway managed a CDN as its endpoint and you had no control over that CDN. What I really wanted was the ability to have a Layer 7 load balancer approach (like an ALB) out in front of the API Gateway but that could go even further than that and route traffic based on a set of programatic rules that I define and route it to either Lambda’s (via an AWS API Gateway) or to my custom rolled API Gateway or monolith. In the end — it was about control — the strangler facade is an extremely important piece of tech to manage while the strangle is going on, and it needs to be something I can evolve — potentially for years depending on the size of the system I am strangling. Ideally, the best strangler is probably something that I can write and manage as my own program.
The two announcements that enable a programatic Serverless Strangler Pattern on AWS were announced in the last 48 hours and in the last couple of weeks:
- Amazon API Gateway Supports Regional API Endpoints (November 2, 2017)
- Lambda@Edge Now Supports Content-Based Dynamic Origin Selection, Network Calls from Viewer Events, and Advanced Response Generation (November 21, 2017)
Let’s break these down and how they can help us implement the Strangler Pattern with AWS Lambda.
By allowing you to deploy your API Gateway as a regional based endpoint, now you have far greater control over your strangler — because we aren’t going to use the API Gateway as the strangler facade — but rather as the thing that we want to eventually fully replace the system we are trying to strangle. Again, you could technically do a strangler pattern with API Gateway since they announced HTTP Proxy support, binary content, and catch-all path based routing but by keeping it separate it allows for far greater flexibility. For instance, one of the best things about the Lambda ecosystem is the ability to cheaply operate in multiple regions. If I am trying to strangle something while also releasing my new serverless features in multiple regions, I don’t want to have to deploy the very thing I am trying to strangle in other regions, too! I might only want my Lambdas to be multi-region deployed and I don’t want to wait until I’ve shut down the last bit of my old system before I go multi-region with my new functionality. Or, if there are specific parts of your application that can be deployed to multiple regions and other parts that need to be centralized to a single region (due to complexities that you are not ready to tackle in the current state of your journey, e.g. distributed data), then it would be ideal to keep your API gateways as regional based services. Each region might have different parts of the functionality of the complete system. However, this all leaves a large question to be answered — where is your strangler facade, and how would you know when to route certain requests to an AWS API gateway in one region, vs another, and yet still other requests to the system you are trying to strangle?
Lambda @ Edge Dynamic Origin Selection
This is the announcement that underpins the entire capability of implementing a programatic Serverless Strangler Pattern. The key is the ability to dynamically switch origins where a request is routed. Now we can programmatically build as sophisticated of a strangler as we want that is itself a Lambda — but one that is running on a CDN that we fully manage ourselves! The Lambda could look at any number of parts of the request to determine how to route the request — should it go to the monolith? Should it go to an API Gateway that we implemented? Should it go an AWS API Gateway in XYZ Region? The choice is up to us — and it’s something that over time will allow us to strangle out our monolith or container based microservices with a fully serverless architecture without needing to do that “big bang” migration that the strangler pattern was meant to prevent you from doing in the first place. Additionally it solves our concern of the strangler being an actual program that we can manage and evolve over time, separate from anything we might implement in an AWS API Gateway.
Here’s an example of what this might look like:
Lambda @ Edge is really beginning to shine. I’ve outlined how you might be able to use it to implement a serverless strangler pattern on AWS. However, you shouldn’t limit yourself to using it purely as an advanced HTTP router — there may be entire apps you could run in the edge itself instead of shipping requests back to an API Gateway within a Region.
I get the feeling this is only the beginning of the Serverless ecosystem announcements for re:Invent. Let’s see what the next week brings!