Goodreads书评备份
这篇书评可能有关键情节透露
I've always felt as a programmer, I only have limited knowledge in software design. A friend of mine recommended this book to me as he read this book for his interview preparation.
Well, this is not a very deep book on the topic of scalability. As the author mentions, scalability itself is too broad a topic to get covered in one book. Instead, this book serves as a very good introduction to many aspects of the technology stack of a Web-based startup - from the front-end layer, to Web services, data layer, caching, message queues and searching component. For me, it is a very nice introduction and I've certainly learned a lot from this book. But if you've worked with many of these components this book might be too trivial for you.
I'm posting my notes here as a backup:
Chapter 1: Core Concepts
• CDN: A hosted service that takes care of global distribution of static files like images, JavaScript, CSS, and videos. (Acts as an HTTP proxy.) (P14)
• Edge cache (P20)
• High-level overview of the data center infrastructure (P23)
a. The Front Line: geoDNS, load balancer, front cache
b. Web Application Layer
§ Render user interface, should be completely stateless
§ Lightweight web framework with a minimal amount of business logic
c. Web Services Layer
§ Usually use REST/SOAP between front-end and web services
§ Also should be stateless
d. Additional components: object caches, message queues
e. Data Persistence Layer: data store, search
• Overview of the Application Architecture (P27)
a. Front End
§ Single responsibility: becoming the user interface
§ The layer translating between the public interface and internal service calls
§ Should not be aware of any databases or 3rd party services
b. Web Services
§ Service-oriented architecture
§ Layered architecture
§ Hexagonal architecture
§ Event-driven architecture (EDA)
Chapter 2: Principles of Good Software Design
1. Simplicity (P38-43)
a. Hide Complexity and Build Abstractions: Strive for local simplicity
b. Avoid Overengineering
c. Try Test-Driven Development
d. Learn from Models of Simplicity in Software Design
§ Example: Grails, Hadoop, Google Maps API
2. Loose Coupling (P43-48)
a. Promoting Loose Couping
§ Hiding details (private, protected) is a great way to reduce coupling and promote simplicity.
b. Avoiding Unnecessary Coupling
§ Example 1: Exposing all private properties using public getters and setters.
§ Example 2: Clients of a module / class need to invoke methods in a particular order for the work to be done correctly.
§ Example 3: Allowing circular dependencies between layers of your application, modules, or classes.
c. Models of Loose Coupling (Unix pipes, SLF4J)
3. Don't Repeat Yourself (DRY) (P48-51)
a. Following an inefficient process
b. Lack of automation
c. Reinventing the wheel
d. Copy / paste programming (Important!)
e. "Hack it quickly" solutions
4. Coding to Contrast (P51-53)
○ When designing a class first consider what functionality your clients really need and then define the minimal interface as the contract. Finally, implement the code fulfilling the contract.
5. Draw Diagrams (P54-61)
○ A must-have skill for every architect and technical leader (switch from code first to DESIGN FIRST!)
a. Use Case Diagrams: actors, actions and high-level structure of how different operations relate to each other.
b. Class Diagrams: Visualize a module's structure with its classes, interfaces, and their interdependencies.
c. Module Diagrams
6. Single Responsibility (P61-63)
○ Your classes should have one single responsibility and no more.
○ Guidelines
i. Keep class length below 2-4 screens of code.
ii. Ensure a class depends on no more than five other interfaces / classes.
iii. Ensure that a class has a specific goal / purpose.
iv. Summarize the responsibility of the class in a single sentence and put it in a comment on top of the class name. IF YOU FIND IT HARD, it usually means that your class does more than one thing!
7. Open-Closed Principle (P63-65)
○ Open for extension
○ Closed for modification
8. Dependency Injection (P65-68)
○ A bit hard to understand
○ Can be summarized as not using the "new" keyword in your classes and demanding instances of your dependencies to be provided to your class by its clients.
9. Inversion of Control (IOC, P68-71)
○ Create plugins inside your framework
○ Fish tank analogy (P71)
10. Designing for Scale (P71-77)
a. Adding clones: good for stateless services, difficult to scale stateful servers
b. Functional Partitioning: Limited functional partitions that you can come up with, you can't keep rewriting your application and keep dividing it into smaller and smaller Web services.
c. Data Partitioning
11. Design for Self-Healing (P77-80)
○ Mainly about removing single points of failure and graceful failover.
Chapter 3: Building the Front-End Layer
• Every user interaction, every connection, and every response has to go through the front-end layer in one form or another. This in turn causes the front-end layer to have the highest throughput and concurrency rate demands, making its scalability critical. (P84)
• Managing State (P85-101)
○ In the context of stateful vs. stateless, state is any information that would have to be synchronized between servers to make them identical. (P86)
○ Example: Order drinks in a pub: cash (stateless), tab (stateful) (P86-87)
1. Managing HTTP Sessions
• The key thing to observe here is that any data you put into the session should be stored outside of the web server itself to be available from any web server.
a. Store session state in cookies (P89)
Pros: Do not have to store the session state anywhere in your data center.
Cons: Session storage becomes expensive.
b. Store session data in a dedicated data store.
Requires very low latency on get-by-key and put-by-key operations. (P91)
c. Use a load balancer that supports sticky sessions. (P92)
Breaks the fundamental principle of statelessness.
2. Managing Files
○ Stick with a third-party provider like S3 first.
○ Opt for data store as a cheap alternative.
3. Managing Other Types of State
○ Components of the Scalable Front End (P101-116)
a. DNS
b. Load Balancers
i. Use load balancers as the entry point to your data center, allowing you to scale more easily and make changes to your infrastructure without negatively affecting your customers.
ii. Benefits:
§ Hidden server maintenance
§ Seamlessly increase capacity
§ Efficient failure management
§ Automated scaling
§ Effective resource management / SSL offloading
○ Options
i. Load Balancer as a Hosted Service, e.g. ELB
ii. Self-Managed Software-Based Load Balancer, e.g. Nginx / HAProxy
iii. Hardware Load Balancer
c. Web Servers
d. Caching
i. Integrate a CDN
ii. Deploy your own reverse proxy servers
iii. Store data directly in the browser
iv. Cache fragments of your responses in an object cache
e. Auto-Scaling
Chapter 4: Web Services
• Designing Web Services (P124-131)
a. Web Services as an Alternative Presentation Layer
b. API-First Approach
c. Pragmatic Approach
• Types of Web Services (P131-138)
a. Function-Centric Services (SOAP)
b. Resource-Centric Services (REST)
• Scaling REST Web Services (P138-153)
1. Keeping Service Machines Stateless
§ No state held between HTTP requests other than auto-expiring caches. (P141)
2. Caching Service Responses
§ The HTTP protocol requires all GET method calls to be read-only. A GET request to any resource should not cause any state changes or data updates. (P146)
§ Another important aspect to consider when designing a REST API is which resources require authentication and which do not. (P147)
3. Functional Partitioning
§ The main challenge that may be an outcome of performing functional partitioning too early or of creating too man partitions is when new use cases arise that require a combination of data and features present in multiple web services. (P153)
Chapter 5: Data Layer
• Scaling with MySQL (P156-189)
1. Replication
○ Allows you to synchronize the state of master and slave
○ Can connect to a slave to read data from it
○ Can modify data only through the master server
○ One of the main reasons why people use replication in MySQL is to increase availability by reducing the time needed to replace the broken database.
○ Replication is only applicable to scaling reads.
○ Replication is not the way to scale writes
§ All of your writes will need to go through a single machine (or through each machine in case of multimaster deployments)
○ Replication is not a way to scale the overall dataset size
§ All of the data must be present on each of the machines
○ Slaves can return stale data
2. Data Partitioning (Sharding)
○ One of the most significant limitations that come with application-level sharding is that you cannot execute queries spanning multiple shards.
○ ACID (Atomicity, Consistency, Isolation, Durability)
○ Another side effect of sharding is that you lose the ACID properties of your database as a whole.
• Scaling with NoSQL (P189-204)
○ CAP theorem: it is impossible to build a distributed system that would simultaneously guarantee consistency, availability and partition tolerance.
§ Consistency: all of the nodes see the same data at the same time
§ Availability: any available nodes can serve client requests even when other nodes fail
§ Partition tolerance: the system can operate even in the face of network failures where communication between nodes is impossible
○ Eventual consistency: different nodes may have different versions of the data, but where state changes eventually propagate to all of the servers
○ Amazon Dynamo: sacrifice consistency for availability
○ MongoDB: Ditto
○ Cassandra: Eventually consistent
Chapter 6: Caching
• Cache Hit Ratio
○ Three main factors: data set size, space, longevity
• Caching Based on HTTP (P210-227)
○ All of the caching technologies in the HTTP layer work as read-through caches (Fig 6-1, P210)
○ HTTP Caching Headers: Cache-Control, Expires, Vary
○ Types of HTTP Cache Technologies (P217-223)
a. Browser Cache
b. Caching Proxies
c. Reverse Proxy
d. Content Delivery Networks
○ Scaling HTTP Caches (P223-227)
• Caching Application Objects (P227-239)
○ Cache-aside rather than read-through
○ Common Types of Object Caches
a. Client-Side Caches
b. Caches co-located with code
c. Distributed Object Caches (Redis / Memcached)
○ Scaling Object Caches
§ Consistent hashing (P236-237)
• Caching Rules of Thumb (P239-244)
○ Cache High Up the Call Stack
○ Reuse Cache Among Users
○ Where to Start Caching? (AggTime Spent)
○ Cache Invalidation Is Difficult
Chapter 7: Asynchronous Processing
• Message Queues (P256-270)
○ Message Producers
○ Message Broker
○ Message Consumers
§ Two most common ways "cron like", "daemon like"
□ cron-like: connects periodically to the queue and checks its status (pull model)
□ daemon-like: runs in an infinite loop, permanent connection to the message broker (push model)
○ Message routing methods
a. Direct Worker Queue: Each message arriving to the queue is routed to only one customer.
b. Publish / Subscribe
□ Producers publish messages to a topic, not a queue
□ Consumers declare which topics they are interested in
c. Custom Routing Rules
○ Messaging Protocols
a. AMQP: Advanced Message Queuing Protocol
b. STOMP: Streaming Text-Oriented Messaging Protocol
c. JMS: Java Message Service
○ Messaging Infrastructure
• Benefits of Message Queues (P270-276)
1. Enabling asynchronous processing
§ Message queues only add values if your application is NOT built in an async way to begin with (e.g. message queues won't benefit you that much if you develop in Node.js)
2. Easier Scalability
3. Evening Out Traffic Spikes
4. Isolating Failures and Self-Healing
5. Decoupling
• Message Queue-Related Challenges (P276-282)
a. No Message Ordering
b. Message Requeueing
c. Race Conditions Become More Likely
d. Risk of Increased Complexity
• Message Queue-Related Anti-Patterns (P282-284)
a. Treating the MQ as a TCP Socket (Instead we should avoid return channels)
b. Treating MQ as a Database
c. Coupling Message Producers with Consumers
d. Lack of Poison Message Handling
Chapter 8: Searching for Data
Chapter 9: Other Dimensions of Scalability
• Scaling Productivity through Automation (P332-347)
a. Testing (Unit, integration, E2E)
b. Build and Deployment
§ Some best practices
1) Write unit tests for all of your code (> 85% code coverage)
2) Create E2E test cases for all critical paths
3) Use feature toggles
4) Use A/B tests
5) Monitoring tools
c. Monitoring and Alerting
§ Reducing mean time to recovery (MTTR)MTTR = time to discover + time to respond + time to investigate + time to fix
d. Log Aggregation
• Scaling Yourself (P347-357)
○ Overtime is NOT a way to scale
○ Managing Yourself
a. Influencing the Scope
1) Prioritize all the tasks
2) Follow the 80/20 rule
b. Influencing the Cost
1) Delegate tasks to other members
2) Use 3rd-party services or commercial tools
c. Influencing the Schedule
1) Release in smaller chunks
2) Experiment with mocks
• Scaling Agile Teams (P357-361)
a. Adding More People: creating cross-functional teams
b. Procedures and Innovation
c. Culture of Alignment
Well, this is not a very deep book on the topic of scalability. As the author mentions, scalability itself is too broad a topic to get covered in one book. Instead, this book serves as a very good introduction to many aspects of the technology stack of a Web-based startup - from the front-end layer, to Web services, data layer, caching, message queues and searching component. For me, it is a very nice introduction and I've certainly learned a lot from this book. But if you've worked with many of these components this book might be too trivial for you.
I'm posting my notes here as a backup:
Chapter 1: Core Concepts
• CDN: A hosted service that takes care of global distribution of static files like images, JavaScript, CSS, and videos. (Acts as an HTTP proxy.) (P14)
• Edge cache (P20)
• High-level overview of the data center infrastructure (P23)
a. The Front Line: geoDNS, load balancer, front cache
b. Web Application Layer
§ Render user interface, should be completely stateless
§ Lightweight web framework with a minimal amount of business logic
c. Web Services Layer
§ Usually use REST/SOAP between front-end and web services
§ Also should be stateless
d. Additional components: object caches, message queues
e. Data Persistence Layer: data store, search
• Overview of the Application Architecture (P27)
a. Front End
§ Single responsibility: becoming the user interface
§ The layer translating between the public interface and internal service calls
§ Should not be aware of any databases or 3rd party services
b. Web Services
§ Service-oriented architecture
§ Layered architecture
§ Hexagonal architecture
§ Event-driven architecture (EDA)
Chapter 2: Principles of Good Software Design
1. Simplicity (P38-43)
a. Hide Complexity and Build Abstractions: Strive for local simplicity
b. Avoid Overengineering
c. Try Test-Driven Development
d. Learn from Models of Simplicity in Software Design
§ Example: Grails, Hadoop, Google Maps API
2. Loose Coupling (P43-48)
a. Promoting Loose Couping
§ Hiding details (private, protected) is a great way to reduce coupling and promote simplicity.
b. Avoiding Unnecessary Coupling
§ Example 1: Exposing all private properties using public getters and setters.
§ Example 2: Clients of a module / class need to invoke methods in a particular order for the work to be done correctly.
§ Example 3: Allowing circular dependencies between layers of your application, modules, or classes.
c. Models of Loose Coupling (Unix pipes, SLF4J)
3. Don't Repeat Yourself (DRY) (P48-51)
a. Following an inefficient process
b. Lack of automation
c. Reinventing the wheel
d. Copy / paste programming (Important!)
e. "Hack it quickly" solutions
4. Coding to Contrast (P51-53)
○ When designing a class first consider what functionality your clients really need and then define the minimal interface as the contract. Finally, implement the code fulfilling the contract.
5. Draw Diagrams (P54-61)
○ A must-have skill for every architect and technical leader (switch from code first to DESIGN FIRST!)
a. Use Case Diagrams: actors, actions and high-level structure of how different operations relate to each other.
b. Class Diagrams: Visualize a module's structure with its classes, interfaces, and their interdependencies.
c. Module Diagrams
6. Single Responsibility (P61-63)
○ Your classes should have one single responsibility and no more.
○ Guidelines
i. Keep class length below 2-4 screens of code.
ii. Ensure a class depends on no more than five other interfaces / classes.
iii. Ensure that a class has a specific goal / purpose.
iv. Summarize the responsibility of the class in a single sentence and put it in a comment on top of the class name. IF YOU FIND IT HARD, it usually means that your class does more than one thing!
7. Open-Closed Principle (P63-65)
○ Open for extension
○ Closed for modification
8. Dependency Injection (P65-68)
○ A bit hard to understand
○ Can be summarized as not using the "new" keyword in your classes and demanding instances of your dependencies to be provided to your class by its clients.
9. Inversion of Control (IOC, P68-71)
○ Create plugins inside your framework
○ Fish tank analogy (P71)
10. Designing for Scale (P71-77)
a. Adding clones: good for stateless services, difficult to scale stateful servers
b. Functional Partitioning: Limited functional partitions that you can come up with, you can't keep rewriting your application and keep dividing it into smaller and smaller Web services.
c. Data Partitioning
11. Design for Self-Healing (P77-80)
○ Mainly about removing single points of failure and graceful failover.
Chapter 3: Building the Front-End Layer
• Every user interaction, every connection, and every response has to go through the front-end layer in one form or another. This in turn causes the front-end layer to have the highest throughput and concurrency rate demands, making its scalability critical. (P84)
• Managing State (P85-101)
○ In the context of stateful vs. stateless, state is any information that would have to be synchronized between servers to make them identical. (P86)
○ Example: Order drinks in a pub: cash (stateless), tab (stateful) (P86-87)
1. Managing HTTP Sessions
• The key thing to observe here is that any data you put into the session should be stored outside of the web server itself to be available from any web server.
a. Store session state in cookies (P89)
Pros: Do not have to store the session state anywhere in your data center.
Cons: Session storage becomes expensive.
b. Store session data in a dedicated data store.
Requires very low latency on get-by-key and put-by-key operations. (P91)
c. Use a load balancer that supports sticky sessions. (P92)
Breaks the fundamental principle of statelessness.
2. Managing Files
○ Stick with a third-party provider like S3 first.
○ Opt for data store as a cheap alternative.
3. Managing Other Types of State
○ Components of the Scalable Front End (P101-116)
a. DNS
b. Load Balancers
i. Use load balancers as the entry point to your data center, allowing you to scale more easily and make changes to your infrastructure without negatively affecting your customers.
ii. Benefits:
§ Hidden server maintenance
§ Seamlessly increase capacity
§ Efficient failure management
§ Automated scaling
§ Effective resource management / SSL offloading
○ Options
i. Load Balancer as a Hosted Service, e.g. ELB
ii. Self-Managed Software-Based Load Balancer, e.g. Nginx / HAProxy
iii. Hardware Load Balancer
c. Web Servers
d. Caching
i. Integrate a CDN
ii. Deploy your own reverse proxy servers
iii. Store data directly in the browser
iv. Cache fragments of your responses in an object cache
e. Auto-Scaling
Chapter 4: Web Services
• Designing Web Services (P124-131)
a. Web Services as an Alternative Presentation Layer
b. API-First Approach
c. Pragmatic Approach
• Types of Web Services (P131-138)
a. Function-Centric Services (SOAP)
b. Resource-Centric Services (REST)
• Scaling REST Web Services (P138-153)
1. Keeping Service Machines Stateless
§ No state held between HTTP requests other than auto-expiring caches. (P141)
2. Caching Service Responses
§ The HTTP protocol requires all GET method calls to be read-only. A GET request to any resource should not cause any state changes or data updates. (P146)
§ Another important aspect to consider when designing a REST API is which resources require authentication and which do not. (P147)
3. Functional Partitioning
§ The main challenge that may be an outcome of performing functional partitioning too early or of creating too man partitions is when new use cases arise that require a combination of data and features present in multiple web services. (P153)
Chapter 5: Data Layer
• Scaling with MySQL (P156-189)
1. Replication
○ Allows you to synchronize the state of master and slave
○ Can connect to a slave to read data from it
○ Can modify data only through the master server
○ One of the main reasons why people use replication in MySQL is to increase availability by reducing the time needed to replace the broken database.
○ Replication is only applicable to scaling reads.
○ Replication is not the way to scale writes
§ All of your writes will need to go through a single machine (or through each machine in case of multimaster deployments)
○ Replication is not a way to scale the overall dataset size
§ All of the data must be present on each of the machines
○ Slaves can return stale data
2. Data Partitioning (Sharding)
○ One of the most significant limitations that come with application-level sharding is that you cannot execute queries spanning multiple shards.
○ ACID (Atomicity, Consistency, Isolation, Durability)
○ Another side effect of sharding is that you lose the ACID properties of your database as a whole.
• Scaling with NoSQL (P189-204)
○ CAP theorem: it is impossible to build a distributed system that would simultaneously guarantee consistency, availability and partition tolerance.
§ Consistency: all of the nodes see the same data at the same time
§ Availability: any available nodes can serve client requests even when other nodes fail
§ Partition tolerance: the system can operate even in the face of network failures where communication between nodes is impossible
○ Eventual consistency: different nodes may have different versions of the data, but where state changes eventually propagate to all of the servers
○ Amazon Dynamo: sacrifice consistency for availability
○ MongoDB: Ditto
○ Cassandra: Eventually consistent
Chapter 6: Caching
• Cache Hit Ratio
○ Three main factors: data set size, space, longevity
• Caching Based on HTTP (P210-227)
○ All of the caching technologies in the HTTP layer work as read-through caches (Fig 6-1, P210)
○ HTTP Caching Headers: Cache-Control, Expires, Vary
○ Types of HTTP Cache Technologies (P217-223)
a. Browser Cache
b. Caching Proxies
c. Reverse Proxy
d. Content Delivery Networks
○ Scaling HTTP Caches (P223-227)
• Caching Application Objects (P227-239)
○ Cache-aside rather than read-through
○ Common Types of Object Caches
a. Client-Side Caches
b. Caches co-located with code
c. Distributed Object Caches (Redis / Memcached)
○ Scaling Object Caches
§ Consistent hashing (P236-237)
• Caching Rules of Thumb (P239-244)
○ Cache High Up the Call Stack
○ Reuse Cache Among Users
○ Where to Start Caching? (AggTime Spent)
○ Cache Invalidation Is Difficult
Chapter 7: Asynchronous Processing
• Message Queues (P256-270)
○ Message Producers
○ Message Broker
○ Message Consumers
§ Two most common ways "cron like", "daemon like"
□ cron-like: connects periodically to the queue and checks its status (pull model)
□ daemon-like: runs in an infinite loop, permanent connection to the message broker (push model)
○ Message routing methods
a. Direct Worker Queue: Each message arriving to the queue is routed to only one customer.
b. Publish / Subscribe
□ Producers publish messages to a topic, not a queue
□ Consumers declare which topics they are interested in
c. Custom Routing Rules
○ Messaging Protocols
a. AMQP: Advanced Message Queuing Protocol
b. STOMP: Streaming Text-Oriented Messaging Protocol
c. JMS: Java Message Service
○ Messaging Infrastructure
• Benefits of Message Queues (P270-276)
1. Enabling asynchronous processing
§ Message queues only add values if your application is NOT built in an async way to begin with (e.g. message queues won't benefit you that much if you develop in Node.js)
2. Easier Scalability
3. Evening Out Traffic Spikes
4. Isolating Failures and Self-Healing
5. Decoupling
• Message Queue-Related Challenges (P276-282)
a. No Message Ordering
b. Message Requeueing
c. Race Conditions Become More Likely
d. Risk of Increased Complexity
• Message Queue-Related Anti-Patterns (P282-284)
a. Treating the MQ as a TCP Socket (Instead we should avoid return channels)
b. Treating MQ as a Database
c. Coupling Message Producers with Consumers
d. Lack of Poison Message Handling
Chapter 8: Searching for Data
Chapter 9: Other Dimensions of Scalability
• Scaling Productivity through Automation (P332-347)
a. Testing (Unit, integration, E2E)
b. Build and Deployment
§ Some best practices
1) Write unit tests for all of your code (> 85% code coverage)
2) Create E2E test cases for all critical paths
3) Use feature toggles
4) Use A/B tests
5) Monitoring tools
c. Monitoring and Alerting
§ Reducing mean time to recovery (MTTR)MTTR = time to discover + time to respond + time to investigate + time to fix
d. Log Aggregation
• Scaling Yourself (P347-357)
○ Overtime is NOT a way to scale
○ Managing Yourself
a. Influencing the Scope
1) Prioritize all the tasks
2) Follow the 80/20 rule
b. Influencing the Cost
1) Delegate tasks to other members
2) Use 3rd-party services or commercial tools
c. Influencing the Schedule
1) Release in smaller chunks
2) Experiment with mocks
• Scaling Agile Teams (P357-361)
a. Adding More People: creating cross-functional teams
b. Procedures and Innovation
c. Culture of Alignment