From ba928022cb30c1cd7bad9cd3f6cee1b34fff8882 Mon Sep 17 00:00:00 2001 From: Ho Ngoc Hai Date: Mon, 12 Jan 2026 18:48:50 +0700 Subject: [PATCH] feat(docs): Update architecture and caching documentation - Added detailed sections on distributed caching architecture, including caching overview, ICacheService interface, and caching strategies for tokens and sessions. - Enhanced documentation with mermaid diagrams to illustrate caching flows and key patterns. - Updated Redis configuration instructions in the README, including environment variable setup and usage examples for caching operations. - Removed outdated notes from the NOTE.MD file to streamline content and focus on relevant tasks and proposals. --- NOTE.MD | 9 - .../iam-service-net/docs/en/ARCHITECTURE.md | 157 +++++++++++++++++- .../iam-service-net/docs/vi/ARCHITECTURE.md | 157 +++++++++++++++++- services/iam-service-net/docs/vi/README.md | 102 ++++++++++++ 4 files changed, 410 insertions(+), 15 deletions(-) diff --git a/NOTE.MD b/NOTE.MD index 4fb36729..4e04fb94 100644 --- a/NOTE.MD +++ b/NOTE.MD @@ -8,15 +8,6 @@ Có Cached chưa -⚠️ Vấn đề phát hiện: -/connect/token endpoint không phản hồi - OAuth2 token endpoint bị treo khi gửi request. Có vẻ OpenIddict Server middleware không xử lý request đúng cách. - -Bạn muốn tôi làm gì tiếp: -Fix OAuth2 /connect/token endpoint - Debug và sửa lỗi OpenIddict configuration -Chỉ cần database connection - Nếu chỉ cần verify database connection thì đã hoàn thành -Tiếp tục với task khác - Cần hướng dẫn cụ thể - - Đề xuất cần implement: Redis Connection - Đăng ký IConnectionMultiplexer trong DI Distributed Caching Service - Sử dụng IDistributedCache diff --git a/services/iam-service-net/docs/en/ARCHITECTURE.md b/services/iam-service-net/docs/en/ARCHITECTURE.md index 149c038e..e0958089 100644 --- a/services/iam-service-net/docs/en/ARCHITECTURE.md +++ b/services/iam-service-net/docs/en/ARCHITECTURE.md @@ -367,12 +367,163 @@ All errors return Problem Details format: } ``` +## Distributed Caching Architecture + +### Caching Overview + +```mermaid +graph TB + subgraph "Application" + SVC[Services] + CACHE[ICacheService] + end + + subgraph "Caching Layer" + REDIS[(Redis Server)] + TOKEN[Token Cache] + SESSION[Session Cache] + DATA[Data Cache] + end + + SVC --> CACHE + CACHE --> REDIS + REDIS --> TOKEN + REDIS --> SESSION + REDIS --> DATA + + style CACHE fill:#e74c3c,stroke:#c0392b,color:#fff + style REDIS fill:#d35400,stroke:#a04000,color:#fff + style TOKEN fill:#9b59b6,stroke:#7d3c98,color:#fff + style SESSION fill:#3498db,stroke:#2980b9,color:#fff + style DATA fill:#2ecc71,stroke:#27ae60,color:#fff +``` + +### ICacheService Interface + +The service implements a generic `ICacheService` interface for distributed caching: + +| Method | Purpose | +|--------|---------| +| `GetAsync` | Retrieve cached item by key | +| `SetAsync` | Store item with optional TTL | +| `RemoveAsync` | Delete cached item | +| `ExistsAsync` | Check if key exists | +| `GetOrSetAsync` | Cache-aside pattern | +| `BlacklistAsync` | Add to token blacklist | +| `IsBlacklistedAsync` | Check token blacklist | + +### Token Caching Strategy + +```mermaid +sequenceDiagram + participant Client + participant AuthController + participant CacheService + participant Redis + participant Database + + Note over Client,Database: Token Validation with Cache + + Client->>AuthController: Request with JWT + AuthController->>CacheService: IsBlacklistedAsync(tokenId) + CacheService->>Redis: GET blacklist:token:{id} + Redis-->>CacheService: null (not blacklisted) + CacheService-->>AuthController: false + AuthController->>AuthController: Validate JWT Claims + AuthController-->>Client: Response + + Note over Client,Database: Token Revocation (Logout) + + Client->>AuthController: POST /logout + AuthController->>CacheService: BlacklistAsync(tokenId, 7 days) + CacheService->>Redis: SETEX blacklist:token:{id} 604800 "1" + Redis-->>CacheService: OK + AuthController-->>Client: 200 OK +``` + +### Token Cache Keys + +| Key Pattern | Purpose | TTL | +|-------------|---------|-----| +| `blacklist:token:{tokenId}` | Revoked tokens | Token remaining lifetime | +| `blacklist:refresh:{tokenId}` | Revoked refresh tokens | 7 days | +| `user:{userId}:tokens` | User's active tokens | 15 minutes | + +### Session Caching Strategy + +```mermaid +graph LR + subgraph "Session Data" + UID[User ID] + ROLES[User Roles] + PERMS[Permissions] + CLAIMS[Claims] + end + + subgraph "Cache Keys" + K1[session:{userId}] + K2[user:{userId}:roles] + K3[user:{userId}:permissions] + end + + UID --> K1 + ROLES --> K2 + PERMS --> K3 + + style K1 fill:#3498db,stroke:#2980b9,color:#fff + style K2 fill:#9b59b6,stroke:#7d3c98,color:#fff + style K3 fill:#2ecc71,stroke:#27ae60,color:#fff +``` + +### Session Cache Keys + +| Key Pattern | Purpose | TTL | +|-------------|---------|-----| +| `session:{userId}` | User session data | 30 minutes | +| `user:{userId}:roles` | Cached user roles | 15 minutes | +| `user:{userId}:permissions` | Computed permissions | 15 minutes | +| `user:{userId}:profile` | User profile data | 10 minutes | + +### Cache-Aside Pattern + +```mermaid +sequenceDiagram + participant Service + participant CacheService + participant Redis + participant Database + + Service->>CacheService: GetOrSetAsync(key, factory) + CacheService->>Redis: GET key + + alt Cache Hit + Redis-->>CacheService: cached data + CacheService-->>Service: return data + else Cache Miss + Redis-->>CacheService: null + CacheService->>Database: factory() - fetch data + Database-->>CacheService: data + CacheService->>Redis: SETEX key ttl data + CacheService-->>Service: return data + end +``` + +### Cache Invalidation Strategies + +| Strategy | When to Use | Implementation | +|----------|-------------|----------------| +| **Time-based (TTL)** | General data | `SetAsync(..., TimeSpan.FromMinutes(15))` | +| **Event-based** | User updates | Remove cache on update event | +| **Pattern-based** | Bulk invalidation | `RemoveByPatternAsync("user:*")` | + ## Performance Considerations 1. **Connection Pooling**: EF Core with Npgsql resilience -2. **Token Caching**: Redis for token validation -3. **Async Operations**: All I/O operations are async -4. **Database Indexes**: Configured in EntityConfigurations +2. **Token Caching**: Redis for token validation and blacklist +3. **Session Caching**: User sessions and permissions cached +4. **Async Operations**: All I/O operations are async +5. **Database Indexes**: Configured in EntityConfigurations +6. **Cache-Aside Pattern**: Reduce database load for frequent reads ## References diff --git a/services/iam-service-net/docs/vi/ARCHITECTURE.md b/services/iam-service-net/docs/vi/ARCHITECTURE.md index 9e04eee9..5e40fc2d 100644 --- a/services/iam-service-net/docs/vi/ARCHITECTURE.md +++ b/services/iam-service-net/docs/vi/ARCHITECTURE.md @@ -367,12 +367,163 @@ Tất cả lỗi trả về định dạng Problem Details: } ``` +## Kiến Trúc Distributed Caching + +### Tổng Quan Caching + +```mermaid +graph TB + subgraph "Application" + SVC[Services] + CACHE[ICacheService] + end + + subgraph "Tầng Caching" + REDIS[(Redis Server)] + TOKEN[Token Cache] + SESSION[Session Cache] + DATA[Data Cache] + end + + SVC --> CACHE + CACHE --> REDIS + REDIS --> TOKEN + REDIS --> SESSION + REDIS --> DATA + + style CACHE fill:#e74c3c,stroke:#c0392b,color:#fff + style REDIS fill:#d35400,stroke:#a04000,color:#fff + style TOKEN fill:#9b59b6,stroke:#7d3c98,color:#fff + style SESSION fill:#3498db,stroke:#2980b9,color:#fff + style DATA fill:#2ecc71,stroke:#27ae60,color:#fff +``` + +### ICacheService Interface + +Service implement interface `ICacheService` cho distributed caching: + +| Method | Mục Đích | +|--------|----------| +| `GetAsync` | Lấy item từ cache theo key | +| `SetAsync` | Lưu item với TTL tùy chọn | +| `RemoveAsync` | Xóa item từ cache | +| `ExistsAsync` | Kiểm tra key tồn tại | +| `GetOrSetAsync` | Pattern cache-aside | +| `BlacklistAsync` | Thêm vào blacklist token | +| `IsBlacklistedAsync` | Kiểm tra blacklist token | + +### Chiến Lược Token Caching + +```mermaid +sequenceDiagram + participant Client + participant AuthController + participant CacheService + participant Redis + participant Database + + Note over Client,Database: Validate Token với Cache + + Client->>AuthController: Request với JWT + AuthController->>CacheService: IsBlacklistedAsync(tokenId) + CacheService->>Redis: GET blacklist:token:{id} + Redis-->>CacheService: null (không bị blacklist) + CacheService-->>AuthController: false + AuthController->>AuthController: Validate JWT Claims + AuthController-->>Client: Response + + Note over Client,Database: Thu Hồi Token (Logout) + + Client->>AuthController: POST /logout + AuthController->>CacheService: BlacklistAsync(tokenId, 7 ngày) + CacheService->>Redis: SETEX blacklist:token:{id} 604800 "1" + Redis-->>CacheService: OK + AuthController-->>Client: 200 OK +``` + +### Token Cache Keys + +| Mẫu Key | Mục Đích | TTL | +|---------|----------|-----| +| `blacklist:token:{tokenId}` | Tokens đã thu hồi | Thời gian còn lại của token | +| `blacklist:refresh:{tokenId}` | Refresh tokens đã thu hồi | 7 ngày | +| `user:{userId}:tokens` | Tokens đang hoạt động của user | 15 phút | + +### Chiến Lược Session Caching + +```mermaid +graph LR + subgraph "Session Data" + UID[User ID] + ROLES[User Roles] + PERMS[Permissions] + CLAIMS[Claims] + end + + subgraph "Cache Keys" + K1[session:{userId}] + K2[user:{userId}:roles] + K3[user:{userId}:permissions] + end + + UID --> K1 + ROLES --> K2 + PERMS --> K3 + + style K1 fill:#3498db,stroke:#2980b9,color:#fff + style K2 fill:#9b59b6,stroke:#7d3c98,color:#fff + style K3 fill:#2ecc71,stroke:#27ae60,color:#fff +``` + +### Session Cache Keys + +| Mẫu Key | Mục Đích | TTL | +|---------|----------|-----| +| `session:{userId}` | Dữ liệu session user | 30 phút | +| `user:{userId}:roles` | Cached user roles | 15 phút | +| `user:{userId}:permissions` | Computed permissions | 15 phút | +| `user:{userId}:profile` | Dữ liệu profile user | 10 phút | + +### Pattern Cache-Aside + +```mermaid +sequenceDiagram + participant Service + participant CacheService + participant Redis + participant Database + + Service->>CacheService: GetOrSetAsync(key, factory) + CacheService->>Redis: GET key + + alt Cache Hit + Redis-->>CacheService: dữ liệu cached + CacheService-->>Service: trả về dữ liệu + else Cache Miss + Redis-->>CacheService: null + CacheService->>Database: factory() - lấy dữ liệu + Database-->>CacheService: dữ liệu + CacheService->>Redis: SETEX key ttl data + CacheService-->>Service: trả về dữ liệu + end +``` + +### Chiến Lược Invalidation Cache + +| Chiến Lược | Khi Nào Sử Dụng | Implementation | +|------------|-----------------|----------------| +| **Time-based (TTL)** | Dữ liệu chung | `SetAsync(..., TimeSpan.FromMinutes(15))` | +| **Event-based** | Cập nhật user | Xóa cache khi có event cập nhật | +| **Pattern-based** | Invalidation hàng loạt | `RemoveByPatternAsync("user:*")` | + ## Cân Nhắc Hiệu Năng 1. **Connection Pooling**: EF Core với Npgsql resilience -2. **Token Caching**: Redis cho token validation -3. **Async Operations**: Tất cả I/O operations đều async -4. **Database Indexes**: Cấu hình trong EntityConfigurations +2. **Token Caching**: Redis cho token validation và blacklist +3. **Session Caching**: User sessions và permissions được cache +4. **Async Operations**: Tất cả I/O operations đều async +5. **Database Indexes**: Cấu hình trong EntityConfigurations +6. **Cache-Aside Pattern**: Giảm tải database cho các truy vấn thường xuyên ## Tài Liệu Tham Khảo diff --git a/services/iam-service-net/docs/vi/README.md b/services/iam-service-net/docs/vi/README.md index 43deacb4..94f2fdc1 100644 --- a/services/iam-service-net/docs/vi/README.md +++ b/services/iam-service-net/docs/vi/README.md @@ -228,6 +228,108 @@ Sau khi chạy service, truy cập Swagger UI tại: | `ASPNETCORE_ENVIRONMENT` | Môi trường | `Development` | | `DATABASE_URL` | PostgreSQL connection | - | | `JWT_SECRET` | Secret ký JWT (32+ ký tự) | - | +| `REDIS_HOST` | Redis server host | `localhost` | +| `REDIS_PORT` | Redis server port | `6379` | +| `REDIS_PASSWORD` | Redis password | - | +| `REDIS_DATABASE` | Redis database number | `0` | + +## Redis Caching + +Service sử dụng Redis cho distributed caching thông qua interface `ICacheService`. + +### Cấu Hình Redis + +Thêm cấu hình Redis trong `appsettings.json`: + +```json +{ + "Redis": { + "Host": "localhost", + "Port": 6379, + "Password": "", + "Database": 0, + "ConnectTimeout": 5000, + "SyncTimeout": 5000 + } +} +``` + +Hoặc sử dụng biến môi trường: + +```bash +REDIS_HOST=your-redis-host +REDIS_PORT=6379 +REDIS_PASSWORD=your-password +REDIS_DATABASE=0 +``` + +### ICacheService Interface + +```csharp +public interface ICacheService +{ + // Các thao tác cơ bản + Task GetAsync(string key); + Task SetAsync(string key, T value, TimeSpan? expiration = null); + Task RemoveAsync(string key); + Task ExistsAsync(string key); + + // Get hoặc tạo mới pattern + Task GetOrSetAsync(string key, Func> factory, TimeSpan? expiration = null); + + // Hỗ trợ blacklist token + Task BlacklistAsync(string key, TimeSpan expiration); + Task IsBlacklistedAsync(string key); +} +``` + +### Ví Dụ Sử Dụng + +**Get/Set cơ bản:** +```csharp +public class MyService +{ + private readonly ICacheService _cache; + + public MyService(ICacheService cache) => _cache = cache; + + public async Task GetUser(string userId) + { + return await _cache.GetAsync($"user:{userId}"); + } + + public async Task CacheUser(User user) + { + await _cache.SetAsync($"user:{user.Id}", user, TimeSpan.FromMinutes(15)); + } +} +``` + +**Get or Set Pattern (Cache-Aside):** +```csharp +public async Task GetUserById(string userId) +{ + return await _cache.GetOrSetAsync( + $"user:{userId}", + async () => await _repository.GetByIdAsync(userId), + TimeSpan.FromMinutes(15) + ); +} +``` + +**Blacklist Token (cho Logout):** +```csharp +public async Task Logout(string tokenId) +{ + // Blacklist refresh token trong thời gian còn lại của token + await _cache.BlacklistAsync($"token:{tokenId}", TimeSpan.FromDays(7)); +} + +public async Task IsTokenRevoked(string tokenId) +{ + return await _cache.IsBlacklistedAsync($"token:{tokenId}"); +} +``` ## Kiểm Thử