chore: adds documentation around the dual writer (#108687)

* chore: adds documentation around the dual writer

Signed-off-by: Bruno Abrantes <bruno@brunoabrantes.com>

* fix: innacuracies in error returned, disambiguate (validation) and move table upwards for more clarity

Signed-off-by: Bruno Abrantes <bruno@brunoabrantes.com>

---------

Signed-off-by: Bruno Abrantes <bruno@brunoabrantes.com>
This commit is contained in:
Bruno Abrantes
2025-07-28 15:50:26 +02:00
committed by GitHub
parent f7523f03bc
commit 3a54c3abae
+312
View File
@@ -469,3 +469,315 @@ For debugging purposes, you can view the memberlist status by visitting `http://
that every instance you create is part of the memberlist.
You can also visit `http://127.0.0.1:3000/ring` to view the ring status and the storage-api servers that are part of the
ring.
---
## Dual Writer System
The Dual Writer system is a critical component of Unified Storage that manages the transition between legacy storage and unified storage during the migration process. It provides six different modes (0-5) that control how data is read from and written to both storage systems.
### Dual Writer Mode Reference Table
| Mode | Description | Read Source | Read Behavior | Write Targets | Write Behavior | Error Handling | Background Sync |
|------|-------------|-------------|---------------|---------------|----------------|----------------|-----------------|
| **0** | Disabled | Legacy Only | Synchronous | Legacy Only | Synchronous | Legacy errors bubble up | None |
| **1** | Legacy Primary + Best Effort Unified | Legacy Only | Legacy: Sync<br/>Unified: Async (background) | Legacy + Unified | Legacy: Sync<br/>Unified: Async (background) | Only legacy errors bubble up.<br/>Unified errors logged but ignored | Active - syncs legacy → unified |
| **2** | Legacy Primary + Unified Sync | Legacy Only | Legacy: Sync<br/>Unified: Sync (verification read) | Legacy + Unified | Legacy: Sync<br/>Unified: Sync | Legacy errors bubble up first.<br/>Unified errors bubble up (except NotFound which is ignored).<br/>If write succeeds in legacy but fails in unified, unified error bubbles up and legacy is cleaned up | Active - syncs legacy → unified |
| **3** | Unified Primary + Legacy Sync | Unified Primary | Unified: Sync<br/>Legacy: Fallback on NotFound | Legacy + Unified | Legacy: Sync<br/>Unified: Sync | Legacy errors bubble up first.<br/>If legacy succeeds but unified fails, unified error bubbles up and legacy is cleaned up | Prerequisite - only available after sync completes |
| **4** | Unified Only (Post-Sync) | Unified Only | Synchronous | Unified Only | Synchronous | Unified errors bubble up | Prerequisite - only available after sync completes |
| **5** | Unified Only (Force) | Unified Only | Synchronous | Unified Only | Synchronous | Unified errors bubble up | None - bypasses sync requirements |
### Dual Writer Architecture
The dual writer acts as an intermediary layer that sits between the API layer and the storage backends, routing read and write operations based on the configured mode.
```mermaid
graph TB
subgraph "API Layer"
A[REST API Request]
end
subgraph "Dual Writer Layer"
B[Dual Writer]
B --> C{Mode Decision}
end
subgraph "Storage Backends"
D[Legacy Storage<br/>SQL Database]
E[Unified Storage<br/>K8s-style Storage]
end
subgraph "Background Services"
F[Data Syncer<br/>Background Job]
G[Server Lock Service<br/>Distributed Lock]
end
A --> B
C --> D
C --> E
F --> D
F --> E
F --> G
```
### Mode-Specific Data Flow Diagrams
#### Mode 0: Legacy Only (Disabled)
```mermaid
sequenceDiagram
participant API as API Request
participant DW as Dual Writer
participant LS as Legacy Storage
participant US as Unified Storage
Note over DW: Mode 0 - Unified Storage Disabled
API->>DW: Read/Write Request
DW->>LS: Forward Request
LS-->>DW: Response
DW-->>API: Response
Note over US: Not Used
```
#### Mode 1: Legacy Primary + Best Effort Unified
```mermaid
sequenceDiagram
participant API as API Request
participant DW as Dual Writer
participant LS as Legacy Storage
participant US as Unified Storage
participant BG as Background Sync
Note over DW: Mode 1 - Legacy Primary, Unified Best-Effort
%% Read Operations
API->>DW: Read Request
DW->>LS: Read from Legacy
LS-->>DW: Data
DW->>US: Read from Unified (Background)
Note over US: Errors ignored
DW-->>API: Legacy Data
%% Write Operations
API->>DW: Write Request
DW->>LS: Write to Legacy
LS-->>DW: Success/Error
alt Legacy Write Successful
DW->>US: Write to Unified (Background)
Note over US: Errors ignored
DW-->>API: Legacy Result
else Legacy Write Failed
DW-->>API: Legacy Error
end
BG->>LS: Periodic Sync Check
BG->>US: Sync Missing Data
```
#### Mode 2: Legacy Primary + Unified Sync
```mermaid
sequenceDiagram
participant API as API Request
participant DW as Dual Writer
participant LS as Legacy Storage
participant US as Unified Storage
participant BG as Background Sync
Note over DW: Mode 2 - Legacy Primary, Unified Synchronous
%% Read Operations
API->>DW: Read Request
DW->>LS: Read from Legacy
LS-->>DW: Data
DW->>US: Verification Read (Foreground)
Note over US: Verifies unified storage can serve the same object
US-->>DW: Success/Error
alt Verification Read Failed (Non-NotFound)
DW-->>API: Unified Error
else Verification Read Success or NotFound
DW-->>API: Legacy Data
end
%% Write Operations
API->>DW: Write Request
DW->>LS: Write to Legacy
LS-->>DW: Success/Error
alt Legacy Write Successful
DW->>US: Write to Unified (Foreground)
US-->>DW: Success/Error
alt Unified Write Failed
DW->>LS: Cleanup Legacy (Best Effort)
DW-->>API: Unified Error
else Both Writes Successful
DW-->>API: Legacy Result
end
else Legacy Write Failed
DW-->>API: Legacy Error
end
BG->>LS: Periodic Sync Check
BG->>US: Sync Missing Data
```
#### Mode 3: Unified Primary + Legacy Sync
```mermaid
sequenceDiagram
participant API as API Request
participant DW as Dual Writer
participant LS as Legacy Storage
participant US as Unified Storage
Note over DW: Mode 3 - Unified Primary, Legacy Sync
Note over DW: Only activated after background sync succeeds
%% Read Operations
API->>DW: Read Request
DW->>US: Read from Unified
US-->>DW: Data/Error
alt Unified Read NotFound
DW->>LS: Fallback to Legacy
LS-->>DW: Data/Error
DW-->>API: Legacy Result
else Unified Read Success
DW-->>API: Unified Data
end
%% Write Operations
API->>DW: Write Request
DW->>LS: Write to Legacy
LS-->>DW: Success/Error
alt Legacy Write Successful
DW->>US: Write to Unified
US-->>DW: Success/Error
alt Unified Write Failed
DW->>LS: Cleanup Legacy (Best Effort)
DW-->>API: Unified Error
else Both Writes Successful
DW-->>API: Unified Result
end
else Legacy Write Failed
DW-->>API: Legacy Error
end
```
#### Mode 4 & 5: Unified Only
```mermaid
sequenceDiagram
participant API as API Request
participant DW as Dual Writer
participant LS as Legacy Storage
participant US as Unified Storage
Note over DW: Mode 4/5 - Unified Only
Note over DW: Mode 4: After background sync succeeds
Note over DW: Mode 5: Ignores background sync state
API->>DW: Read/Write Request
DW->>US: Forward Request
US-->>DW: Response
DW-->>API: Response
Note over LS: Not Used
```
### Background Sync Behavior
The background sync service runs periodically (default: every hour) and is responsible for:
1. **Data Synchronization**: Ensures legacy and unified storage contain the same data
2. **Mode Progression**: Enables transition from Mode 2 → Mode 3 → Mode 4
3. **Conflict Resolution**: Handles cases where data exists in one storage but not the other
#### Sync Process Flow
```mermaid
flowchart TD
A[Background Sync Trigger] --> B{Current Mode}
B -->|Mode 1/2| C[Acquire Distributed Lock]
B -->|Mode 3+| Z[No Sync Needed]
C --> D[List Legacy Storage Items]
D --> E[List Unified Storage Items]
E --> F[Compare All Items]
F --> G{Item Comparison}
G -->|Missing in Unified| H[Create in Unified]
G -->|Missing in Legacy| I[Delete from Unified]
G -->|Different Content| J[Update Unified with Legacy Version]
G -->|Identical| K[No Action Needed]
H --> L[Track Sync Success]
I --> L
J --> L
K --> L
L --> M{All Items Synced?}
M -->|Yes| N[Mark Sync Complete<br/>Enable Mode Progression]
M -->|No| O[Log Failures<br/>Retry Next Cycle]
N --> P[Release Lock]
O --> P
Z --> P
```
#### Mode Transition Requirements
- **Mode 0 → Mode 1**: Configuration change only
- **Mode 1 → Mode 2**: Configuration change only
- **Mode 2 → Mode 3**: Requires successful background sync completion
- **Mode 3 → Mode 4**: Requires successful background sync completion
- **Mode 4 → Mode 5**: Configuration change only
- **Any Mode → Mode 5**: Configuration change only (bypasses sync requirements)
### Error Handling Strategies
#### Write Operation Error Priority
1. **Legacy Storage Errors**: Always bubble up immediately if legacy write fails
2. **Unified Storage Errors**:
- Mode 1: Logged but ignored
- Mode 2+: Bubble up after legacy cleanup attempt
3. **Cleanup Operations**: Best effort - failures are logged but don't fail the original operation
#### Read Operation Fallback
- **Mode 2**: `NotFound` errors from unified storage are ignored (object may not be synced yet), but other errors bubble up
- **Mode 3**: If unified storage returns `NotFound`, automatically falls back to legacy storage
- **Other Modes**: No fallback - errors bubble up directly
### Configuration
#### Setting Dual Writer Mode
```ini
[unified_storage.{resource}.{kind}.{group}]
dualWriterMode = {0-5}
```
#### Background Sync Configuration
```ini
[unified_storage]
; Enable data sync between legacy and unified storage
enable_data_sync = true
; Sync interval (default: 1 hour)
data_sync_interval = 1h
; Maximum records to sync per run (default: 1000)
data_sync_records_limit = 1000
; Skip data sync requirement for mode transitions
skip_data_sync = false
```
### Monitoring and Observability
The dual writer system provides metrics for monitoring:
- `dual_writer_requests_total`: Counter of requests by mode, operation, and status
- `dual_writer_sync_duration_seconds`: Histogram of background sync duration
- `dual_writer_sync_success_total`: Counter of successful sync operations
- `dual_writer_mode_transitions_total`: Counter of mode transitions
Use these metrics to monitor the health of your migration and identify any issues with the dual writer system.