- Enhanced the architecture documentation to recommend direct upload over legacy proxy upload for improved performance and scalability. - Added detailed comparisons of upload patterns, including throughput, memory usage, and latency. - Updated API endpoint documentation to reflect new direct upload methods and their benefits. - Included examples for direct upload flow and bucket directory structure to aid developers in implementation.
394 lines
12 KiB
Markdown
394 lines
12 KiB
Markdown
# Kiến Trúc Storage Service
|
|
|
|
> Tài liệu kiến trúc chi tiết cho microservice Storage Service.
|
|
|
|
## Tổng Quan Kiến Trúc
|
|
|
|
```mermaid
|
|
graph TB
|
|
subgraph "API Layer"
|
|
C[Controllers]
|
|
CMD[Commands]
|
|
Q[Queries]
|
|
B[Behaviors]
|
|
end
|
|
|
|
subgraph "Domain Layer"
|
|
SF[StorageFile]
|
|
SQ[UserStorageQuota]
|
|
DE[Domain Events]
|
|
RI[Repository Interfaces]
|
|
end
|
|
|
|
subgraph "Infrastructure Layer"
|
|
SP[Storage Providers]
|
|
IAM[IAM Client]
|
|
R[Repositories]
|
|
CTX[DbContext]
|
|
end
|
|
|
|
subgraph "External Services"
|
|
MINIO[(MinIO)]
|
|
OSS[(Aliyun OSS)]
|
|
IAMS[IAM Service]
|
|
DB[(PostgreSQL)]
|
|
end
|
|
|
|
C --> CMD
|
|
C --> Q
|
|
CMD --> B --> SF
|
|
Q --> R
|
|
R --> CTX --> DB
|
|
SF --> DE
|
|
|
|
CMD --> SP
|
|
SP --> MINIO
|
|
SP --> OSS
|
|
|
|
C --> IAM --> IAMS
|
|
|
|
style C fill:#4a90d9,stroke:#2d5986,color:#fff
|
|
style SF fill:#50c878,stroke:#2d8659,color:#fff
|
|
style MINIO fill:#c73b3b,stroke:#922b2b,color:#fff
|
|
style OSS fill:#ff6b35,stroke:#cc5500,color:#fff
|
|
style IAMS fill:#9b59b6,stroke:#7d3c98,color:#fff
|
|
```
|
|
|
|
## Trách Nhiệm Từng Layer
|
|
|
|
### 1. Domain Layer (StorageService.Domain)
|
|
|
|
Trái tim của ứng dụng chứa business logic thuần túy.
|
|
|
|
| Component | Mục đích |
|
|
|-----------|----------|
|
|
| **StorageFile** | Aggregate root cho metadata file và lifecycle |
|
|
| **UserStorageQuota** | Aggregate root cho giới hạn và usage storage của user |
|
|
| **StorageProvider** | Enum: MinIO, AliyunOSS |
|
|
| **FileAccessLevel** | Enum: Private, Public, Shared |
|
|
| **Domain Events** | FileUploadedDomainEvent, FileDeletedDomainEvent, UserQuotaUpdatedDomainEvent |
|
|
|
|
### 2. Infrastructure Layer (StorageService.Infrastructure)
|
|
|
|
Triển khai kỹ thuật và tích hợp bên ngoài:
|
|
|
|
| Component | Mục đích |
|
|
|-----------|----------|
|
|
| **MinioStorageProvider** | Thao tác storage tương thích MinIO S3 |
|
|
| **AliyunOssStorageProvider** | Thao tác Alibaba Cloud OSS |
|
|
| **StorageProviderFactory** | Chọn provider runtime dựa trên config |
|
|
| **HttpIamServiceClient** | Giao tiếp inter-service với IAM |
|
|
| **FileRepository** | EF Core repository cho StorageFile |
|
|
| **QuotaRepository** | EF Core repository cho UserStorageQuota |
|
|
|
|
### 3. API Layer (StorageService.API)
|
|
|
|
Entry point ứng dụng và triển khai CQRS:
|
|
|
|
| Component | Mục đích |
|
|
|-----------|----------|
|
|
| **FilesController** | Endpoints CRUD file (proxy upload cũ) |
|
|
| **SignedUrlController** | Endpoints direct upload (khuyến nghị) |
|
|
| **QuotaController** | Endpoints quota của user |
|
|
| **SignUploadCommand** | Tạo pre-signed upload URLs |
|
|
| **ConfirmUploadCommand** | Xác nhận direct uploads và lưu metadata |
|
|
| **UploadFileCommand** | Xử lý proxy uploads (cũ) |
|
|
| **DeleteFileCommand** | Xử lý xóa file |
|
|
| **Query Handlers** | Xử lý các thao tác đọc |
|
|
|
|
## Kiến Trúc Direct Upload (Khuyến Nghị)
|
|
|
|
Cho hệ thống với hàng triệu users, pattern Direct Client Upload được khuyến nghị thay vì proxy upload.
|
|
|
|
### So Sánh Upload Patterns
|
|
|
|
| Khía cạnh | Proxy Upload (Cũ) | Direct Upload (Khuyến nghị) |
|
|
|-----------|------------------|----------------------------|
|
|
| **Throughput** | ~100-500/giây | ~10,000+/giây |
|
|
| **Memory mỗi request** | 100MB (kích thước file) | ~10KB (chỉ metadata) |
|
|
| **Latency (file 100MB)** | 30-60 giây | 10-20 giây |
|
|
| **Tải backend** | Cao | Tối thiểu |
|
|
|
|
### Luồng Direct Upload
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant Storage_Service as Storage Service
|
|
participant MinIO
|
|
|
|
rect rgb(200, 230, 200)
|
|
Note over Client,Storage_Service: 1. Yêu cầu Upload URL (nhẹ)
|
|
Client->>Storage_Service: POST /api/v1/storage/sign-upload
|
|
Storage_Service->>Storage_Service: Validate JWT, Kiểm tra Quota
|
|
Storage_Service-->>Client: Pre-signed PUT URL + ObjectKey
|
|
end
|
|
|
|
rect rgb(200, 200, 230)
|
|
Note over Client,MinIO: 2. Upload trực tiếp (bỏ qua backend)
|
|
Client->>MinIO: PUT file binary vào Pre-signed URL
|
|
MinIO-->>Client: 200 OK
|
|
end
|
|
|
|
rect rgb(230, 230, 200)
|
|
Note over Client,Storage_Service: 3. Xác nhận Upload (nhẹ)
|
|
Client->>Storage_Service: POST /api/v1/storage/confirm-upload
|
|
Storage_Service->>MinIO: Xác minh file tồn tại
|
|
Storage_Service->>Storage_Service: Lưu metadata, Cập nhật quota
|
|
Storage_Service-->>Client: File metadata
|
|
end
|
|
```
|
|
|
|
### Kiểm Soát Truy Cập Theo Path
|
|
|
|
Files được tổ chức với prefix theo access level:
|
|
|
|
```
|
|
storage-bucket/
|
|
├── public/{userId}/{date}/{fileId}_{filename} → Truy cập công khai
|
|
├── private/{userId}/{date}/{fileId}_{filename} → Yêu cầu pre-signed URL
|
|
└── shared/{userId}/{date}/{fileId}_{filename} → Kiểm soát bằng quy tắc
|
|
```
|
|
|
|
### Components Direct Upload
|
|
|
|
| Component | Mục đích |
|
|
|-----------|----------|
|
|
| **SignUploadCommand** | Validate quota, tạo object key với path prefix, tạo pre-signed PUT URL |
|
|
| **SignUploadCommandHandler** | Xử lý yêu cầu sign-upload |
|
|
| **ConfirmUploadCommand** | Xác minh file tồn tại, lưu metadata, cập nhật quota |
|
|
| **ConfirmUploadCommandHandler** | Xử lý confirm-upload với idempotency |
|
|
| **SignedUrlController** | Endpoints `/sign-upload` và `/confirm-upload` |
|
|
|
|
|
|
## Kiến Trúc Storage Provider
|
|
|
|
```mermaid
|
|
graph TD
|
|
subgraph "Storage Provider Factory"
|
|
F[StorageProviderFactory]
|
|
C[Configuration]
|
|
end
|
|
|
|
subgraph "Providers"
|
|
MP[MinioStorageProvider]
|
|
AP[AliyunOssStorageProvider]
|
|
end
|
|
|
|
subgraph "Storage Backends"
|
|
MINIO[(MinIO)]
|
|
OSS[(Aliyun OSS)]
|
|
end
|
|
|
|
C --> |STORAGE_PROVIDER=minio| F
|
|
C --> |STORAGE_PROVIDER=aliyun| F
|
|
F --> |GetProvider| MP
|
|
F --> |GetProvider| AP
|
|
MP --> MINIO
|
|
AP --> OSS
|
|
|
|
style F fill:#4a90d9,stroke:#2d5986,color:#fff
|
|
style MP fill:#c73b3b,stroke:#922b2b,color:#fff
|
|
style AP fill:#ff6b35,stroke:#cc5500,color:#fff
|
|
```
|
|
|
|
### Interface Storage Provider
|
|
|
|
```csharp
|
|
public interface IStorageProvider
|
|
{
|
|
Task<UploadResult> UploadAsync(Stream stream, string objectKey, ...);
|
|
Task<Stream> DownloadAsync(string bucketName, string objectKey);
|
|
Task DeleteAsync(string bucketName, string objectKey);
|
|
Task<bool> ExistsAsync(string bucketName, string objectKey);
|
|
Task<string> GetPreSignedDownloadUrlAsync(string bucketName, string objectKey, int expirationSeconds);
|
|
Task<string> GetPreSignedUploadUrlAsync(string bucketName, string objectKey, int expirationSeconds);
|
|
}
|
|
```
|
|
|
|
## Giao Tiếp Inter-Service
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
participant Client
|
|
participant Storage as Storage Service
|
|
participant Cache as In-Memory Cache
|
|
participant IAM as IAM Service
|
|
|
|
Client->>Storage: Upload File (JWT)
|
|
Storage->>Cache: Kiểm tra cache user
|
|
alt Cache Hit
|
|
Cache-->>Storage: Thông tin user
|
|
else Cache Miss
|
|
Storage->>IAM: GET /api/v1/users/me
|
|
Note over Storage,IAM: Headers: Authorization, X-Service-Name
|
|
IAM-->>Storage: Thông tin user
|
|
Storage->>Cache: Lưu (5 phút TTL)
|
|
end
|
|
Storage->>Storage: Validate quota
|
|
Storage->>Storage: Upload lên provider
|
|
Storage-->>Client: Kết quả upload
|
|
```
|
|
|
|
### Tính Năng IAM Client
|
|
|
|
| Tính năng | Mô tả |
|
|
|-----------|-------|
|
|
| **Caching** | In-memory cache cho user info (5 phút TTL) |
|
|
| **Health Check** | Kiểm tra IAM availability với caching (1 phút TTL) |
|
|
| **Polly Resilience** | Retry (3x exponential) + Circuit Breaker |
|
|
| **Permission Check** | HasPermissionAsync, HasRoleAsync |
|
|
|
|
### Các Phương Thức IAM Client
|
|
|
|
```csharp
|
|
// Thao tác User
|
|
Task<IamUserInfo?> ValidateUserAsync(string accessToken);
|
|
Task<IamUserInfo?> GetUserByIdAsync(string userId, string accessToken);
|
|
Task<bool> UserExistsAsync(string userId, string accessToken);
|
|
Task<IReadOnlyList<string>> GetUserRolesAsync(string userId, string accessToken);
|
|
Task<IReadOnlyList<string>> GetUserPermissionsAsync(string userId, string accessToken);
|
|
Task<bool> HasPermissionAsync(string userId, string permission, string accessToken);
|
|
Task<bool> HasRoleAsync(string userId, string role, string accessToken);
|
|
|
|
// Health Check
|
|
Task<IamHealthStatus> CheckHealthAsync();
|
|
Task<bool> IsAvailableAsync();
|
|
|
|
// Quản lý Cache
|
|
void InvalidateUserCache(string userId);
|
|
void ClearCache();
|
|
```
|
|
|
|
## Database Schema
|
|
|
|
```mermaid
|
|
erDiagram
|
|
storage_files {
|
|
uuid id PK
|
|
varchar file_name
|
|
varchar bucket_name
|
|
varchar object_key
|
|
varchar content_type
|
|
bigint file_size_bytes
|
|
varchar user_id
|
|
varchar tenant_id
|
|
int provider
|
|
int access_level
|
|
timestamp uploaded_at
|
|
timestamp expires_at
|
|
varchar checksum
|
|
boolean is_deleted
|
|
timestamp deleted_at
|
|
}
|
|
|
|
user_storage_quotas {
|
|
uuid id PK
|
|
varchar user_id UK
|
|
bigint max_storage_bytes
|
|
bigint used_storage_bytes
|
|
int max_file_count
|
|
int current_file_count
|
|
varchar quota_tier
|
|
timestamp last_updated_at
|
|
timestamp created_at
|
|
}
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### Files (Proxy Upload Cũ)
|
|
|
|
| Method | Endpoint | Mô tả |
|
|
|--------|----------|-------|
|
|
| `POST` | `/api/v1/files/upload` | Upload file qua backend (tối đa 100MB) |
|
|
| `GET` | `/api/v1/files` | Danh sách file với phân trang |
|
|
| `GET` | `/api/v1/files/{id}` | Lấy metadata file |
|
|
| `GET` | `/api/v1/files/{id}/download-url` | Lấy pre-signed download URL |
|
|
| `DELETE` | `/api/v1/files/{id}` | Xóa file (soft delete) |
|
|
|
|
### Direct Upload (Khuyến Nghị)
|
|
|
|
| Method | Endpoint | Mô tả |
|
|
|--------|----------|-------|
|
|
| `POST` | `/api/v1/storage/sign-upload` | Lấy pre-signed PUT URL để upload trực tiếp |
|
|
| `POST` | `/api/v1/storage/confirm-upload` | Xác nhận upload và lưu metadata |
|
|
|
|
### Quota
|
|
|
|
| Method | Endpoint | Mô tả |
|
|
|--------|----------|-------|
|
|
| `GET` | `/api/v1/quota` | Lấy quota storage của user |
|
|
|
|
|
|
## Health Checks
|
|
|
|
```mermaid
|
|
graph TD
|
|
HC[Health Check Endpoint]
|
|
HC --> |/health/live| L[Liveness]
|
|
HC --> |/health/ready| R[Readiness]
|
|
|
|
R --> DB[(PostgreSQL)]
|
|
R --> MINIO[(MinIO)]
|
|
R --> IAM[IAM Service]
|
|
|
|
style HC fill:#3498db,stroke:#2980b9,color:#fff
|
|
style L fill:#2ecc71,stroke:#27ae60,color:#fff
|
|
style R fill:#f39c12,stroke:#d68910,color:#fff
|
|
```
|
|
|
|
## Kiến Trúc Deployment
|
|
|
|
### Docker Compose (Local)
|
|
|
|
```yaml
|
|
services:
|
|
storage-api:
|
|
build: .
|
|
ports: ["5002:8080"]
|
|
depends_on:
|
|
- postgres
|
|
- redis
|
|
- minio
|
|
environment:
|
|
- Storage__Provider=minio
|
|
- Storage__MinIO__Endpoint=minio:9000
|
|
|
|
minio:
|
|
image: minio/minio:latest
|
|
ports: ["9000:9000", "9001:9001"]
|
|
```
|
|
|
|
### Tích Hợp Traefik
|
|
|
|
```yaml
|
|
labels:
|
|
- "traefik.enable=true"
|
|
- "traefik.http.routers.storage-service.rule=PathPrefix(`/api/v1/files`) || PathPrefix(`/api/v1/quota`)"
|
|
- "traefik.http.services.storage-service.loadbalancer.server.port=8080"
|
|
```
|
|
|
|
## Cân Nhắc Bảo Mật
|
|
|
|
1. **Authentication**: Xác thực JWT Bearer qua IAM Service
|
|
2. **Authorization**: Kiểm tra quyền sở hữu trên files
|
|
3. **Input Validation**: Giới hạn kích thước file, xác thực content type
|
|
4. **Pre-signed URLs**: Truy cập file có thời hạn
|
|
5. **Soft Delete**: Files được đánh dấu xóa, không xóa ngay lập tức
|
|
|
|
## Tối Ưu Hiệu Suất
|
|
|
|
1. **Caching**: In-memory cache cho IAM user info
|
|
2. **Pre-signed URLs**: Client download trực tiếp từ storage
|
|
3. **Streaming Upload**: Xử lý file dựa trên stream
|
|
4. **Async Operations**: Tất cả thao tác I/O đều async
|
|
5. **Connection Pooling**: HTTP client với Polly policies
|
|
|
|
## Tài Liệu Tham Khảo
|
|
|
|
- [MinIO Documentation](https://min.io/docs/minio/)
|
|
- [Aliyun OSS Documentation](https://www.alibabacloud.com/help/oss)
|
|
- [Polly Resilience](https://github.com/App-vNext/Polly)
|
|
- [Clean Architecture](https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html)
|