System Design
  • Introduction
  • Glossary of System Design
    • System Design Basics
    • Key Characteristics of Distributed Systems
    • Scalability - Harvard lecture
      • Scalability for Dummies - Part 1: Clones
      • Scalability for Dummies - Part 2: Database
      • Scalability for Dummies - Part 3: Cache
      • Scalability for Dummies - Part 4: Asynchronism
    • Trade-off
      • CAP Theorem
      • Performance vs scalability
      • Latency vs throughput
      • Availability vs consistency
    • Load Balancing
      • Load balancer
    • Proxies
      • Reverse proxy
    • Cache
      • Caching
    • Asynchronism
    • Processing guarantee in Kafka
    • Database
      • Relational database management system (RDBMS)
      • Redundancy and Replication
      • Data Partitioning
      • Indexes
      • NoSQL
      • SQL vs. NoSQL
      • Consistent Hashing
    • Application layer
    • DNS
    • CDN
    • Communication
      • Long-Polling vs WebSockets vs Server-Sent Events
    • Security
    • Lambda Architecture
  • OOD design
    • Concepts
      • Object-Oriented Basics
      • OO Analysis and Design
      • What is UML?
      • Use Case Diagrams
    • Design a parking lot
  • System Design Cases
    • Overview
    • Design a system that scales to millions of users on AWS
    • Designing a URL Shortening service like TinyURL
      • Design Unique ID Generator
      • Designing Pastebin
      • Design Pastebin.com (or Bit.ly)
    • Design notification system (scott)
      • Designing notification service
    • Designing Chat System
      • Designing Slack
      • Designing Facebook Messenger
    • Design Top K System
    • Designing Instagram
    • Design a newsfeed system
      • Designing Facebook’s Newsfeed
      • Design the data structures for a social network
    • Designing Twitter
      • Design the Twitter timeline and search
      • Designing Twitter Search
    • Design Youtube - Scott
      • Design live commenting
      • Designing Youtube or Netflix
    • Designing a Web Crawler
      • Designing a distributed job scheduler
      • Designing a Web Crawler/Archive (scott)
      • Design a web crawler
    • Designing Dropbox
    • Design Google Doc
    • Design Metrics Aggregation System
      • Design Ads Logging System
    • Design Instacart
    • Design a payment system
      • Airbnb - Avoiding Double Payments in a Distributed Payments System
    • Design Distributed Message Queue
      • Cherami: Uber Engineering’s Durable and Scalable Task Queue in Go
    • Design Distributed Cache
      • Design a key-value cache to save the results of the most recent web server queries
    • Design a scalable file distribution system
    • Design Amazon's sales ranking by category feature
    • Design Mint.com
    • Design Autocomplete System
      • Designing Typeahead Suggestion
    • Designing an API Rate Limiter
      • Designing Rate Limiter
    • Design Google Map
      • Designing Yelp or Nearby Friends
      • Designing Uber backend
    • Designing Ticketmaster
      • Design 12306 - Scott
    • Design AirBnB or a Hotel Booking System
  • Paper Reading
    • MapReduce
  • Other Questions
    • What happened after you input the url in the browser?
Powered by GitBook
On this page
  • Design Amazon's sales ranking by category feature
  • Step 1: Outline use cases and constraints
  • Use cases
  • Constraints and assumptions
  • Step 2: Create a high level design
  • Step 3: Design core components
  • Use case: Service calculates the past week's most popular products by category
  • Use case: User views the past week's most popular products by category
  • Step 4: Scale the design
  • Additional talking points

Was this helpful?

  1. System Design Cases

Design Amazon's sales ranking by category feature

Design Amazon's sales ranking by category feature

Step 1: Outline use cases and constraints

Use cases

  • Service calculates the past week's most popular products by category

  • User views the past week's most popular products by category

  • Service has high availability

Out of scope

  • The general e-commerce site

    • Design components only for calculating sales rank

Constraints and assumptions

State assumptions

  • Traffic is not evenly distributed

  • Items can be in multiple categories

  • Items cannot change categories

  • There are no subcategories ie foo/bar/baz

  • Results must be updated hourly

    • More popular products might need to be updated more frequently

  • 10 million products

  • 1000 categories

  • 1 billion transactions per month

  • 100 billion read requests per month

  • 100:1 read to write ratio

Calculate usage

  • Size per transaction:

    • created_at - 5 bytes

    • product_id - 8 bytes

    • category_id - 4 bytes

    • seller_id - 8 bytes

    • buyer_id - 8 bytes

    • quantity - 4 bytes

    • total_price - 5 bytes

    • Total: ~40 bytes

  • 40 GB of new transaction content per month

    • 40 bytes per transaction * 1 billion transactions per month

    • 1.44 TB of new transaction content in 3 years

    • Assume most are new transactions instead of updates to existing ones

  • 400 transactions per second on average

  • 40,000 read requests per second on average

Handy conversion guide:

  • 2.5 million seconds per month

  • 1 request per second = 2.5 million requests per month

  • 40 requests per second = 100 million requests per month

  • 400 requests per second = 1 billion requests per month

Step 2: Create a high level design

Step 3: Design core components

Use case: Service calculates the past week's most popular products by category

We could store the raw Sales API server log files on a managed Object Store such as Amazon S3, rather than managing our own distributed file system.

We'll assume this is a sample log entry, tab delimited:

timestamp   product_id  category_id    qty     total_price   seller_id    buyer_id
t1          product1    category1      2       20.00         1            1
t2          product1    category2      2       20.00         2            2
t2          product1    category2      1       10.00         2            3
t3          product2    category1      3        7.00         3            4
t4          product3    category2      7        2.00         4            5
t5          product4    category1      1        5.00         5            6
...

The Sales Rank Service could use MapReduce, using the Sales API server log files as input and writing the results to an aggregate table sales_rank in a SQL Database. We should discuss the use cases and tradeoffs between choosing SQL or NoSQL.

We'll use a multi-step MapReduce:

  • Step 1 - Transform the data to (category, product_id), sum(quantity)

  • Step 2 - Perform a distributed sort

class SalesRanker(MRJob):

    def within_past_week(self, timestamp):
        """Return True if timestamp is within past week, False otherwise."""
        ...

    def mapper(self, _ line):
        """Parse each log line, extract and transform relevant lines.

        Emit key value pairs of the form:

        (category1, product1), 2
        (category2, product1), 2
        (category2, product1), 1
        (category1, product2), 3
        (category2, product3), 7
        (category1, product4), 1
        """
        timestamp, product_id, category_id, quantity, total_price, seller_id, \
            buyer_id = line.split('\t')
        if self.within_past_week(timestamp):
            yield (category_id, product_id), quantity

    def reducer(self, key, value):
        """Sum values for each key.

        (category1, product1), 2
        (category2, product1), 3
        (category1, product2), 3
        (category2, product3), 7
        (category1, product4), 1
        """
        yield key, sum(values)

    def mapper_sort(self, key, value):
        """Construct key to ensure proper sorting.

        Transform key and value to the form:

        (category1, 2), product1
        (category2, 3), product1
        (category1, 3), product2
        (category2, 7), product3
        (category1, 1), product4

        The shuffle/sort step of MapReduce will then do a
        distributed sort on the keys, resulting in:

        (category1, 1), product4
        (category1, 2), product1
        (category1, 3), product2
        (category2, 3), product1
        (category2, 7), product3
        """
        category_id, product_id = key
        quantity = value
        yield (category_id, quantity), product_id

    def reducer_identity(self, key, value):
        yield key, value

    def steps(self):
        """Run the map and reduce steps."""
        return [
            self.mr(mapper=self.mapper,
                    reducer=self.reducer),
            self.mr(mapper=self.mapper_sort,
                    reducer=self.reducer_identity),
        ]

The result would be the following sorted list, which we could insert into the sales_rank table:

(category1, 1), product4
(category1, 2), product1
(category1, 3), product2
(category2, 3), product1
(category2, 7), product3

The sales_rank table could have the following structure:

id int NOT NULL AUTO_INCREMENT
category_id int NOT NULL
total_sold int NOT NULL
product_id int NOT NULL
PRIMARY KEY(id)
FOREIGN KEY(category_id) REFERENCES Categories(id)
FOREIGN KEY(product_id) REFERENCES Products(id)

Use case: User views the past week's most popular products by category

  • The Client sends a request to the Web Server, running as a reverse proxy

  • The Web Server forwards the request to the Read API server

  • The Read API server reads from the SQL Database sales_rank table

We'll use a public REST API:

$ curl https://amazon.com/api/v1/popular?category_id=1234

Response:

{
    "id": "100",
    "category_id": "1234",
    "total_sold": "100000",
    "product_id": "50",
},
{
    "id": "53",
    "category_id": "1234",
    "total_sold": "90000",
    "product_id": "200",
},
{
    "id": "75",
    "category_id": "1234",
    "total_sold": "80000",
    "product_id": "3",
},

For internal communications, we could use Remote Procedure Calls.

Step 4: Scale the design

Important: Do not simply jump right into the final design from the initial design!

It's important to discuss what bottlenecks you might encounter with the initial design and how you might address each of them. For example, what issues are addressed by adding a Load Balancer with multiple Web Servers? CDN? Master-Slave Replicas? What are the alternatives and Trade-Offs for each?

We'll introduce some components to complete the design and to address scalability issues. Internal load balancers are not shown to reduce clutter.

The Analytics Database could use a data warehousing solution such as Amazon Redshift or Google BigQuery.

We might only want to store a limited time period of data in the database, while storing the rest in a data warehouse or in an Object Store. An Object Store such as Amazon S3 can comfortably handle the constraint of 40 GB of new content per month.

To address the 40,000 average read requests per second (higher at peak), traffic for popular content (and their sales rank) should be handled by the Memory Cache instead of the database. The Memory Cache is also useful for handling the unevenly distributed traffic and traffic spikes. With the large volume of reads, the SQL Read Replicas might not be able to handle the cache misses. We'll probably need to employ additional SQL scaling patterns.

400 average writes per second (higher at peak) might be tough for a single SQL Write Master-Slave, also pointing to a need for additional scaling techniques.

SQL scaling patterns include:

We should also consider moving some data to a NoSQL Database.

Additional talking points

Additional topics to dive into, depending on the problem scope and time remaining.

NoSQL

Caching

  • Where to cache

  • What to cache

  • When to update the cache

Asynchronism and microservices

Communications

  • Discuss tradeoffs:

Security

Latency numbers

Ongoing

  • Continue benchmarking and monitoring your system to address bottlenecks as they come up

  • Scaling is an iterative process

PreviousDesign a scalable file distribution systemNextDesign Mint.com

Last updated 4 years ago

Was this helpful?

We'll create an on id , category_id, and product_id to speed up lookups (log-time instead of scanning the entire table) and to keep the data in memory. Reading 1 MB sequentially from memory takes about 250 microseconds, while reading from SSD takes 4x and from disk takes 80x longer.

State you would 1) Benchmark/Load Test, 2) Profile for bottlenecks 3) address bottlenecks while evaluating alternatives and trade-offs, and 4) repeat. See as a sample on how to iteratively scale the initial design.

To avoid repeating discussions, refer to the following for main talking points, tradeoffs, and alternatives:

External communication with clients -

Internal communications -

Refer to the .

See .

index
Design a system that scales to millions of users on AWS
system design topics
DNS
CDN
Load balancer
Horizontal scaling
Web server (reverse proxy)
API server (application layer)
Cache
Relational database management system (RDBMS)
SQL write master-slave failover
Master-slave replication
Consistency patterns
Availability patterns
Federation
Sharding
Denormalization
SQL Tuning
Key-value store
Document store
Wide column store
Graph database
SQL vs NoSQL
Client caching
CDN caching
Web server caching
Database caching
Application caching
Caching at the database query level
Caching at the object level
Cache-aside
Write-through
Write-behind (write-back)
Refresh ahead
Message queues
Task queues
Back pressure
Microservices
HTTP APIs following REST
RPC
Service discovery
security section
Latency numbers every programmer should know