Library / Case Studies
Benchmarking Streaming Computation Engines at Yahoo
(Yahoo Storm Team in alphabetical order) Sanket Chintapalli, Derek Dagit, Bobby Evans, Reza Farivar, Tom Graves, Mark Holderbaugh, Zhuo Liu, Kyle Nusbaum, Kishorkumar Patil, Boyang Jerry Peng and Paul Poulosky. DISCLAIMER: Dec 17th 2015 data-artisans has pointed out to us that we accidentally left on some debugging…
By Yahoo engineers · Yahoo · Added 2026-10-12
All content belongs to Yahoo engineers / Yahoo. We only link to it and give credit. Report a problem
Learn this case study
About 37 min left. Your work is saved as you go.
What you are about to study
Yahoo explains a real system. You should know the basics: caching, queues and replication.
Ideas you will meet
- Event Driven Architecture
- Loosely coupled services reacting to events.
- Distributed Systems
- Consensus, time, failure and the fundamentals of scale-out.
What we already know about this
Our own lessons on these ideas. Read them here before you start, so it makes sense.
Software Design Essentials · 11 minBehavioural patterns: Strategy, Observer, Command, StatePatterns for how objects cooperate: swapping algorithms, reacting to events, turning actions into objects and changing behaviour with state.Read here
The goal
Behavioural patterns distribute responsibility between objects and define how they communicate.
Strategy
Define a family of interchangeable algorithms behind an interface and pick one at runtime.
type Pricing = (subtotalCents: number) => number; const regular: Pricing = (s) => s; const member: Pricing = (s) => Math.round(s * 0.9); const blackFriday: Pricing = (s) => Math.round(s * 0.7); function checkout(subtotal: number, pricing: Pricing) { return pricing(subtotal); } checkout(10_000, member); // the strategy is passed inReplaces long
if/elseorswitchchains and supports the open/closed principle. In languages with first-class functions the "strategy" is simply a function you pass in.Observer (publish and subscribe)
Objects subscribe to a subject and are notified when it changes, without the subject knowing who listens.
class Emitter<T> { private handlers = new Set<(v: T) => void>(); on(h: (v: T) => void) { this.handlers.add(h); return () => this.handlers.delete(h); } // returns "unsubscribe" emit(v: T) { this.handlers.forEach((h) => h(v)); } } const cart = new Emitter<number>(); const stop = cart.on((count) => updateBadge(count)); cart.emit(3); stop(); // always clean upUsed for UI events, domain events and message buses. Watch for leaks (forgotten unsubscribes), ordering surprises and cascades of updates that are hard to follow.
Observer as a picture
100%Figure SDA-SDE-05-1 · One subject, many observers · © forcsguy.com
Command
Turn a request into an object containing everything needed to run it. That lets you queue, log, retry, schedule and undo it.
interface Command { run(): void; undo(): void } class InsertText implements Command { constructor(private doc: Doc, private at: number, private text: string) {} run() { this.doc.insert(this.at, this.text); } undo() { this.doc.remove(this.at, this.text.length); } } const history: Command[] = []; function perform(c: Command) { c.run(); history.push(c); } function undo() { history.pop()?.undo(); }Editors, job queues, macros and transaction logs all use it.
State
Let an object change behaviour when its internal state changes, by delegating to a state object (or a transition table).
type State = "new" | "paid" | "shipped" | "cancelled"; const next: Record<State, Partial<Record<"pay" | "ship" | "cancel", State>>> = { new: { pay: "paid", cancel: "cancelled" }, paid: { ship: "shipped", cancel: "cancelled" }, shipped: {}, cancelled: {}, }; function apply(state: State, action: "pay" | "ship" | "cancel"): State { const to = next[state][action]; if (!to) throw new Error(`Cannot ${action} an order that is ${state}`); return to; }Makes illegal transitions explicit and impossible, replacing scattered flags and nested conditions.
Template Method
Define the skeleton of an algorithm in one place and let steps vary.
abstract class Importer { run() { const raw = this.read(); const rows = this.parse(raw); this.save(rows); } // fixed order protected abstract read(): string; protected abstract parse(raw: string): Row[]; protected save(rows: Row[]) { /* default */ } }Frameworks use it widely ("override these hooks"). With functions, you can pass the varying steps in instead of subclassing.
Chain of Responsibility
Pass a request along a chain of handlers until one handles it (or each adds something). Middleware pipelines in web servers are this pattern.
type Handler = (req: Req, next: () => Promise<Res>) => Promise<Res>; // authenticate -> rateLimit -> validate -> handleIterator and others
- Iterator: walk a collection without exposing its structure. In most languages this is built in (
for...of, generators). - Mediator: one object coordinates many (a chat room, a form controller) so participants do not reference each other.
- Memento: capture and restore an object's state (undo snapshots).
- Visitor: add new operations over a structure of object types without modifying them; common in compilers.
- Interpreter: evaluate expressions of a small language.
Choosing
Problem Pattern Many alternative algorithms or rules Strategy React to changes without coupling Observer Undo, queue, log or retry actions Command Behaviour depends on lifecycle state State Same steps, different details Template Method A pipeline of optional processing steps Chain of Responsibility Remember: with first-class functions many of these become callbacks, closures and tables. Use the lightest form that keeps the code clear.
Real-world reading
Related reading
- Cape: Event Stream Processing Framework at DropboxDropbox engineers · DropboxCase Studies
- NATS ServerNATS · CNCF / NATSGitHub
- Samza: Stream Processing System for Latency Insighs at LinkedInLinkedIn engineers · LinkedInCase Studies
- Autoscaling AWS Step Functions Activities at YelpYelp engineers · YelpCase Studies
Show 6 moreShow fewer
- Distributed Messaging, Queuing, and Event StreamingArxivPapers
- Steady State: Always Put Logs on Separate DiskMicrosoft engineers · MicrosoftCase Studies
- Self-Serve Reporting Platform on Hadoop at LinkedInLinkedInPapers
- Ambry: Distributed Immutable Object Store at LinkedInLinkedIn engineers · LinkedInCase Studies
- Benchmarking Streaming Computation Engines at YahooYahoo engineers · YahooCase Studies
- NodeJS High Availability at YahooYahoo engineers · YahooCase Studies
- Iterator: walk a collection without exposing its structure. In most languages this is built in (
Go deeper on this
A path through videos, articles, other case studies and code on the same ideas as Benchmarking Streaming Computation Engines at Yahoo.
Warm upGet the vocabulary first.
Documentation
Apache Flink: Concepts overview
Stateful stream processing concepts: time, windows, state and fault tolerance.
Apache Software FoundationAdvanced
Books · Free from the author
Concurrent and Distributed Systems (Cambridge lecture notes)
Eight lectures on time, broadcast, replication, consensus and transactions, with notes, slides and video. Free from the author under CC BY-SA.
University of CambridgeIntermediate
WatchHow others solve the same problem, on video.
Videos belong to their creators and play from YouTube. More on YouTube (opens in a new tab)
ReadEngineers explain it in their own words.
Papers
Kafka - Message Broker
Apache Kafka is a scalable message broker , and Apache Samza is a stream processing framework built upon Kafka. They are widely used as infrastructure for implementing personalized online services and real-time predic...
KleppmannIntermediate
Papers
Distributed Messaging, Queuing, and Event Streaming
This paper surveys the message brokers that are in vogue today for distributed communication. Their primary goal is to facilitate the construction of decentralized topologies without single points of failure, enabling...
ArxivIntermediate
See it in another companyThe same ideas, a different system.
Case Studies · Read here
Brooklin: Distributed Service for Near Real-Time Data Streaming at LinkedIn
Brooklin—a distributed service for streaming data in near real-time and at scale—has been running in production at LinkedIn since 2016, powering thousands of data streams and over 2 trillion messages per day. Today, w...
LinkedInIntermediate
Case Studies · Read here
Delaying Asynchronous Message Processing with RabbitMQ at Indeed
By implementing a delay queue for our message processing, we improved the resilience of our internal systems and were able to deliver jobs more reliably.
IndeedIntermediate
Read the codeSee how it looks when it is real.
GitHub
Awesome Microservices
Curated tools, frameworks and reading material for building microservice systems.
mfornosIntermediate
GitHub
Engineering Blogs
A huge directory of company engineering blogs to learn from real production systems.
kilimchoiIntermediate
Keep learning
Loading community…