Introduction
Many applications today are data-intensive rather than compute-intensive. The biggest challenges are usually the amount of data, the complexity of data, and the speed at which it’s changing—not the raw CPU power. A data-intensive application is typically built from standard building blocks:- Databases: Store data for later retrieval
- Caches: Remember expensive operation results to speed up reads
- Search indexes: Allow users to search/filter data by keywords
- Stream processing: Send messages to other processes for asynchronous handling
- Batch processing: Periodically crunch large amounts of accumulated data
- Reliability: The system continues working correctly even when things go wrong
- Scalability: As the system grows, there are reasonable ways of dealing with that growth
- Maintainability: Over time, different people will work on the system, and they should be able to work on it productively
1. Reliability
Reliability means the system continues to work correctly, even when things go wrong. The things that can go wrong are called faults, and systems that anticipate faults and can cope with them are called fault-tolerant or resilient.A fault is not the same as a failure:
- Fault: One component deviating from its spec
- Failure: The whole system stops providing the required service to the user
1.1 Hardware faults
Hardware faults are common in large datacenters:- Hard disks crash
- RAM becomes faulty
- Power grid has a blackout
- Network cables are unplugged
- Disks set up in RAID configuration
- Dual power supplies
- Hot-swappable CPUs
- Backup power (batteries and diesel generators)
1.2 Software errors
Software errors are systematic and harder to anticipate: Real-world examples:- Linux leap second bug (2012): Many applications hung due to a kernel bug triggered by leap second
- Memory leak: Process gradually uses more memory until system runs out
- Cascading failure: One server’s slowdown causes others to overload
1.3 Human errors
Humans are known to be unreliable. Studies show that configuration errors by operators are a leading cause of outages. Best practices to minimize human errors:-
Design systems that minimize opportunities for error
- Well-designed abstractions, APIs, and admin interfaces
- Example: Admin UI that makes it easy to “do the right thing” and discourages “the wrong thing”
-
Decouple the places where people make mistakes from the places where they can cause failures
- Provide fully featured sandbox environments where people can explore safely
- Example: Separate staging environment identical to production
-
Test thoroughly at all levels
- Unit tests, integration tests, and manual tests
- Automated testing for corner cases
-
Allow quick and easy recovery from human errors
- Fast rollback of configuration changes
- Roll out new code gradually
- Provide tools to recompute data
-
Set up detailed and clear monitoring
- Telemetry: performance metrics and error rates
- Early warning signals
2. Scalability
Scalability is the term we use to describe a system’s ability to cope with increased load. Even if a system is working reliably today, that doesn’t mean it will necessarily work reliably in the future with 10x or 100x the load.2.1 Describing load
Load can be described with a few numbers called load parameters. The best choice depends on your system architecture: Example: Twitter’s scaling challenge (circa 2012) Twitter has two main operations:- Post tweet: User publishes a new message (4.6k requests/sec on average, 12k at peak)
- Home timeline: User views tweets from people they follow (300k requests/sec)
- Most users: fan-out on write (fast reads)
- Celebrities: fan-out on read (avoid massive writes)
2.2 Describing performance
Once you’ve described load, you can investigate what happens when load increases:- When load increases and system resources stay the same, how is performance affected?
- When load increases, how much do you need to increase resources to keep performance unchanged?
2.3 Approaches for coping with load
How do we maintain good performance when load parameters increase by an order of magnitude? Scaling strategies:-
Vertical scaling (scaling up): Moving to a more powerful machine
- Simpler to implement
- Limited by maximum machine size
- Single point of failure
-
Horizontal scaling (scaling out): Distributing load across multiple smaller machines
- Can scale indefinitely
- More complex (distributed systems challenges)
- Better fault tolerance
There is no one-size-fits-all scalable architecture. The architecture of systems that operate at large scale is usually highly specific to the application.
3. Maintainability
The majority of the cost of software is in ongoing maintenance:- Fixing bugs
- Keeping systems operational
- Investigating failures
- Adapting to new platforms
- Modifying for new use cases
- Repaying technical debt
- Adding new features
3.1 Operability: Making life easy for operations
Good operability means making routine tasks easy, allowing operations teams to focus on high-value activities. Good operability practices:3.2 Simplicity: Managing complexity
As projects grow, they often become very complex and difficult to understand. This complexity slows down everyone who needs to work on the system. Solution: Abstraction - hiding implementation details behind clean, simple-to-understand interfaces. Example: Good abstraction3.3 Evolvability: Making change easy
System requirements change constantly:- New facts are learned
- Unexpected use cases emerge
- Business priorities shift
- Users request new features
- New platforms emerge
- Legal or regulatory requirements change
- Growth in scale requires architectural changes
Summary
This chapter explored three fundamental concerns in software systems:Reliability
Key takeaways:- Anticipate and handle faults to prevent failures
- Use redundancy for hardware faults
- Minimize opportunities for human error
- Test thoroughly and monitor continuously
Scalability
Key takeaways:- Describe load with specific parameters relevant to your system
- Measure performance with percentiles, not just averages
- No universal scalability solution—design for your specific needs
- Plan for growth: vertical scaling (up) or horizontal scaling (out)
Maintainability
Key takeaways:- Operability: Make it easy to keep the system running smoothly
- Simplicity: Manage complexity with good abstractions
- Evolvability: Design for change from the start