Most architecture talks describe a system that already works. Daniele Frasca's is about the eighteen months of iteration that got there, and his framing is deliberately unglamorous: "there is not a blueprint to follow. It's just iteration, learning to make things suck less." His central thesis is that technical debt is usually discussed as code debt, but the debt that actually hurt his team was architectural — an architecture that did not grow with the business. Everything else in the talk follows from that: the patterns he adopted, the trade-offs he accepted, and the argument he had to make to management about what availability costs.
Frasca is an AWS Serverless Community Builder working in Munich for ProSiebenSat.1 Media, a German broadcaster. He was part of the group building Joyn, a streaming application available in the DACH region — Germany, Austria, and Switzerland — serving millions of requests. The rebuild was done by a team of two developers with, in his words, no prior AWS experience. InfoQ recorded the 46-minute talk at InfoQ Dev Summit Munich; the recording and transcript are dated May 11, 2026. These notes report what Frasca presented; supplementary explanation is labeled as such.
What You Will Learn
- Why an architecture can be individually correct at every component and still fail as a whole once the business outgrows it.
- How the Hub and Spoke pattern with Amazon EventBridge gives every service a single integration interface and restores a single source of truth.
- Why event size limits force a choice between sparse and full-state events, and how the claim check pattern sidesteps the limit entirely.
- When database replication is a legitimate alternative to event-driven integration, and the coupling you inherit if you choose it.
- How to compose service-level SLAs into a realistic availability number, and why the "most serverless" stack was not the most available one.
- How cell-based architecture multiplies concurrency limits and shrinks blast radius using the same code and the same CI pipeline.
- How a three-layer cache reduced database traffic to under 10% and made active-active multi-region viable.
- The specific cost levers — API Gateway to load balancer, Lambda-to-Fargate traffic shifting — that made multi-region affordable at this scale.
The Starting Point and Why It Failed
What users expect from a streaming app is, Frasca says, very simple and very demanding: they open the app and they want to play video. They do not care that the Bundesliga is showing in Germany and something else is showing in another country — they want everything in the app, with almost real-time synchronization across platforms. That expectation is why data consistency, not throughput, became the first thing the team fixed. "These actually are our user expectations that are actually very difficult to meet when nothing really works."
The original architecture was conventional and, Frasca is careful to say, not wrong in principle: a worker subscribed to Kafka topics, performed some transformation, and stored results in a database; a GraphQL API in front of that database was "bombarded" by the frontend. What made it fail was everything around the shape. The database was a single node with no cache. Every traffic spike crashed the system. Deployment took an hour and a half. One team of two owned six services with no shared standards.
The data problem was the more insidious one. Each of those six services subscribed to the same Kafka topic and then did completely different things with it: different validation, different transformations, some persisting and some not, some throwing errors and some swallowing them. The user-visible symptom was that a video appeared on one page and was missing from another, or the details page contradicted the listing. For the team, an investigation that should have taken minutes took hours, because there was no authoritative version of a record.
A second structural problem was boundary erosion. Services that should have communicated with each other were publishing their internal state onto the company-wide Kafka bus, which Frasca names outright as an antipattern. He is honest about the cause: doing it correctly with Kafka means standing up additional infrastructure, such as a second internal bus, and "people usually are lazy to do the job right in the first place. I am lazy as well." That candour matters, because the pattern he adopts next is essentially a way of making the correct thing the easy thing.
The move to serverless was not, he stresses, aesthetic. "Not because serverless is cool, only because it lets us focus on what really matters, the code." The immediate wins were that scaling stopped being their problem and deployment dropped from ninety minutes to minutes.
The Management Conversation
Frasca returns repeatedly to a constraint triangle that shapes every later decision. What management writes down is "everything available, everything scalable, and cheap." His position is blunt: you cannot have it both ways, and this needs to be very clear to management. In a streaming business the feedback loop is brutally short — if something goes down, you know immediately, because users are on social media and the manager is on the phone.
His resolution is not to win the argument but to relocate it. The builder's job, as he describes it, is to make the trade-off transparent and force the decision makers to own it. "If my manager gets the responsibility to get a downtime during prime time, to me, I can put Excel as a database." Read uncharitably that sounds like abdication; read in context it is the opposite — he is insisting that availability is a business risk decision with a price tag, not an engineering preference, and that engineers should present the price rather than absorb the risk silently. Every cost number later in the talk exists to make that conversation possible.
Fixing Data Consistency: Hub and Spoke
The first half of the rebuild targeted data quality. The solution Frasca describes is the Hub and Spoke pattern, which he also calls a "bus mesh." There are three actors.
| Component | Role |
|---|---|
| Kafka | The company-wide bus, treated as the event store where all events live |
| EventBridge Pipes | A point-to-point AWS service acting as a middleman between Kafka and EventBridge |
| Amazon EventBridge | The service's local bus, responsible for fanning messages out to subscribers |
EventBridge Pipes is the leverage point. Because it sits inline as a point-to-point connector, it intercepts every message on the way through, and that interception is where validation and transformation now happen — once, in one place, rather than six times inconsistently. Supplementary context for readers new to these services: EventBridge is a serverless event bus that routes events to targets based on content-matching rules, and Pipes is its point-to-point integration primitive with an optional enrichment step.
The property Frasca cares about is interface reduction. Each service talks only to its local EventBridge bus. Whether the traffic is internal to a microservice, between microservices, or headed to the company bus, there is exactly one interface and routing is expressed as rules. "It's like Pub/Sub, but you don't care if the subscriber is SQS, SNS, whatever" — the transport is hidden behind the abstraction. Because everything now passes through that hub before fan-out, the single-source-of-truth problem is solved as a side effect: there is one validated, transformed version of each event and everyone downstream sees it.
flowchart LR
Kafka["Kafka
company bus / event store"] --> Pipe["EventBridge Pipe
validate + transform"]
Pipe -->|"enrichment: store payload"| S3[("S3
event payload")]
Pipe -->|"event with S3 key"| EB["EventBridge
local bus"]
EB -->|"rule"| SvcA["Service A"]
EB -->|"rule"| SvcB["Service B"]
EB -->|"rule"| Queue["SQS / SNS target"]
SvcA -->|"fetch payload"| S3
SvcB -->|"fetch payload"| S3Sparse Versus Full-State Events, and the Claim Check
Any event-driven design has to choose what an event carries, and Frasca presents it as a genuine trade-off rather than a solved question.
A sparse event carries only basic information — typically identifiers — so the subscriber must fetch the rest. That obligation is the cost: you now have to build and operate an API capable of absorbing a large volume of fetches triggered by fan-out. A full-state event carries everything, which makes the subscriber's life easy, but couples publisher and subscriber more tightly: change a property and you risk breaking consumers. It also moves the problem to the network, because you may be shipping megabytes per event instead of kilobytes.
For Joyn the choice was forced by a hard limit. Kafka can carry messages of 30 to 40 megabytes, and in media streaming Frasca notes that such payloads are normal. EventBridge accepts at most 256 KB. That is, as he puts it, "a completely different world." Full-state events simply would not fit.
The resolution is the claim check pattern. Using the EventBridge Pipes enrichment feature, the pipe validates and transforms the message and then stores the event payload in S3. What travels onward through EventBridge is the S3 key — a small reference — and every consumer fetches the payload from S3 itself. The result Frasca highlights is that they got "an API that scales out of the box without building our own API and maintain it." S3 absorbs the fan-out read load that a sparse-event design would have forced them to build a service for.
Together, the Hub and Spoke and claim check patterns solved the number one problem, data consistency. Frasca contrasts this with the brute-force alternative: for scalability "you put 500 tasks to handle three users, and this is how you survive" — scaling vertically and horizontally around a design problem rather than fixing it.
The Alternative He Rejected: Database Replication
To his credit Frasca presents the road not taken. Instead of events, you can replicate data — his example is PostgreSQL pglogical logical replication. Kafka feeds a normalized database, and downstream services that need only part of the data replicate the two tables they care about out of the twenty that exist. He is explicit that both approaches are valid and the choice depends on company requirements.
| Dimension | Event-driven | Data replication |
|---|---|---|
| Coupling | Decoupled; subscribers rebuild data as they wish | Teams coupled; the source database becomes the bottleneck |
| Storage freedom | Aurora, DynamoDB, a text file, Excel — consumer's choice | Everyone must run the same engine; subscriber DB must be same size or bigger |
| Schema change | Consumers adapt independently | A source schema change breaks subscribers |
| Release process | Independent deploys | Coordinated deploys: "you deploy first, I deploy after" |
| Operational complexity | Managed services | Subnets, DB subnet groups, CIDR ranges, separate networks per database |
Operational complexity is what he objects to most. Every replica database has to live in its own network, with all the VPC plumbing that implies. His verdict is generational rather than technical: "Why? It's there. I was doing this 10 years ago."
Composing Availability From Service SLAs
The second half of the talk is scalability and resilience, and it opens with a diagnosis worth keeping: "the real problem is not Lambda or cluster. The problem was the autoscaling rules that we had." Cache was absent, and the best practices that produce scaling behaviour were simply missing. Choosing a shinier compute service does not fix that.
The stack they moved to is a fairly standard managed-services layering, and Frasca's commentary on each choice is the useful part.
- Route 53 for DNS. If DNS is your only entry point you are exposed to public internet DNS issues, so he recommends always putting CloudFront or Global Accelerator in front. Both terminate the request at an AWS edge location and carry it to your region over AWS's private network; the difference is that CloudFront is a CDN and can cache at the edge.
- Front door: an Application Load Balancer or API Gateway. He starts with API Gateway because it operates at a higher networking level, giving you CORS handling and compression out of the box.
- Compute: Lambda or Fargate, both serverless. "Lambda is magic, it scales from zero to 1000 in milliseconds" and needs little more than correct memory sizing for your runtime. Fargate gives more control "but you also have more ways to fail."
- Data: Aurora, DynamoDB, or RDS, plus a cache layer.
The insight that surprised him was what happens when you multiply the SLAs. API Gateway and Lambda — the most fully serverless combination — were not the most available; the best pairing was Application Load Balancer with Lambda. He qualifies this immediately and twice: the numbers are theoretical, and they only describe foundations. "If you are not applying your best practice like circuit breaker, retry, timeouts, you're still bringing down a service like Lambda that is 99.99% available. The architecture gives you the foundation, but the code allows you to reach these numbers."
Composing his chosen stack produced 99.78% availability. Supplementary context, since the talk does not spell out the arithmetic: composing services in series means multiplying their availabilities, so each additional dependency can only reduce the total, and 99.78% corresponds to roughly nineteen hours of downtime per year. He uses the single-region versus two-region comparison of worst-case downtime to make the point concrete — the difference between the two numbers is "a happy customer and an angry customer that are on social."
On databases, only DynamoDB and Aurora DSQL are fully serverless in AWS today, usable as fire-and-forget APIs with no VPC or subnet concerns. Aurora and RDS bring networking back into scope. His framing of the choice is the sharpest line in this section: you are "trading operational complexity for cost, and at the same time you're trading reliability for simplicity." RDS with a single node plus replicas is a legitimate production setup — "nobody tells you not to. It works until it doesn't." The failure modes that never appear in a proof-of-concept are replication lag, failover behaviour, and split-brain: the write node is presumed dead, a read replica is promoted to writer, the original write node returns, and now two writers have accepted divergent data that cannot be reconciled. His reduction of the whole database decision is a single question for management: how much are you willing to be down when the problem occurs?
Their final service template is those managed services plus one deliberate exception — Momento Cache instead of self-managed Redis or Valkey, moving sizing and operations to a third party. DynamoDB or Aurora global tables replicate data to another region for disaster recovery. The design goal Frasca states for the template is "never go down and recover gracefully." And then the caveat that sets up the rest of the talk: zoom into a single region and you still have a single point of failure. "You cannot escape this."
Cell-Based Architecture
Before attempting multi-region, the team ran a series of iterations to make the application more available within a region. The first is cell-based architecture: partitioning traffic so that one failing unit cannot take down everything.
The partitioning keys were natural business dimensions. Three countries — Germany, Austria, Switzerland — times two user types, paid and free, gives six cells. One Lambda becomes six Lambdas. Split further by the five client platforms and you have thirty. The concurrency arithmetic is the immediately visible benefit: if a single Lambda function scales from zero to 1,000 concurrent executions, thirty functions give you 30,000 — Frasca phrases this as "30,000 requests in a millisecond," though the limit is more precisely a concurrency ceiling than a per-millisecond request rate. He notes the practical prerequisite — you must raise your quotas with AWS — and the practical non-cost: "you write the code once and you deploy through the CI. It doesn't really matter if you have one Lambda or 30." The same partitioning applies to Fargate: many smaller services scaling independently on their own traffic, memory, and CPU patterns instead of one monolithic service.
Frasca is clear that concurrency was not the main goal. "The key here for us was to reduce the blast radius in case of a problem." A second benefit followed: deployment granularity. They can ship to Germany, iOS, free users only, watch the metrics, and roll out from there.
Cells stop at the database, and for an honest reason — cost. With fully serverless databases such as DynamoDB and Aurora DSQL, "if you have 10 of them or one, it's the same," so you can cell them freely. With RDS, Aurora, or OpenSearch, "this is where AWS makes money," and at Joyn's scale splitting them did not make sense. They run one database and one OpenSearch per region serving all cells.
flowchart TD
User["Client request"] --> CF["CloudFront / Global Accelerator
edge entry + AWS backbone"]
CF --> ALB["Application Load Balancer
weighted routing"]
ALB -->|"weight"| L["Lambda cells
country x user type x platform"]
ALB -->|"weight"| F["Fargate cells"]
L --> Mem["In-process memory cache
hot keys"]
F --> Mem
Mem -->|"miss"| Momento["Momento cache"]
Momento -->|"miss (<10% of reads)"| DB[("DynamoDB / Aurora
global tables")]
Alarms["CPU / memory alarms
emit events"] -.->|"shift traffic weights"| ALB
R53["Route 53 health checks"] -.->|"regional failover"| CFCaching as the Enabler
The single-node database with no cache was the original sin, and the fix is the piece of the talk with the clearest numbers. Frasca's observation is that a streaming catalogue is close to an ideal caching workload: "Everybody loads exactly the same things. Give me the profile of Brad Pitt. It's always the same." There are small per-platform variations, but the content is overwhelmingly shared and static. "There is no point to use the database as an expensive cache."
They apply three layers, checked in order.
- CloudFront at the edge, absorbing repetitive requests before they reach a region at all.
- In-process memory inside the Lambda or Fargate instance, holding hot keys with per-service settings.
- Momento, a managed cache sitting in front of the database, which also provides real-time notification features.
Only on a miss at all three layers does a request reach the database. The reported result is that database traffic falls to under 10%, even 5% during prime time. He also notes that caching in the CDN for only a few seconds produces "huge benefits for services that are receiving 100 million requests simultaneously," and does not pretend invalidation is free — it is a trade-off you have to manage.
The consequence is what makes this section structural rather than incidental. A small database cluster is enough, instead of a giant memory-heavy cluster sized to raw request volume. That unlocks two things: request-driven serverless scaling, and a real active-active option. Frasca prefers DynamoDB's multi-region writes over Aurora global tables, where writes go to one region only. And once the cluster is small, "it becomes cheaper or the same as having the global tables" — caching is what makes the more resilient topology affordable.
Automating the Data Plane
The third investment was automation, made necessary by the proliferation of functions and services that cells produced. Two mechanisms are described. First, monitoring compute through the Application Load Balancer and performing automatic failover: if something goes wrong in a region, Route 53 switches traffic to a different country — the same country partitioning the cells use. Second, alarms on resources such as CPU and memory that emit events, and those events shift traffic between Fargate and Lambda. Traffic is never served by one compute service alone; rules decide, per moment and per traffic pattern, which is the better target.
The motivation he gives is as much operational as technical: "The time that there is an incident, I see the email, I try to log in with everything. I try to figure out what's happening, it's gone." An automated data plane means the recovery completes before a human can usefully intervene — and, as the cost section argues, before a bridge call assembles.
Multi-Region, and Why It Is Really a Culture Problem
Frasca does not claim everyone needs multi-region. Cells, caching, and automation "make our service more scalable and available. We reduce the blast radius, but we are not really resilient." Resilience, in his usage, requires a second region.
It does not require it everywhere. Only services whose failure brings the whole application down warrant active-active. "If bookmarks go down, nobody cares. We can go there and spin it up." Every service is prepared for multi-region deployment, but the strategy is chosen per service severity from the standard ladder: backup and restore, pilot light, warm standby, active-active. The end state is therefore a deliberately mixed estate — some services active-active, others active-passive, in what Frasca calls "different shades, depends on the severity of the services," rather than one uniform topology. Joyn ran three regions at the time of the talk, with plans to extend across Europe following an acquisition.
The obstacle he identifies is not technical. "The real problem for multi-region, I think, is the mentality." Developers ask why they should complicate infrastructure they have run the same way for a decade; if there is an SRE team it becomes their job, and the SRE team is busy. The result is "a culture of, if the problem happens, let's brace, let's take the heat for the manager and wait that it passes."
His counterargument is that the risk being ignored is not the dramatic one. People imagine an entire region going dark — he half-remembers a 2021 incident, "I think, back in 2021, was 8 hours down?" — and conclude it is too rare to plan for. The failures that actually bite are constant and small, and he lists what his team saw in recent months: DNS issues where CloudFront or the load balancer could not reach the origin; Lambda recycling everything at once, producing a wave of cold starts with a domino effect; Fargate tasks vanishing, ten tasks dropping to zero. All of it auto-recovers. The cost is elsewhere: "there are multiple people in a call. We need to investigate. We need to bring the VP in, the CTO. How much does it cost, all of this? Just to turn out." Incident response labour is a real, recurring expense that never appears on the infrastructure bill, and it is the item most often missing when a multi-region proposal is priced. That reframes the question from whether multi-region is correct to, in his words, how "to make multi-region more affordable."
Making Multi-Region Affordable
Multi-region is unambiguously more expensive: replication and cross-region data transfer both cost money, and AWS charges for networking even within a region. Affordability came from a sequence of specific optimizations.
API Gateway to Application Load Balancer. API Gateway is, in his words, famously more expensive than a load balancer at scale. Switching produced a 90% saving. The price was re-implementing in code what API Gateway had provided: CORS headers and compression, which he characterizes as "just a bunch of headers and networking compressions. Not a big deal." Supplementary caution: that trade is cheap only if you are comfortable owning those concerns; API Gateway also brings authorizers, throttling, and usage plans that a load balancer does not.
Shifting traffic between Fargate and Lambda. This produced a 60% cost decrease, and it inverts common advice. "If you are around with AWS Heroes and everything, or from AWS, they always tell you, Fargate is cheaper than Lambda. It is, if you see the price, but it really depends on the scale." Their own calculation put the crossover at roughly 30 to 50 million requests per day; below that, Fargate was actually the more expensive option. So they compute the current traffic level and user count, estimate how many requests a task can handle, and move the load balancer weights accordingly.
The operating policy he describes in the Q&A is Lambda-first. The load balancer starts at 100% Lambda weight, and as traffic rises he shifts toward Fargate, reaching at most 90% Fargate and 10% Lambda at high traffic. Lambda is permanently retained as the overflow path, because scaling Fargate up takes five or six minutes; when a spike arrives they may drop Fargate to 70% and let Lambda absorb the difference — accepting some cold starts — while Fargate spins up new tasks. Overnight, when nobody is watching TV, Fargate scales to zero and Lambda serves everything.
The sizing behind those decisions came from load testing: a Fargate task with 4 GB of memory and 2 vCPUs handles roughly 3,000 to 4,000 concurrent requests before CPU and memory start climbing. They deliberately do not run toward 60–70% utilization, "because it will be too late in case of traffic" — the headroom exists precisely so the overflow mechanism has time to engage.
Asked directly whether they pre-warm for predictable peaks — prime time for German live TV is 7 p.m. to 11 p.m. — Frasca said no, and explained the preference. He dislikes the common approach of scaling everything up in advance; the Lambda-first weighting makes the system reactive instead. "I do not care if I have one user or 1000 users or 100,000, 200,000. It's all taken care of automatically."
The final lever is the automated data plane described earlier, which Frasca counts as a cost measure and not only a reliability one, because it removes the recurring incident-response labour. His summary of affordability is measured rather than triumphant: "you are not eliminating the cost, but you are making it reasonable for the protection that you gain."
Testing Failure
Asked how regional failure is tested, Frasca described using AWS Fault Injection Service — "I call it Daniele monkey's chaos engineering. Practically, I go there and stop things and see what's happened." Beyond the managed service, the team runs major simulations whenever a big change ships, and sometimes inserts a deliberate delay or thrown exception into the code purely to force a failure path.
The mindset matters more than the tooling. "When we are building it, I build for failure. I'm not thinking about the green part. I'm thinking how this can fail." He also concedes the limits: over eighteen months there were many things they were not covering, and the discipline was that when something did happen, they automated the response afterwards.
On keeping regional databases in sync — the obvious risk when you fail traffic over — his answer is that they do not converge after the fact, they are written in parallel. Two pipelines consume from Kafka, one per region, each acting as an independent writer of the same data almost in real time. There is no cross-region reconciliation step and none is wanted; divergence is bounded instead by the dead-letter queue, where a failed message lands and is retried automatically. Where a service genuinely needs active-active they write in every region; where it does not, they use global tables and write once while reading from both.
What It Added Up To
Over roughly eighteen months the two-person team rewrote all of these services. Frasca's reported outcome is that the team — he has since moved on — "never had any issues that came from availability or reliability." The bugs that remained were, in his account, human: "we didn't test it correctly, deployed, everything is working. I figured out later that it was a bug." Cost went down as well. These are the speaker's reported results for one team and one product, not a generalizable benchmark, and the availability claim covers the period after the rewrite rather than a formally measured SLO.
He closes by addressing the criticism the design attracts inside his own company: colleagues count components — "You're using EventBridge. You're using S3. You're using this. Three components, I can do everything with a cluster." His reply is that serverless does not add complexity so much as expose it. "Serverless just gives us the visibility that you're actually building inside your giant box. They see complexity, I see delegation to AWS." The stated payoff is letting the team focus on what counts "instead of introducing bugs through code."
Trade-offs And Limitations
- The claim check pattern moves the problem, it does not delete it. Consumers now depend on S3 for every payload, and the event is no longer self-contained. Added context not covered in the talk: this introduces object lifecycle and retention questions, and an ordering hazard if a consumer reads a key whose object has been expired.
- Sparse versus full-state has no universal answer. Joyn's choice was decided by EventBridge's 256 KB limit against Kafka's tens of megabytes; a team with small events faces a genuinely open decision.
- Database replication is not dismissed. Frasca says both approaches are valid and the choice depends on company requirements. His objection is operational complexity and team coupling, not correctness.
- The availability numbers are theoretical. He says so twice. Published SLAs are a foundation; circuit breakers, retries, and timeouts in application code are what let you approach them, and their absence can bring down a 99.99% service.
- Cells stop at the stateful tier for cost reasons. With RDS, Aurora, or OpenSearch, one instance per cell is prohibitively expensive at their scale, so the shared regional database remains a shared failure domain.
- Caching aggressively means owning invalidation. He names it as a trade-off without claiming to have solved it, and their mitigation for some services is simply a very short CDN TTL.
- Aurora global tables write to a single region. That is why he prefers DynamoDB for genuinely active-active services.
- Cost figures are Joyn's, not laws. The 90% API Gateway saving, the 60% compute saving, and especially the 30–50 million requests per day Fargate/Lambda crossover come from this team's traffic shape and calculations. He explicitly frames the crossover as "from our calculations."
- Trading API Gateway for a load balancer means re-implementing features. They accepted CORS and compression in code; other API Gateway capabilities do not transfer.
- Multi-region deployment tooling is still painful. His closing wish is for cloud providers to make it easier: "my CI pipelines are huge... I wish to have, for example, a list of regions that I apply and that's it."
- The component-count objection is real and unresolved. Colleagues inside his own company still read the design as needlessly complicated, and his answer is a perspective rather than a proof — see the previous section.
Practical Takeaways
- Audit architectural debt, not just code debt. The question is whether the architecture grew with the business, not whether any individual component is well written.
- Give each service one integration interface. Route everything through a local bus and express fan-out as rules, so subscribers never care whether the target is a queue, a topic, or a function.
- Do validation and transformation once, in the pipe. Six consumers of one topic each doing their own validation is how a single source of truth is lost.
- Never publish internal state to a shared company bus, even when doing it correctly requires extra infrastructure.
- Check your message size limits before choosing full-state events. If the payload does not fit, use a claim check: store the body in object storage and send the key.
- Multiply your SLAs before promising availability, then remember the number is only reachable with timeouts, retries, and circuit breakers in your code.
- Put a CDN or accelerator in front of DNS so requests enter the provider network at the edge rather than traversing the public internet to your region.
- Partition by business dimension to shrink blast radius, and take the concurrency-limit multiplication and the fine-grained rollouts as bonuses.
- Cell your serverless data stores freely and your provisioned ones carefully — per-cell RDS or OpenSearch is where the bill grows.
- Layer caches until the database is the exception, not the path. Edge, then in-process hot keys, then a managed cache; a small cluster behind a good cache is what makes active-active affordable.
- Reserve multi-region for services whose failure takes the product down, and match the rest to a cheaper strategy on the recovery ladder.
- Price the incident, not just the outage. Recurring small failures cost engineer, VP, and CTO time even when the platform auto-recovers.
- Re-derive the Lambda versus containers cost comparison for your own traffic instead of accepting the general advice, and consider serving both with weighted routing.
- Prefer reactive shifting over pre-warming where your compute can absorb a spike, and keep the fast-scaling option permanently in the mix as overflow.
- Present the trade-off to management as a decision they own, with numbers attached, rather than absorbing the risk silently.
Key Terms
- Hub and Spoke (bus mesh) — An integration pattern where every service talks to a single local event bus, which fans messages out by rule, hiding the transport and the identity of subscribers.
- Amazon EventBridge — AWS's serverless event bus; routes events to targets based on content-matching rules. Maximum event size 256 KB.
- EventBridge Pipes — A point-to-point AWS integration service connecting a source to a target, with optional filtering, enrichment, and transformation in between.
- Claim check pattern — Storing a large message body in external storage and sending only a reference through the messaging system, so consumers fetch the body themselves.
- Sparse event — An event carrying only identifiers, requiring subscribers to fetch details. Reduces payload size but forces you to build a fetch API.
- Full-state event — An event carrying the complete entity. Convenient for subscribers, but couples publisher and subscriber and moves cost to the network.
- pglogical — A logical replication extension for PostgreSQL, used here as the representative of the database-replication alternative to event-driven integration.
- Cell-based architecture — Partitioning a workload into independent units along a business dimension so that a failure or limit affects one cell rather than the whole system.
- Blast radius — The scope of what breaks when one component fails; the metric cell-based architecture is designed to reduce.
- Split-brain — A failover fault where a presumed-dead write node returns after a replica has been promoted, leaving two writers with divergent, irreconcilable data.
- Global tables — A DynamoDB and Aurora feature replicating data across regions. Aurora global tables accept writes in one region only; DynamoDB supports multi-region writes.
- Aurora DSQL — Along with DynamoDB, one of the two fully serverless AWS databases in Frasca's account, usable without VPC or subnet configuration.
- Global Accelerator — An AWS service that routes traffic into the AWS private network at an edge location. Unlike CloudFront it is not a CDN and does not cache.
- Momento — The third-party managed cache Joyn adopted instead of operating Redis or Valkey themselves.
- AWS Fault Injection Service — AWS's managed chaos engineering service, used here to stop components deliberately and observe recovery.
- Active-active / warm standby / pilot light / backup and restore — The standard ladder of multi-region strategies, in decreasing order of cost and recovery speed.
The most transferable idea here is not any single AWS service. It is that Frasca treated availability as an economic argument and then did the engineering work that made his side of the argument cheap. If you want multi-region and cannot get it approved, the productive question is probably not how to argue harder but which cost curve you can bend first.
Reference: Daniele Frasca, Evolution of a Backend for a Streaming Application, InfoQ Dev Summit Munich, recorded by InfoQ on May 11, 2026.