system-design-patterns
π―Skillfrom thapaliyabikendra/ai-artifacts
Designs scalable, reliable distributed systems by applying proven architectural patterns and evaluating trade-offs across performance, consistency, and availability.
Installation
npx skills add https://github.com/thapaliyabikendra/ai-artifacts --skill system-design-patternsSkill Details
"System design patterns for scalability, reliability, and performance. Use when: (1) designing distributed systems, (2) planning for scale, (3) making architecture decisions, (4) evaluating trade-offs."
Overview
# System Design Patterns
Design scalable, reliable, and performant systems with proven patterns.
When to Use
- Designing new systems or features
- Evaluating architecture trade-offs
- Planning for scale
- Improving system reliability
- Making infrastructure decisions
Core Principles
CAP Theorem
| Property | Meaning | Trade-off |
|----------|---------|-----------|
| Consistency | All nodes see the same data | Higher latency |
| Availability | System responds to every request | May return stale data |
| Partition Tolerance | System works despite network failures | Must sacrifice C or A |
Choose 2:
- CP: Banking, inventory (consistency critical)
- AP: Social media, caching (availability critical)
- CA: Single-node systems only (no network partitions)
ACID vs BASE
| ACID (Traditional RDBMS) | BASE (Distributed) |
|--------------------------|-------------------|
| Atomicity | Basically Available |
| Consistency | Soft state |
| Isolation | Eventually consistent |
| Durability | |
Scalability Patterns
Horizontal vs Vertical Scaling
```
Vertical Scaling (Scale Up) Horizontal Scaling (Scale Out)
βββββββββββββββββββββββββββ ββββββββ ββββββββ ββββββββ
β β β β β β β β
β Bigger Server β vs βServerβ βServerβ βServerβ
β β β β β β β β
β More CPU, RAM, Storage β β β β β β β
βββββββββββββββββββββββββββ ββββββββ ββββββββ ββββββββ
Pros: Pros:
- Simple to implement - Near-infinite scale
- No code changes - Fault tolerant
- Lower operational complexity - Cost effective at scale
Cons: Cons:
- Hardware limits - Distributed complexity
- Single point of failure - Data consistency challenges
- Expensive at scale - More operational overhead
```
Load Balancing Strategies
```csharp
// Strategy selection based on use case
public enum LoadBalancingStrategy
{
// Simple, stateless services
RoundRobin,
// Varying server capacities
WeightedRoundRobin,
// Session affinity needed
IpHash,
// Optimal resource utilization
LeastConnections,
// Latency-sensitive applications
LeastResponseTime,
// Geographic distribution
GeographicBased
}
```
| Strategy | Use Case | Trade-off |
|----------|----------|-----------|
| Round Robin | Stateless, homogeneous | No health awareness |
| Weighted | Different server sizes | Manual configuration |
| IP Hash | Session stickiness | Uneven distribution |
| Least Connections | Long-lived connections | Overhead tracking |
| Geographic | Global users | Complexity |
Database Scaling
#### Read Replicas
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Application β
ββββββββββββββββββββββββ¬βββββββββββββββββββββββββββββββ
β
ββββββββββββββββ΄βββββββββββββββ
β β
βΌ βΌ
βββββββββββββββββ βββββββββββββββββββ
β Primary DB ββββββββββββΊβ Read Replica 1 β
β (Writes) β Async βββββββββββββββββββ€
β ββββββββββββΊβ Read Replica 2 β
βββββββββββββββββ Repl βββββββββββββββββββ
β²
β
Read Queries
```
```csharp
// Read/Write splitting in ABP
public class PatientAppService : ApplicationService
{
private readonly IReadOnlyRepository
private readonly IRepository
// Reads go to replicas
public async Task
{
var patient = await _readRepository.GetAsync(id);
return ObjectMapper.Map
}
// Writes go to primary
public async Task
{
var patient = new Patient(GuidGenerator.Create(), input.Name);
await _writeRepository.InsertAsync(patient);
return ObjectMapper.Map
}
}
```
#### Database Sharding
```
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Shard Router β
β (Routes queries based on shard key) β
ββββββββββββββ¬βββββββββββββββ¬βββββββββββββββ¬ββββββββββββββββββ
β β β
βΌ βΌ βΌ
βββββββββββββ βββββββββββββ βββββββββββββ
β Shard 1 β β Shard 2 β β Shard 3 β
β A - H β β I - P β β Q - Z β
β (Users) β β (Users) β β (Users) β
βββββββββββββ βββββββββββββ βββββββββββββ
```
| Sharding Strategy | Pros | Cons |
|-------------------|------|------|
| Range-based | Simple, range queries work | Hotspots possible |
| Hash-based | Even distribution | Range queries need scatter-gather |
| Directory-based | Flexible | Lookup overhead, SPOF |
| Geographic | Data locality | Cross-region queries slow |
Caching Patterns
Cache-Aside (Lazy Loading)
```csharp
public class PatientService
{
private readonly IDistributedCache _cache;
private readonly IPatientRepository _repository;
public async Task
{
var cacheKey = $"patient:{id}";
// 1. Check cache
var cached = await _cache.GetStringAsync(cacheKey);
if (cached != null)
{
return JsonSerializer.Deserialize
}
// 2. Cache miss - load from DB
var patient = await _repository.GetAsync(id);
var dto = ObjectMapper.Map
// 3. Populate cache
await _cache.SetStringAsync(
cacheKey,
JsonSerializer.Serialize(dto),
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
});
return dto;
}
public async Task UpdateAsync(Guid id, UpdatePatientDto input)
{
// Update database
var patient = await _repository.GetAsync(id);
patient.Update(input.Name, input.Email);
await _repository.UpdateAsync(patient);
// Invalidate cache
await _cache.RemoveAsync($"patient:{id}");
}
}
```
Write-Through Cache
```csharp
public async Task
{
// 1. Write to database
var patient = new Patient(GuidGenerator.Create(), input.Name);
await _repository.InsertAsync(patient);
// 2. Write to cache synchronously
var dto = ObjectMapper.Map
await _cache.SetStringAsync(
$"patient:{patient.Id}",
JsonSerializer.Serialize(dto),
new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10)
});
return dto;
}
```
Cache Strategies Comparison
| Pattern | Consistency | Performance | Use Case |
|---------|-------------|-------------|----------|
| Cache-Aside | Eventual | Read-heavy | User profiles |
| Write-Through | Strong | Write + Read | Financial data |
| Write-Behind | Eventual | Write-heavy | Analytics, logs |
| Read-Through | Eventual | Read-heavy | Reference data |
Reliability Patterns
Circuit Breaker
```csharp
// Using Polly
public class ExternalServiceClient
{
private readonly HttpClient _client;
private readonly AsyncCircuitBreakerPolicy _circuitBreaker;
public ExternalServiceClient(HttpClient client)
{
_client = client;
_circuitBreaker = Policy
.Handle
.CircuitBreakerAsync(
exceptionsAllowedBeforeBreaking: 5,
durationOfBreak: TimeSpan.FromSeconds(30),
onBreak: (ex, duration) =>
Log.Warning("Circuit opened for {Duration}s", duration.TotalSeconds),
onReset: () =>
Log.Information("Circuit closed"),
onHalfOpen: () =>
Log.Information("Circuit half-open, testing...")
);
}
public async Task
{
return await _circuitBreaker.ExecuteAsync(async () =>
{
var response = await _client.GetAsync(endpoint);
response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync
});
}
}
```
Retry with Exponential Backoff
```csharp
var retryPolicy = Policy
.Handle
.WaitAndRetryAsync(
retryCount: 3,
sleepDurationProvider: attempt =>
TimeSpan.FromSeconds(Math.Pow(2, attempt)), // 2, 4, 8 seconds
onRetry: (ex, delay, attempt, context) =>
Log.Warning("Retry {Attempt} after {Delay}s: {Error}",
attempt, delay.TotalSeconds, ex.Message)
);
```
Bulkhead Pattern
```csharp
// Isolate failures to prevent cascade
var bulkhead = Policy.BulkheadAsync(
maxParallelization: 10, // Max concurrent executions
maxQueuingActions: 20, // Max queued requests
onBulkheadRejectedAsync: context =>
{
Log.Warning("Bulkhead rejected request");
return Task.CompletedTask;
}
);
```
Event-Driven Architecture
Message Queue Pattern
```
βββββββββββ βββββββββββββββ βββββββββββββββ
β Service βββββΊβ Message βββββΊβ Consumer β
β A β β Queue β β Service B β
βββββββββββ β β βββββββββββββββ
β (RabbitMQ, β
β Kafka, β βββββββββββββββ
β Azure SB) βββββΊβ Consumer β
βββββββββββββββ β Service C β
βββββββββββββββ
```
Event Sourcing
```csharp
// Store events, not state
public class PatientAggregate
{
private readonly List
public Guid Id { get; private set; }
public string Name { get; private set; }
public PatientStatus Status { get; private set; }
public void Apply(PatientCreated @event)
{
Id = @event.PatientId;
Name = @event.Name;
Status = PatientStatus.Active;
_events.Add(@event);
}
public void Apply(PatientNameChanged @event)
{
Name = @event.NewName;
_events.Add(@event);
}
// Rebuild state from events
public static PatientAggregate FromEvents(IEnumerable
{
var patient = new PatientAggregate();
foreach (var @event in events)
{
patient.Apply((dynamic)@event);
}
return patient;
}
}
```
Quick Reference: Design Trade-offs
| Decision | Option A | Option B | Consider |
|----------|----------|----------|----------|
| Storage | SQL | NoSQL | Data structure, consistency needs |
| Caching | Redis | In-memory | Distributed needs, size |
| Communication | Sync (HTTP) | Async (Queue) | Coupling, latency tolerance |
| Consistency | Strong | Eventual | Business requirements |
| Scaling | Vertical | Horizontal | Cost, complexity, limits |
System Design Checklist
- [ ] Requirements: Functional + Non-functional defined
- [ ] Scale: Expected users, requests/sec, data volume
- [ ] Availability: Uptime target (99.9% = 8.76h downtime/year)
- [ ] Latency: P50, P95, P99 targets
- [ ] Data: Storage type, retention, backup strategy
- [ ] Caching: What to cache, invalidation strategy
- [ ] Security: Auth, encryption, compliance
- [ ] Monitoring: Metrics, logging, alerting
- [ ] Failure modes: What happens when X fails?
- [ ] Cost: Infrastructure, operational overhead
Related Skills
technical-design-patterns- Document designsapi-design-principles- API architecturedistributed-events-advanced- Event patterns
More from this repository10
Provides clean code guidelines and refactoring techniques for C#/.NET, focusing on improving code readability, maintainability, and adherence to SOLID principles.
Implements comprehensive REST APIs in ABP Framework with robust AppServices, DTOs, pagination, filtering, and authorization for .NET applications.
Implements domain layer patterns for ABP Framework, providing robust entity, aggregate, repository, and domain service implementations following DDD principles.
Validates input DTOs in ABP Framework using FluentValidation with async checks, conditional rules, custom validators, and localized error messages.
abp-infrastructure-patterns skill from thapaliyabikendra/ai-artifacts
Configures and optimizes Entity Framework Core patterns for ABP Framework, focusing on entity configuration, migrations, and relationship design with PostgreSQL.
content-retrieval skill from thapaliyabikendra/ai-artifacts
Generates ABP Application.Contracts layer scaffolding, enabling parallel development by creating standardized interfaces, DTOs, and permissions for .NET microservices.
Implements permission-based OAuth 2.0 authorization for ABP Framework using OpenIddict, enabling fine-grained access control and multi-tenant security.
api-response-patterns skill from thapaliyabikendra/ai-artifacts