This article is about how we generally architect our products and platforms to be more resilient, low maintenance, and stress-free for our clients. This is also a biased opinion, as we've put many eggs into one cloud bucket (AWS). Our expertise in AWS services has allowed us to address many of the drawbacks you might hear about in other articles you have read.
Most organizations choose one path, but there is a middle ground between microservices and serverless infrastructure, and I'll also explain how some organizations might consider architecting their solutions. Again, this does require choosing AWS as a long term partner and incurring vendor lock-in, but if that's ok with you, as it is with us, you'll find that systems can run smoothly without a vast team and much cheaper for most use cases.
The goal has been simple for us: put as much responsibility on AWS as possible to keep operations running with low overhead while following the shared responsibility model. Serverless allows us to do this more effectively.
Servers Suck, and Vogels Knows Better!
The very first time I realized servers suck was back in June of 2012. It was my first day on the job, and we were launching a brand-new E-commerce site. I know it's not the best situation to find yourself in on the first day, but I was up for the challenge. Surprisingly, the launch went over smoothly, and I was more than happy to take the credit for a system someone else designed and architected. The real horrors started to creep their ugly heads when the weekend came, accompanied by a store-wide sale that would unleash massive traffic onto this new system I had just inherited. Bound to licensing that limited my use of the underlying software to 1 CPU, the system toppled over faster than a house of cards in a wind tunnel.
For the next week, we monitored the system's performance and were forced to do manual restarts as we worked tirelessly to build a suitable caching system that allowed our systems to breathe. During this time, I was introduced to the famous quote by Werner Vogels.
"...everything fails all the time."
I sat there questioning the life decisions I had made to that point. This quote comforted me, as it does for many people in my field. I knew that Mr. Vogels had once felt that dread I was feeling in those moments and that he was looking at me from his big cloud on the internet.
That horrible experience in my first couple of weeks and this quote developed a deep bias in me that would shape how I architect solutions for clients today. The quote taught me three things: never assume a system is ever bulletproof, AWS really gets me and knows what keeps me up at night, and servers just SUCK!
AWS Lambdas wouldn't be introduced for another two years, but I would like to imagine Mr. Vogels hearing my nerd prayers and working on a solution to my problems after that day, and from that day on, I accepted my new world view and looked for everything to support it. Mix this with the fact I'm really cheap and like to find ways to save on infrastructure; the past ten years have been an exercise in shedding the shackles of server dependence and embracing the elegance of ephemeral computing. It's been a journey of constant learning, experimentation, and optimization, always seeking the most efficient and cost-effective ways to build and run applications. From the early days of containerization to the serverless revolution, the quest for a truly hands-off, scalable, and resilient architecture has been my guiding star.
From Monoliths to Microservices
I was involved in early talks for a startup in 2010 that would utilize LXC (LinuX Containers) for a new hosting solution. Most of it went over my head at the time because my expertise was still mainly on the front-end JS/CSS of this whole web thing. It wouldn't be for another five years before I became a fanboy.
When Docker brought containers into the mainstream, I embraced the concept of microservices and containers. It freed me of the pain of Virtual Machines and ushered in an era of modularity and agility, allowing us to break down monolithic applications into smaller, independent services. This newfound freedom empowered us to develop, deploy, and scale individual components with unprecedented ease, fostering a culture of continuous delivery and experimentation. Like a master Lego builder, we could snap together different services, each with its own specific purpose, creating a flexible and adaptable architecture that could evolve alongside our ever-changing business needs.
Our first project in production utilized containers in AWS Elastic Beanstalk, of all things. As some might imagine, it wasn't the best example of continuous development, but it got the wheels spinning. We built a reusable user management service, a product service system, and a few other services that made us see ourselves as cutting edge engineers.
Soon after looking in the mirror and seeing the limitations of Beanstalk, the biggest one being the max service limit of ten, we moved our internal services inside Docker Swarm but quickly migrated to AWS Kubernetes because that’s what the cool kids were doing at the time, but also because Swarm kept falling over. We finally landed on AWS Elastic Container Services (ECS) because of its ease of use and lower costs.
We quickly saw many of the benefits a microservice architecture promised, mainly around decoupled code and fault isolation. However, I still had to hit that proverbial reset button when something broke down. Some services stopped working unexpectedly for whatever reason. My having to adjust the orchestration layer to make sure we have enough computing power and memory was still something in my tasks of things to do. That bothered me, but it wasn't my biggest annoyance.
The biggest annoyance and most nagging realization that loomed over my head was AWS Cognito! Cognito was a better version of our own user management microservice. Why would anybody spend time building a service like this when AWS is doing it for you WITH HIPPA COMPLIANCE INCLUDED? This nagging realization was that I had spent the time to build something AWS was doing better – not as a microservice, but in the ever growing serverless realm of products. Some might say there are great teams out there creating open source microservices like KeyCloak that allow you to avoid vendor lock-in while helping with time spent in development, but running these services still cost money and every minute someone isn’t logging in is money down the drain.
Serverless Salvation
While containers and microservices offered a significant leap forward from the monolithic nightmares of the past, that nagging feeling of "servers suck" never entirely dissipated, and AWS kept coming out with services for pennies that required no maintenance from us. The constant need to monitor, manage, and scale infrastructure, even with the help of orchestration tools like ECS, still felt like a burden. Thankfully, the winds of change were blowing, and on the horizon emerged a beacon of hope: serverless computing.
Diving into the Serverless Sea
Serverless, with its promise of "No servers? No problem!" immediately resonated with my inherent server aversion. The idea of focusing solely on writing code and letting the cloud provider handle the underlying infrastructure was like a dream come true. AWS Lambda, the poster child of serverless computing, became our new playground. With each function deployed, I felt a weight lifting off my shoulders. No more worrying about server provisioning, scaling, or patching – just pure, unadulterated coding bliss. And Lambdas are just the beginning.
While serverless functions like AWS Lambda form the core of this architectural style, diving deeper into the serverless world reveals a rich ecosystem of supporting services that truly unlock its potential. Embracing the serverless Kool-Aid means immersing yourself in an event-driven architecture, where services react and respond to events rather than waiting for direct calls. This paradigm shift opens doors to building highly decoupled, scalable, and responsive applications.
Here's a glimpse into the serverless toolbox:
- Event Sources: These are the triggers that set your serverless functions in motion. They can include cloud storage events (e.g., file uploads to S3), database changes (e.g., DynamoDB updates), HTTP API Gateway requests, and much more.
- Messaging Services: Tools like Amazon SQS and SNS act as communication channels between different parts of your application. They allow asynchronous message passing, ensuring loose coupling and reliable delivery.
- Workflow Orchestration: Services like AWS Step Functions help you coordinate complex workflows involving multiple serverless functions and other AWS services. They provide a visual interface for defining state machines and managing the execution flow.
- Databases: Serverless databases like Amazon DynamoDB offer on-demand scaling and pay-per-use billing, perfectly complementing your serverless functions.
- API Gateways: Services like Amazon API Gateway act as the front door for your serverless applications, handling API requests, authorization, and traffic management.
This is just a taste of the vast serverless landscape. Each service plays a crucial role in building a robust, event-driven architecture that can adapt to changing demands and deliver exceptional user experiences.
Pros That Made Me a Serverless Convert:
- Cost Efficiency: My inner cheapskate rejoiced at the pay-per-execution model. No more idle servers burning a hole in my (or our clients') pockets.
- Operational Nirvana: The shackles of infrastructure management were gone. We could finally focus on what we loved – building awesome applications.
- Scalability on Autopilot: Traffic spikes? No sweat. Serverless functions scaled seamlessly, handling whatever load was thrown their way.
- Development Velocity: With less operational overhead, development became a breeze. Time to market shrunk, and innovation flourished.
Challenges on the Serverless Seas
Of course, no technology is without its challenges. Serverless presented a few hurdles to overcome, but we've figured it out:
- Vendor Lock-in: Embracing AWS Lambda meant tying myself to the AWS ecosystem, which could limit flexibility in the future. However, I saw solutions to all of our needs inside AWS. Not to mention, AWS has been the leader in all things cloud for many years. I have all of the flexibility I need. Embrace AWS, and feel good about that decision. What I’ve noticed is that projects that are vendor agnostic, end up getting migrated over to AWS sooner or later. I never see them going from AWS to Azure or google.
- Cold Start Quirks: The occasional cold start latency was a minor annoyance but manageable with careful design and optimization. It is entirely acceptable for an API call to take a couple of seconds to load some data when your front-end assets are being served statically from a CDN.
- Monitoring and Debugging: Gaining visibility into serverless applications required adopting new tools and techniques. We've learned to utilize other services like Kenisis to handle logs at a higher volume.
- Limited Control: The serverless environment imposed some constraints, requiring adjustments to certain coding practices. For example, when writing Lambdas, you may use things like layers. We've avoided using this for testing purposes.
- Time to Deploy: I've seen teams complain about the time it takes to deploy ( sometimes 45 minutes for larger projects), but we've mitigated this with tools like Nx, which only deploys the logic that has changed.
So What Now?
Throughout this exploration, we've seen how serverless architecture, particularly within the AWS ecosystem, has revolutionized how we build and manage applications. By offloading infrastructure concerns to the cloud, we've unlocked remarkable benefits: cost efficiency that aligns with our "cheapskate" sensibilities, operational ease that allows us to focus on development rather than server babysitting, automatic scaling that effortlessly handles traffic surges, and accelerated development velocity that keeps us at the forefront of innovation.
While acknowledging the existence of challenges like vendor lock-in and occasional cold starts, we've demonstrated that these hurdles are easily surmountable through careful planning and optimization techniques. Our experience has solidified our belief that the advantages of serverless far outweigh any limitations, making it the ideal path forward for building resilient, low-maintenance, and stress-free systems for our clients and ourselves. Although we still utilize microservices via ECS ( Fargate) occasionally, we do this by regularly fusing it with Serverless architecture.
If you're ready to break free from the shackles of server management and embrace a future of agility and efficiency, Five & Done is here to guide you on your serverless journey. Our expert team has extensive experience designing, implementing, and optimizing serverless architectures within the AWS ecosystem.