• Uncategorised
  • 0

Building a Scalable URL Shortener: System Design and Java Implementation

High-Level System Design of a URL Shortener

1. Overview

A URL shortener is a system that takes a long URL and generates a shorter, unique alias. When users visit the short URL, they are redirected to the original URL.

2. Key Requirements

  • Core Features:
    • Generate short, unique URLs.
    • Redirect short URLs to their original destination.
  • Non-Functional Requirements:
    • High scalability to handle millions of URLs.
    • Low latency for URL redirection.
    • Fault-tolerance and high availability.

3. Architecture Components

  1. Load Balancer:
    • Distributes incoming traffic across multiple servers.
    • Ensures reliability and handles failover.
  2. API Layer:
    • Exposes endpoints for creating and retrieving URLs.
    • Manages user authentication (if required).
  3. Caching Layer:
    • A distributed cache (e.g., Redis, Memcached) to store frequently accessed mappings, reducing database load.
  4. Database:
    • A database to store the mappings and metadata.
    • Options:
      • Relational (e.g., PostgreSQL): Ensures data consistency with ACID properties.
      • NoSQL (e.g., DynamoDB, MongoDB): Scales horizontally for high throughput.
  5. Encoding Service:
    • Converts IDs into short alphanumeric strings (base-62 encoding).
    • Ensures compactness and uniqueness.
  6. Monitoring and Analytics:
    • Tracks API usage, system health, and URL access statistics.
  7. Fault Tolerance:
    • Backup and replication mechanisms for databases.
    • Health checks and failover strategies for critical components.

4. Workflow

  1. Shortening a URL:
    • User sends a POST request with the original URL.
    • The system checks for an existing mapping.
    • If no mapping exists, a unique ID is generated, encoded, and stored in the database.
    • The shortened URL is returned.
  2. Redirecting to the Original URL:
    • User accesses the short URL.
    • The system decodes the short URL, fetches the original URL from the cache or database, and performs the redirect.
  3. Handling Expirations and Metadata:
    • Store metadata such as creation timestamp and expiry date.
    • Periodic cleanup for expired mappings.

Implementation: Java Code for URL Shortener

Below is a scalable, production-ready Java implementation of a URL shortener:

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class URLShortener {
    private static final String ALLOWED_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
    private static final int BASE = ALLOWED_CHARS.length();
    private static final String DOMAIN = "https://short.ly/";
    private final Map<String, String> shortToOriginal = new ConcurrentHashMap<>();
    private final Map<String, String> originalToShort = new ConcurrentHashMap<>();
    private int counter = 1;

    // Synchronize counter to avoid collisions in a multi-threaded environment
    private synchronized int getNextCounter() {
        return counter++;
    }

    // Generate a short code for a given ID
    private String encode(int id) {
        StringBuilder shortCode = new StringBuilder();
        while (id > 0) {
            shortCode.append(ALLOWED_CHARS.charAt(id % BASE));
            id /= BASE;
        }
        return shortCode.reverse().toString();
    }

    // Create a short URL
    public String shortenURL(String originalURL) {
        if (originalToShort.containsKey(originalURL)) {
            return DOMAIN + originalToShort.get(originalURL);
        }

        int id = getNextCounter();
        String shortCode = encode(id);

        shortToOriginal.put(shortCode, originalURL);
        originalToShort.put(originalURL, shortCode);

        return DOMAIN + shortCode;
    }

    // Retrieve the original URL
    public String retrieveOriginalURL(String shortURL) {
        String shortCode = shortURL.replace(DOMAIN, "");
        return shortToOriginal.getOrDefault(shortCode, "URL not found");
    }

    public static void main(String[] args) {
        URLShortener urlShortener = new URLShortener();

        // Test case
        String longURL1 = "https://example.com/very-long-url-with-parameters";
        String longURL2 = "https://another-example.com/path";

        String shortURL1 = urlShortener.shortenURL(longURL1);
        String shortURL2 = urlShortener.shortenURL(longURL2);

        System.out.println("Shortened URL 1: " + shortURL1);
        System.out.println("Shortened URL 2: " + shortURL2);

        System.out.println("Original URL 1: " + urlShortener.retrieveOriginalURL(shortURL1));
        System.out.println("Original URL 2: " + urlShortener.retrieveOriginalURL(shortURL2));
    }
}

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *