This project is a microservice module developed using .NET 9, Redis, and PostgreSQL technologies, based on real-life usage scenarios. Its primary goal is to demonstrate Best Practice approaches for high-performance caching strategies, data consistency, concurrency management, and real-time analytics requirements through practical applications.
The project minimizes database load by combining L1 (In-Memory) and L2 (Distributed) cache layers.
1. Performance Test (HybridCache)
When HybridCache is active, the response time drops from 30ms+ (Database) to around 1ms (Cache).
4. Concurrency Test (Distributed Lock)
Prevention of Race Condition during simultaneous requests.
Note: To simulate this test, we need to manually set the product stock to 1 and send parallel requests.
Step 1: Database Setup
Connect to the database terminal via Docker Desktop (Exec) and set the stock to 1:
psql -U postgres productredisdb
UPDATE "Products" SET "Stock" = 1 WHERE "Id" = 10;
SELECT "Id","Name","Stock" FROM "Products" WHERE "Id" = 10;Step 2: Parallel Requests (PowerShell) Run the script below in PowerShell to send 2 sales requests simultaneously:
$url = "http://localhost:5044/api/products/10/sell?qty=1"
# Start two parallel jobs
$job1 = Start-Job -ScriptBlock {
param($u)
try { Invoke-RestMethod -Uri $u -Method POST } catch { $_.Exception.Message }
} -ArgumentList $url
$job2 = Start-Job -ScriptBlock {
param($u)
try { Invoke-RestMethod -Uri $u -Method POST } catch { $_.Exception.Message }
} -ArgumentList $url
# Wait for jobs to finish
Wait-Job $job1, $job2
# Print results to console
Write-Host "--- Job 1 Result ---" -ForegroundColor Cyan
Receive-Job $job1
Write-Host "--- Job 2 Result ---" -ForegroundColor Yellow
Receive-Job $job2
# Clean up jobs
Remove-Job *| Feature | Technology Used | Solved Problem (Business Value) |
|---|---|---|
| Hybrid Caching | .NET 9 HybridCache |
Reducing database response time from 100ms to <1ms and decreasing network traffic. |
| Concurrency Control | Redis Distributed Lock |
Preventing stock errors (overselling) in thousands of simultaneous requests by solving the "Race Condition" problem. |
| Real-time Analytics | Redis Sorted Sets |
Listing the most popular products with O(log(N)) complexity without sending costly COUNT/SUM queries to the database. |
| Event-Driven Comm. | Redis Pub/Sub |
Asynchronous event management via Pub/Sub (Event-Driven). |
| Auto-Invalidation | Cache Aside Pattern |
Ensuring the user always sees fresh data by automatically cleaning the cache when data is updated. |
The following approaches were applied in this project to increase code quality and maintainability:
- Singleton Connection Pattern: The Redis
ConnectionMultiplexerobject is managed as a single instance (Singleton), minimizing TCP connection costs and resource consumption. - Dependency Injection (DI): Loose Coupling is ensured via the
IProductServiceinterface. - Clean Architecture (Lite): Domain, Infrastructure, and Application layers are logically separated, distributing responsibilities (Separation of Concerns).
- Background Services: Worker services running independently of the application lifecycle are integrated using
IHostedService.
The project requires Docker and .NET 9 SDK. No database installation is required; Docker Compose prepares the entire environment.
docker-compose up -dPostgreSQL (Port: 5436), Redis (Port: 6379), and RedisInsight (Port: 8001) are up and running.
dotnet runWhen the application starts, Seeding mechanisms engage, and 1000 sample products are automatically added to the database for testing.
| Method | Endpoint | Description | Expected Behavior (Test) |
|---|---|---|---|
GET |
/api/products/{id} |
Retrieves product details. | First request comes from DB (slow), second request from Cache (fast). |
PUT |
/api/products/{id}/price |
Updates price. | DB is updated, Cache is deleted (Invalidation), Pub/Sub message is published. |
POST |
/api/products/{id}/sell |
Performs product sale. | Distributed Lock engages. Returns error if stock is insufficient or transaction is locked. |
GET |
/api/products/top-products |
Lists popular products. | Most viewed products come instantly via Sorted Set. |
ProductService
├── 📁 Application
│ ├── 📂 DTOs
│ └── 📂 Interfaces
├── 📁 Domain
├── 📁 Infrastructure
│ ├── 📂 Data
│ └── 📂 Services
├── 📄 Program.cs
└── 🐳 docker-compose.ymlThis project has been developed to demonstrate .NET 9 and Redis capabilities.
Bu proje, .NET 9, Redis ve PostgreSQL teknolojileriyle geliştirilmiş, gerçek hayattaki kullanım senaryolarını esas alan bir mikroservis yapısını örneklemektedir. Temel hedefi; yüksek performanslı caching stratejileri, veri tutarlılığı (consistency), eşzamanlılık (concurrency) yönetimi ve gerçek zamanlı analitik gereksinimlerine yönelik Best Practice yaklaşımlarını pratik uygulamalar üzerinden ortaya koymaktır.
Proje, L1 (In-Memory) ve L2 (Distributed) cache katmanlarını birleştirerek veritabanı üzerindeki yükü minimize eder.
1. Performans Testi (HybridCache)
HybridCache devreye girdiğinde, veritabanından 30ms+ sürede gelen yanıt, önbellekten 1ms civarında dönmektedir.
3. Gerçek Zamanlı Analitik (Sorted Sets)
Redis Sorted Sets (ZSET) kullanılarak tutulan "En Çok Görüntülenenler" listesi.
4. Concurrency Testi (Distributed Lock)
Aynı anda gelen isteklerde Race Condition durumunun engellenmesi.
Not: Bu testi simüle etmek için ürün stoğunu manuel olarak 1'e düşürüp, paralel istek göndermemiz gerekmektedir.
Adım 1: Veritabanı Hazırlığı
Docker Desktop üzerinden veritabanı terminaline bağlanın (Exec) ve stoğu 1 yapın:
psql -U postgres productredisdb
UPDATE "Products" SET "Stock" = 1 WHERE "Id" = 10;
SELECT "Id","Name","Stock" FROM "Products" WHERE "Id" = 10;Adım 2: Paralel İstek (PowerShell) Aşağıdaki scripti PowerShell'de çalıştırarak aynı anda 2 satış isteği gönderin:
$url = "http://localhost:5044/api/products/10/sell?qty=1"
# İki paralel iş başlat (Start Jobs)
$job1 = Start-Job -ScriptBlock {
param($u)
try { Invoke-RestMethod -Uri $u -Method POST } catch { $_.Exception.Message }
} -ArgumentList $url
$job2 = Start-Job -ScriptBlock {
param($u)
try { Invoke-RestMethod -Uri $u -Method POST } catch { $_.Exception.Message }
} -ArgumentList $url
# İşlerin bitmesini bekle
Wait-Job $job1, $job2
# Sonuçları yazdır
Write-Host "--- Job 1 Result ---" -ForegroundColor Cyan
Receive-Job $job1
Write-Host "--- Job 2 Result ---" -ForegroundColor Yellow
Receive-Job $job2
# Temizlik
Remove-Job *| Özellik | Kullanılan Teknoloji | Çözülen Problem (Business Value) |
|---|---|---|
| Hybrid Caching | .NET 9 HybridCache |
Veritabanı yanıt süresini 100ms'den <1ms'ye düşürmek ve ağ trafiğini azaltmak. |
| Concurrency Control | Redis Distributed Lock |
"Race Condition" sorununu çözerek, aynı anda gelen binlerce istekte stok hatasını (overselling) engellemek. |
| Real-time Analytics | Redis Sorted Sets |
Veritabanına maliyetli COUNT/SUM sorguları atmadan, en popüler ürünleri O(log(N)) karmaşıklığında listelemek. |
| Event-Driven Comm. | Redis Pub/Sub |
Pub/Sub ile asenkron olay yönetimi (Event-Driven) |
| Auto-Invalidation | Cache Aside Pattern |
Veri güncellendiğinde cache'in otomatik temizlenerek kullanıcının her zaman güncel veri görmesini sağlamak. |
Bu projede kod kalitesini ve sürdürülebilirliği artırmak için aşağıdaki yaklaşımlar uygulanmıştır:
- Singleton Connection Pattern: Redis
ConnectionMultiplexernesnesi tek bir instance olarak yönetilerek (Singleton) TCP bağlantı maliyeti ve kaynak tüketimi minimize edildi. - Dependency Injection (DI):
IProductServicearayüzü üzerinden gevşek bağımlılık (Loose Coupling) sağlandı. - Clean Architecture (Lite): Domain, Infrastructure ve Application katmanları mantıksal olarak ayrılarak sorumluluklar (Separation of Concerns) dağıtıldı.
- Background Services:
IHostedServicekullanılarak uygulama yaşam döngüsünden bağımsız çalışan Worker servisleri entegre edildi.
Proje, Docker ve .NET 9 SDK gerektirir. Herhangi bir veritabanı kurulumuna gerek yoktur, Docker Compose tüm ortamı hazırlar.
docker-compose up -dPostgreSQL (Port: 5436), Redis (Port: 6379) ve RedisInsight (Port: 8001) ayağa kalkar.
dotnet runUygulama başlatıldığında Seeding mekanizmaları devreye girer ve test için veritabanına 1000 adet ürün otomatik olarak eklenir.
| Metod | Endpoint | Açıklama | Beklenen Davranış (Test) |
|---|---|---|---|
GET |
/api/products/{id} |
Ürün detayını getirir. | İlk istek DB'den (yavaş), ikinci istek Cache'den (hızlı) döner. |
PUT |
/api/products/{id}/price |
Fiyat günceller. | DB güncellenir, Cache silinir (Invalidation), Pub/Sub mesajı yayınlanır. |
POST |
/api/products/{id}/sell |
Ürün satışı yapar. | Distributed Lock devreye girer. Stok yetersizse veya işlem kilitliyse hata döner. |
GET |
/api/products/top-products |
Popüler ürünleri listeler. | En çok görüntülenen ürünler Sorted Set üzerinden anlık gelir. |
ProductService
├── 📁 Application
│ ├── 📂 DTOs
│ └── 📂 Interfaces
├── 📁 Domain
├── 📁 Infrastructure
│ ├── 📂 Data
│ └── 📂 Services
├── 📄 Program.cs
└── 🐳 docker-compose.ymlBu proje .NET 9 ve Redis yeteneklerini göstermek amacıyla geliştirilmiştir.