![]()
System design is a critical skill for Java developers, especially for senior roles. It involves designing scalable, maintainable, and efficient systems. Below are some common Java system design questions that you might encounter in interviews, along with detailed explanations and example answers.
1. Design a URL Shortening Service (e.g., TinyURL)
- Requirements:
- Shorten long URLs.
- Redirect users from the short URL to the original URL.
- Handle high traffic and ensure scalability.
- Key Components:
- URL Encoding: Use a hash function (e.g., Base62) to generate short URLs.
- Database: Store mappings between short and long URLs.
- Cache: Use a distributed cache (e.g., Redis) to store frequently accessed URLs.
- Load Balancer: Distribute traffic across multiple servers.
- Example:
public class URLShortener {
private Map<String, String> urlMap = new HashMap<>();
private static final String BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
public String shortenURL(String longURL) {
String shortURL = generateShortURL(longURL);
urlMap.put(shortURL, longURL);
return shortURL;
}
public String getLongURL(String shortURL) {
return urlMap.get(shortURL);
}
private String generateShortURL(String longURL) {
int hash = longURL.hashCode();
StringBuilder shortURL = new StringBuilder();
while (hash > 0) {
shortURL.append(BASE62.charAt(hash % 62));
hash /= 62;
}
return shortURL.toString();
}
}
2. Design a Distributed Cache (e.g., Memcached)
- Requirements:
- Store key-value pairs in memory.
- Support high read/write throughput.
- Ensure data consistency and fault tolerance.
- Key Components:
- Hashing: Use consistent hashing to distribute keys across nodes.
- Replication: Replicate data across multiple nodes for fault tolerance.
- Eviction Policy: Use LRU (Least Recently Used) or LFU (Least Frequently Used) for cache eviction.
- Load Balancer: Distribute requests across cache nodes.
- Example:
public class DistributedCache {
private Map<String, String> cache = new HashMap<>();
private int capacity;
private Queue<String> lruQueue = new LinkedList<>();
public DistributedCache(int capacity) {
this.capacity = capacity;
}
public String get(String key) {
if (cache.containsKey(key)) {
lruQueue.remove(key);
lruQueue.add(key);
return cache.get(key);
}
return null;
}
public void put(String key, String value) {
if (cache.size() >= capacity) {
String oldestKey = lruQueue.poll();
cache.remove(oldestKey);
}
cache.put(key, value);
lruQueue.add(key);
}
}
3. Design a Social Media News Feed (e.g., Facebook, Twitter)
- Requirements:
- Display a personalized news feed for each user.
- Handle high read/write traffic.
- Ensure low latency and high availability.
- Key Components:
- Data Storage: Use a distributed database (e.g., Cassandra) to store posts and user data.
- Caching: Use a distributed cache (e.g., Redis) to store news feeds.
- Fan-out on Write: Precompute and store news feeds for each user when a post is made.
- Load Balancer: Distribute traffic across multiple servers.
- Example:
public class NewsFeedService {
private Map<String, List<String>> userFeeds = new HashMap<>();
public void post(String userId, String post) {
List<String> followers = getFollowers(userId);
for (String follower : followers) {
userFeeds.computeIfAbsent(follower, k -> new ArrayList<>()).add(post);
}
}
public List<String> getNewsFeed(String userId) {
return userFeeds.getOrDefault(userId, new ArrayList<>());
}
private List<String> getFollowers(String userId) {
// Fetch followers from database
return List.of("follower1", "follower2");
}
}
4. Design a Rate Limiter
- Requirements:
- Limit the number of requests a user can make within a time window.
- Handle high traffic and ensure scalability.
- Key Components:
- Token Bucket Algorithm: Use tokens to represent allowed requests.
- Distributed Cache: Store token counts in a distributed cache (e.g., Redis).
- Load Balancer: Distribute traffic across multiple servers.
- Example:
public class RateLimiter {
private Map<String, Integer> tokenBucket = new HashMap<>();
private int maxTokens;
private long refillInterval;
public RateLimiter(int maxTokens, long refillInterval) {
this.maxTokens = maxTokens;
this.refillInterval = refillInterval;
}
public synchronized boolean allowRequest(String userId) {
int tokens = tokenBucket.getOrDefault(userId, maxTokens);
if (tokens > 0) {
tokenBucket.put(userId, tokens - 1);
return true;
}
return false;
}
public void refillTokens() {
new Timer().scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
for (String userId : tokenBucket.keySet()) {
tokenBucket.put(userId, maxTokens);
}
}
}, 0, refillInterval);
}
}
5. Design a Distributed File Storage System (e.g., Google Drive)
- Requirements:
- Store and retrieve files efficiently.
- Handle high traffic and ensure fault tolerance.
- Key Components:
- File Chunking: Split files into smaller chunks for efficient storage and retrieval.
- Distributed Storage: Use a distributed file system (e.g., HDFS) to store file chunks.
- Metadata Storage: Use a distributed database (e.g., Cassandra) to store file metadata.
- Load Balancer: Distribute traffic across multiple servers.
- Example:
public class FileStorageService {
private Map<String, List<String>> fileChunks = new HashMap<>();
public void uploadFile(String fileId, List<String> chunks) {
fileChunks.put(fileId, chunks);
}
public List<String> downloadFile(String fileId) {
return fileChunks.get(fileId);
}
}
Best Practices
- Scalability: Design systems to handle increasing loads by adding more resources.
- Fault Tolerance: Ensure systems can recover from failures gracefully.
- Consistency: Choose the right consistency model (e.g., eventual consistency, strong consistency) based on requirements.
- Performance: Optimize for low latency and high throughput.
- Monitoring: Implement monitoring and logging for observability.
Resources
- Books: “Designing Data-Intensive Applications” by Martin Kleppmann.
- Websites: System Design Primer, High Scalability.
- Tools: Redis, Cassandra, HDFS.
