|
1 | 1 | # Multi-Exporter Architecture Design |
2 | 2 |
|
3 | | -**Document Status:** Phase 1 Complete ✅ |
| 3 | +**Document Status:** Phase 2 Complete ✅ |
4 | 4 | **Created:** 2025-10-30 |
5 | | -**Implemented:** 2025-10-30 |
6 | | -**Target Version:** v2.1.0+ |
| 5 | +**Phase 1 Implemented:** 2025-10-30 |
| 6 | +**Phase 2 Implemented:** 2025-10-30 |
| 7 | +**Target Version:** v2.2.0+ |
7 | 8 |
|
8 | 9 | ## Executive Summary |
9 | 10 |
|
@@ -38,12 +39,136 @@ Each exporter is a top-level key with an array of metric snapshots. This allows: |
38 | 39 | - Easy extensibility (add new exporters without schema changes) |
39 | 40 |
|
40 | 41 | **Phased Approach:** |
41 | | -- **Phase 1**: Plugin architecture with exporter registry ✅ **COMPLETE** |
42 | | -- **Phase 2**: Independent scrape loops + smart batching (true scalability, ~5-7 days) |
| 42 | +- **Phase 1**: Plugin architecture with exporter registry ✅ **COMPLETE** (2025-10-30) |
| 43 | +- **Phase 2**: Independent scrape loops + smart batching ✅ **COMPLETE** (2025-10-30) |
43 | 44 | - **Phase 3**: Auto-discovery and advanced features (optional, ~3-5 days) |
44 | 45 |
|
45 | 46 | --- |
46 | 47 |
|
| 48 | +## Implementation Status - Phase 2 Complete ✅ |
| 49 | + |
| 50 | +**Completed:** 2025-10-30 |
| 51 | + |
| 52 | +### What Was Implemented in Phase 2 |
| 53 | + |
| 54 | +#### 1. Per-Exporter Intervals |
| 55 | +- ✅ Updated `ExporterConfig` to support optional `interval` field (string) |
| 56 | +- ✅ Added `ParsedInterval` computed field to store parsed time.Duration |
| 57 | +- ✅ `agent.interval` now serves as default for exporters without explicit interval |
| 58 | +- ✅ Validation supports: 15s, 30s, 1m, 5m intervals |
| 59 | + |
| 60 | +#### 2. Independent Scraper Goroutines |
| 61 | +- ✅ Each exporter runs in its own goroutine with independent ticker |
| 62 | +- ✅ Implemented `runScraperLoop()` - per-exporter scrape loop |
| 63 | +- ✅ Implemented `scrapeAndBuffer()` - single scrape operation |
| 64 | +- ✅ Parallel scraping - no blocking between exporters |
| 65 | +- ✅ Graceful shutdown with `sync.WaitGroup` |
| 66 | + |
| 67 | +#### 3. Smart Batching by Time Windows |
| 68 | +- ✅ Implemented `groupFilesByTimeWindow()` - groups files into 5s buckets |
| 69 | +- ✅ Implemented `parseTimestampFromFilename()` - extracts timestamp from filename |
| 70 | +- ✅ Drain loop processes oldest time window first |
| 71 | +- ✅ Multiple exporters scraped at similar times batched into single HTTP request |
| 72 | + |
| 73 | +#### 4. Configuration Changes |
| 74 | +**agent.interval:** |
| 75 | +- Still required (serves as default for exporters) |
| 76 | +- Falls back when exporter doesn't specify interval |
| 77 | + |
| 78 | +**exporters[].interval:** |
| 79 | +- Optional per-exporter interval |
| 80 | +- Validates against allowed values: 15s, 30s, 1m, 5m |
| 81 | +- Falls back to `agent.interval` if not specified |
| 82 | + |
| 83 | +### Example Phase 2 Configuration |
| 84 | + |
| 85 | +```yaml |
| 86 | +server: |
| 87 | + endpoint: "https://dashboard.nodepulse.io/metrics/prometheus" |
| 88 | + timeout: 5s |
| 89 | + |
| 90 | +agent: |
| 91 | + server_id: "550e8400-e29b-41d4-a716-446655440000" |
| 92 | + interval: 15s # Default interval for exporters without explicit interval |
| 93 | + |
| 94 | +exporters: |
| 95 | + - name: node_exporter |
| 96 | + enabled: true |
| 97 | + endpoint: "http://localhost:9100/metrics" |
| 98 | + interval: 15s # Fast scraping for system metrics |
| 99 | + timeout: 3s |
| 100 | + |
| 101 | + - name: postgres_exporter |
| 102 | + enabled: true |
| 103 | + endpoint: "http://localhost:9187/metrics" |
| 104 | + interval: 30s # Slower scraping for database metrics |
| 105 | + timeout: 5s |
| 106 | + |
| 107 | + - name: backup_monitor |
| 108 | + enabled: true |
| 109 | + endpoint: "http://localhost:8080/metrics" |
| 110 | + interval: 5m # Very slow scraping for backup status |
| 111 | + timeout: 10s |
| 112 | + |
| 113 | +buffer: |
| 114 | + path: "/var/lib/nodepulse/buffer" |
| 115 | + retention_hours: 48 |
| 116 | + batch_size: 10 # Increased for Phase 2 efficiency |
| 117 | +``` |
| 118 | +
|
| 119 | +### Key Features Delivered |
| 120 | +
|
| 121 | +✅ **True Parallelism** - Each exporter runs independently |
| 122 | +✅ **Per-Exporter Intervals** - Different scrape rates (15s, 30s, 1m, 5m) |
| 123 | +✅ **No Blocking** - Slow exporters don't delay fast ones |
| 124 | +✅ **Smart Batching** - Time-window grouping reduces HTTP requests |
| 125 | +✅ **Graceful Shutdown** - WaitGroup ensures clean exit |
| 126 | +✅ **Backward Compatible** - Phase 1 configs work (all use default interval) |
| 127 | +
|
| 128 | +### Behavioral Changes from Phase 1 |
| 129 | +
|
| 130 | +**Phase 1 (Sequential):** |
| 131 | +``` |
| 132 | +14:00:00 - Scrape all exporters sequentially (blocking) |
| 133 | +14:00:15 - Scrape all exporters sequentially |
| 134 | +14:00:30 - Scrape all exporters sequentially |
| 135 | +``` |
| 136 | + |
| 137 | +**Phase 2 (Independent):** |
| 138 | +``` |
| 139 | +14:00:00 - node_exporter scrapes |
| 140 | +14:00:00 - postgres_exporter scrapes |
| 141 | +14:00:00 - backup_monitor scrapes |
| 142 | +14:00:15 - node_exporter scrapes |
| 143 | +14:00:30 - node_exporter scrapes |
| 144 | +14:00:30 - postgres_exporter scrapes (30s interval) |
| 145 | +14:05:00 - backup_monitor scrapes (5m interval) |
| 146 | +``` |
| 147 | + |
| 148 | +### Files Modified in Phase 2 |
| 149 | + |
| 150 | +1. `internal/config/config.go` - Added per-exporter interval support |
| 151 | +2. `cmd/start.go` - Replaced single loop with independent goroutines |
| 152 | +3. `internal/report/sender.go` - Added time-window batching |
| 153 | + |
| 154 | +### Performance Improvements |
| 155 | + |
| 156 | +**Without Phase 2 (3 exporters at 15s interval):** |
| 157 | +- node_exporter: 0.5s scrape |
| 158 | +- postgres_exporter: 3s scrape (slow database query) |
| 159 | +- backup_monitor: 2s scrape |
| 160 | +- **Total time per cycle: 5.5s** (sequential blocking) |
| 161 | + |
| 162 | +**With Phase 2 (independent intervals):** |
| 163 | +- node_exporter: 15s interval, 0.5s scrape (parallel) |
| 164 | +- postgres_exporter: 30s interval, 3s scrape (parallel) |
| 165 | +- backup_monitor: 5m interval, 2s scrape (parallel) |
| 166 | +- **Max scrape time: 3s** (longest individual scrape, no blocking) |
| 167 | +- **50% fewer postgres scrapes** (30s vs 15s) |
| 168 | +- **95% fewer backup scrapes** (5m vs 15s) |
| 169 | + |
| 170 | +--- |
| 171 | + |
47 | 172 | ## Implementation Status - Phase 1 Complete ✅ |
48 | 173 |
|
49 | 174 | **Completed:** 2025-10-30 |
@@ -1682,18 +1807,18 @@ Expected output: |
1682 | 1807 | - ⏭️ Write unit tests for exporter interface (TODO) |
1683 | 1808 | - ⏭️ Write integration tests for multi-exporter buffering (TODO) |
1684 | 1809 |
|
1685 | | -### Phase 2: Independent Scrape Loops |
1686 | | - |
1687 | | -- [ ] Update `cmd/start.go` (launch goroutines per exporter) |
1688 | | -- [ ] Implement `runScraperLoop()` function |
1689 | | -- [ ] Implement `groupFilesByTimeWindow()` in sender |
1690 | | -- [ ] Implement `sendBatchedMetrics()` for batch payloads |
1691 | | -- [ ] Update dashboard API to accept batched metrics |
1692 | | -- [ ] Add per-exporter interval validation |
1693 | | -- [ ] Add WaitGroup for graceful shutdown |
1694 | | -- [ ] Write tests for concurrent scraping |
1695 | | -- [ ] Write tests for time-window batching |
1696 | | -- [ ] Performance testing with 10+ exporters |
| 1810 | +### Phase 2: Independent Scrape Loops ✅ COMPLETE |
| 1811 | + |
| 1812 | +- ✅ Update `cmd/start.go` (launch goroutines per exporter) |
| 1813 | +- ✅ Implement `runScraperLoop()` function |
| 1814 | +- ✅ Implement `groupFilesByTimeWindow()` in sender |
| 1815 | +- ✅ Implement `parseTimestampFromFilename()` helper |
| 1816 | +- ✅ Dashboard already supports batched metrics (Phase 1 payload format) |
| 1817 | +- ✅ Add per-exporter interval validation |
| 1818 | +- ✅ Add WaitGroup for graceful shutdown |
| 1819 | +- ⏭️ Write tests for concurrent scraping (TODO) |
| 1820 | +- ⏭️ Write tests for time-window batching (TODO) |
| 1821 | +- ⏭️ Performance testing with 10+ exporters (TODO) |
1697 | 1822 |
|
1698 | 1823 | ### Phase 3: Advanced Features (Optional) |
1699 | 1824 |
|
|
0 commit comments