Əsas məzmuna keçin

URL Qısaldıcı Sistem Dizaynı

Problem Təsviri

TinyURL və ya bit.ly kimi URL qısaldıcı servis dizayn edin. Bu sistem uzun URL-ləri qısa və unikal URL-lərə çevirməli və istifadəçiləri qısa URL-dən orijinal uzun URL-ə yönləndirməlidir.

Tələblər

  1. Funksional Tələblər:

    • Uzun URL-ləri qısa URL-lərə çevirmək
    • Qısa URL-lərdən orijinal URL-lərə yönləndirmək
    • İstifadəçilərə custom qısa URL təyin etmək imkanı (isteğe bağlı)
    • URL-lər üçün expiration müddəti təyin etmək (isteğe bağlı)
  2. Qeyri-Funksional Tələblər:

    • Yüksək availability
    • Yönləndirmə üçün aşağı latency
    • URL-lərin təxmin edilməsi çətin olmalı
    • Sistem scalable olmalı

Əsas Komponentlər

  1. URL Qısaldma Servisi: Uzun URL-ləri qısa URL-lərə çevirir
  2. URL Saxlama: Qısa və uzun URL-lər arasında mapping saxlayır
  3. URL Yönləndirmə Servisi: İstifadəçiləri qısa URL-dən orijinal URL-lərə yönləndirir

Dizayn Yanaşması

Müxtəlif URL qısaldma alqoritmlərini dəstəkləmək üçün Strategy Pattern istifadə edəcəyik:

  1. Random String Generation: Təsadüfi simvol sətri yaratmaq
  2. Base62 Encoding: Artan ID-ni Base62 string-ə çevirmək
  3. MD5 Hashing: URL-nin hash-ini yaradıb substring almaq

Implementation

Koda bax
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

// Strategy interface for URL shortening algorithms
interface UrlShorteningStrategy {
String shortenUrl(String longUrl);
}

// Random string generation strategy
class RandomStringStrategy implements UrlShorteningStrategy {
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final int SHORT_URL_LENGTH = 7;
private final Random random = new Random();

@Override
public String shortenUrl(String longUrl) {
StringBuilder sb = new StringBuilder(SHORT_URL_LENGTH);
for (int i = 0; i < SHORT_URL_LENGTH; i++) {
int randomIndex = random.nextInt(CHARACTERS.length());
sb.append(CHARACTERS.charAt(randomIndex));
}
return sb.toString();
}
}

// Base62 encoding strategy
class Base62Strategy implements UrlShorteningStrategy {
private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
private static final int BASE = CHARACTERS.length();
private final AtomicLong counter = new AtomicLong(1000000); // Start from a non-zero value

@Override
public String shortenUrl(String longUrl) {
long id = counter.incrementAndGet();
StringBuilder sb = new StringBuilder();

while (id > 0) {
sb.append(CHARACTERS.charAt((int) (id % BASE)));
id /= BASE;
}

return sb.reverse().toString();
}
}

// MD5 hashing strategy
class MD5HashingStrategy implements UrlShorteningStrategy {
private static final int SHORT_URL_LENGTH = 7;

@Override
public String shortenUrl(String longUrl) {
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] digest = md.digest(longUrl.getBytes());
String hash = Base64.getUrlEncoder().encodeToString(digest);
return hash.substring(0, SHORT_URL_LENGTH);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5 algorithm not found", e);
}
}
}

// URL Shortener service
class UrlShortener {
private final UrlShorteningStrategy strategy;
private final Map<String, String> shortToLongMap;
private final Map<String, String> longToShortMap;

public UrlShortener(UrlShorteningStrategy strategy) {
this.strategy = strategy;
// Using ConcurrentHashMap for thread safety
this.shortToLongMap = new ConcurrentHashMap<>();
this.longToShortMap = new ConcurrentHashMap<>();
}

public String shorten(String longUrl) {
// Check if URL is already shortened
if (longToShortMap.containsKey(longUrl)) {
return longToShortMap.get(longUrl);
}

// Generate a short URL
String shortUrl;
do {
shortUrl = strategy.shortenUrl(longUrl);
} while (shortToLongMap.containsKey(shortUrl)); // Ensure uniqueness

// Store the mapping
shortToLongMap.put(shortUrl, longUrl);
longToShortMap.put(longUrl, shortUrl);

return shortUrl;
}

public String expand(String shortUrl) {
return shortToLongMap.get(shortUrl);
}
}

// Example usage
public class UrlShortenerDemo {
public static void main(String[] args) {
// Create URL shortener with Base62 strategy
UrlShortener shortener = new UrlShortener(new Base62Strategy());

// Shorten a URL
String longUrl = "https://www.example.com/very/long/url/that/needs/shortening";
String shortUrl = shortener.shorten(longUrl);
System.out.println("Short URL: " + shortUrl);

// Expand the short URL
String expandedUrl = shortener.expand(shortUrl);
System.out.println("Original URL: " + expandedUrl);
}
}

Thread Safety Mülahizələri

  1. ConcurrentHashMap: URL mapping-lərə thread-safe giriş üçün istifadə edilir
  2. AtomicLong: Base62 strategiyasında thread-safe counter artımı üçün istifadə edilir
  3. Immutable Strategy-lər: Strategy implementasiyaları faktiki olaraq immutable-dır

Scaling Mülahizələri

  1. Distributed Storage: Böyük miqyaslı sistemlər üçün in-memory map-ləri distributed database ilə əvəz edin
  2. Caching: Tez-tez istifadə olunan URL-lər üçün caching əlavə edin
  3. Load Balancing: Sorğuları çoxlu instance-lər arasında paylaşdırın
  4. Collision Handling: Daha mürəkkəb collision detection və resolution tətbiq edin

Əlavə Xüsusiyyətlər

  1. Custom URL-lər: İstifadəçilərə öz qısa URL-lərini təyin etmək imkanı verin
  2. Analytics: Click-through rate və digər metrikləri izləyin
  3. Expiration: URL-lər üçün expiration vaxtı təyin edin