Skip to main content

microscope_memory/
architecture_simulator.rs

1//! Architecture Simulator — valós idejű architektúra szimuláció és stressztesztelés.
2//!
3//! Ez a modul képes a memóriában tárolt architektúrák (szoftver, hardver, hálózati)
4//! valós idejű szimulációjára, stressztesztelésére és teljesítményértékelésére.
5//! A szimulációs eredmények visszakerülnek a kognitív memóriába, hogy a rendszer
6//! tanulhasson belőlük.
7
8use std::collections::HashMap;
9use std::sync::{Arc, RwLock};
10use std::time::Instant;
11
12// ─── Alap típusok ───────────────────────────────────────────────────────────
13
14/// Egy architektúra komponens típusa
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16pub enum ComponentType {
17    /// Szoftver komponens (mikroszolgáltatás, modul, library)
18    Software,
19    /// Hardver komponens (CPU, GPU, memória, hálózati eszköz)
20    Hardware,
21    /// Hálózati protokoll vagy kapcsolat
22    Network,
23    /// Adattároló (adatbázis, cache, fájlrendszer)
24    Storage,
25    /// Egyéb
26    Custom(String),
27}
28
29/// Egy architektúra komponens
30#[derive(Debug, Clone)]
31pub struct Component {
32    pub id: String,
33    pub name: String,
34    pub component_type: ComponentType,
35    /// Kapacitás paraméterek (pl. "cpu_cores": 8, "memory_mb": 16384)
36    pub capacity: HashMap<String, f64>,
37    /// Aktuális terhelés (0.0 - 1.0)
38    pub load: f64,
39    /// Hibaarány (0.0 - 1.0)
40    pub error_rate: f64,
41    /// Késleltetés ms-ben
42    pub latency_ms: f64,
43}
44
45/// Kapcsolat két komponens között
46#[derive(Debug, Clone)]
47pub struct Connection {
48    pub from: String,
49    pub to: String,
50    /// Sávszélesség (Mbps)
51    pub bandwidth: f64,
52    /// Protokoll típusa
53    pub protocol: String,
54    /// Aktuális késleltetés
55    pub latency_ms: f64,
56    /// Csomagvesztési arány
57    pub packet_loss: f64,
58}
59
60/// Egy teljes architektúra modell
61#[derive(Debug, Clone)]
62pub struct Architecture {
63    pub id: String,
64    pub name: String,
65    pub description: String,
66    pub components: HashMap<String, Component>,
67    pub connections: Vec<Connection>,
68    /// Verzió / generáció
69    pub version: u32,
70    /// Belső kohéziós pontszám (0.0 - 1.0)
71    pub cohesion_score: f64,
72}
73
74/// Szimulációs konfiguráció
75#[derive(Debug, Clone)]
76pub struct SimulationConfig {
77    /// Szimuláció időtartama másodpercben
78    pub duration_secs: f64,
79    /// Időlépés mérete ms-ben
80    pub time_step_ms: f64,
81    /// Maximális egyidejű kérések száma
82    pub max_concurrent_requests: u32,
83    /// Terhelési minta (pl. "linear", "spike", "sine", "random")
84    pub load_pattern: String,
85    /// Csúcs terhelés (0.0 - 1.0)
86    pub peak_load: f64,
87    /// Hibainjektálás engedélyezése
88    pub enable_fault_injection: bool,
89    /// Hibaarány (0.0 - 1.0)
90    pub fault_rate: f64,
91}
92
93impl Default for SimulationConfig {
94    fn default() -> Self {
95        Self {
96            duration_secs: 60.0,
97            time_step_ms: 100.0,
98            max_concurrent_requests: 100,
99            load_pattern: "linear".to_string(),
100            peak_load: 0.8,
101            enable_fault_injection: false,
102            fault_rate: 0.01,
103        }
104    }
105}
106
107/// Szimulációs metrikák
108#[derive(Debug, Clone)]
109pub struct SimulationMetrics {
110    pub architecture_id: String,
111    pub avg_latency_ms: f64,
112    pub p95_latency_ms: f64,
113    pub p99_latency_ms: f64,
114    pub throughput_req_per_sec: f64,
115    pub error_rate: f64,
116    pub cpu_utilization: f64,
117    pub memory_utilization: f64,
118    pub network_utilization: f64,
119    pub bottleneck_components: Vec<String>,
120    pub stability_score: f64,
121    pub resilience_score: f64,
122    pub total_requests: u64,
123    pub failed_requests: u64,
124    pub simulation_time_secs: f64,
125}
126
127/// Stresszteszt eredmény
128#[derive(Debug, Clone)]
129pub struct StressTestResult {
130    pub architecture_id: String,
131    pub breaking_point_load: f64,
132    pub recovery_time_ms: f64,
133    pub graceful_degradation: bool,
134    pub cascade_failures: Vec<String>,
135    pub recommendations: Vec<String>,
136}
137
138/// Szimulációs esemény (naplózáshoz)
139#[derive(Debug, Clone)]
140pub struct SimulationEvent {
141    pub time_ms: f64,
142    pub event_type: String,
143    pub component_id: String,
144    pub description: String,
145    pub severity: u8, // 0=info, 1=warning, 2=error, 3=critical
146}
147
148// ─── Architektúra Szimulátor ─────────────────────────────────────────────────
149
150/// A fő szimulátor motor
151pub struct ArchitectureSimulator {
152    architectures: Arc<RwLock<HashMap<String, Architecture>>>,
153    simulation_results: Arc<RwLock<HashMap<String, Vec<SimulationMetrics>>>>,
154    stress_test_results: Arc<RwLock<HashMap<String, Vec<StressTestResult>>>>,
155    events: Arc<RwLock<Vec<SimulationEvent>>>,
156    /// Tanult minták a korábbi szimulációkból
157    learned_patterns: Arc<RwLock<HashMap<String, f64>>>,
158}
159
160impl Default for ArchitectureSimulator {
161    fn default() -> Self {
162        Self::new()
163    }
164}
165
166impl ArchitectureSimulator {
167    /// Létrehoz egy új szimulátort
168    pub fn new() -> Self {
169        Self {
170            architectures: Arc::new(RwLock::new(HashMap::new())),
171            simulation_results: Arc::new(RwLock::new(HashMap::new())),
172            stress_test_results: Arc::new(RwLock::new(HashMap::new())),
173            events: Arc::new(RwLock::new(Vec::new())),
174            learned_patterns: Arc::new(RwLock::new(HashMap::new())),
175        }
176    }
177
178    /// Regisztrál egy architektúrát a szimulátorban
179    pub fn register_architecture(&self, arch: Architecture) {
180        let mut architectures = crate::sync_guard::write_lock(&self.architectures);
181        architectures.insert(arch.id.clone(), arch);
182    }
183
184    /// Lekér egy architektúrát ID alapján
185    pub fn get_architecture(&self, id: &str) -> Option<Architecture> {
186        let architectures = crate::sync_guard::read_lock(&self.architectures);
187        architectures.get(id).cloned()
188    }
189
190    /// Listázza az összes regisztrált architektúrát
191    pub fn list_architectures(&self) -> Vec<Architecture> {
192        let architectures = crate::sync_guard::read_lock(&self.architectures);
193        architectures.values().cloned().collect()
194    }
195
196    /// Futtat egy szimulációt egy architektúrán
197    pub fn run_simulation(
198        &self,
199        arch_id: &str,
200        config: &SimulationConfig,
201    ) -> Option<SimulationMetrics> {
202        let arch = {
203            let architectures = crate::sync_guard::read_lock(&self.architectures);
204            architectures.get(arch_id).cloned()?
205        };
206
207        let mut events = crate::sync_guard::write_lock(&self.events);
208        let _start_time = Instant::now();
209        let mut metrics = SimulationMetrics {
210            architecture_id: arch_id.to_string(),
211            avg_latency_ms: 0.0,
212            p95_latency_ms: 0.0,
213            p99_latency_ms: 0.0,
214            throughput_req_per_sec: 0.0,
215            error_rate: 0.0,
216            cpu_utilization: 0.0,
217            memory_utilization: 0.0,
218            network_utilization: 0.0,
219            bottleneck_components: Vec::new(),
220            stability_score: 1.0,
221            resilience_score: 1.0,
222            total_requests: 0,
223            failed_requests: 0,
224            simulation_time_secs: config.duration_secs,
225        };
226
227        let steps = (config.duration_secs * 1000.0 / config.time_step_ms) as u64;
228        let mut latencies: Vec<f64> = Vec::new();
229        let mut current_load: f64;
230        let mut component_loads: HashMap<String, Vec<f64>> = HashMap::new();
231
232        // Inicializáljuk a komponens terheléseket
233        for comp_id in arch.components.keys() {
234            component_loads.insert(comp_id.clone(), Vec::new());
235        }
236
237        for step in 0..steps {
238            let current_time = step as f64 * config.time_step_ms;
239
240            // Terhelési minta generálása
241            current_load = match config.load_pattern.as_str() {
242                "linear" => (current_time / (config.duration_secs * 1000.0)) * config.peak_load,
243                "spike" => {
244                    if current_time > config.duration_secs * 500.0
245                        && current_time < config.duration_secs * 600.0
246                    {
247                        config.peak_load
248                    } else {
249                        config.peak_load * 0.3
250                    }
251                }
252                "sine" => {
253                    let phase = (current_time / (config.duration_secs * 1000.0))
254                        * std::f64::consts::PI
255                        * 4.0;
256                    (phase.sin() * 0.5 + 0.5) * config.peak_load
257                }
258                "random" => rand::random::<f64>() * config.peak_load,
259                _ => config.peak_load * 0.5,
260            };
261
262            // Kérések generálása
263            let requests_this_step = (current_load * config.max_concurrent_requests as f64) as u64;
264            metrics.total_requests += requests_this_step;
265
266            // Komponensek terhelésének szimulálása
267            for (comp_id, comp) in &arch.components {
268                let base_latency = comp.latency_ms;
269                let load_factor = current_load * (1.0 + comp.error_rate);
270                let effective_latency = base_latency * (1.0 + load_factor * 2.0);
271
272                latencies.push(effective_latency);
273                component_loads.get_mut(comp_id).unwrap().push(load_factor);
274
275                // Hibainjektálás
276                if config.enable_fault_injection && rand::random::<f64>() < config.fault_rate {
277                    metrics.failed_requests += 1;
278                    events.push(SimulationEvent {
279                        time_ms: current_time,
280                        event_type: "fault".to_string(),
281                        component_id: comp_id.clone(),
282                        description: format!(
283                            "Fault injected in {} at load {:.2}",
284                            comp.name, current_load
285                        ),
286                        severity: 2,
287                    });
288                }
289
290                // Kapcsolatok szimulálása
291                for conn in &arch.connections {
292                    if conn.from == *comp_id || conn.to == *comp_id {
293                        let network_delay = conn.latency_ms * (1.0 + current_load);
294                        latencies.push(network_delay);
295
296                        if rand::random::<f64>() < conn.packet_loss {
297                            metrics.failed_requests += 1;
298                        }
299                    }
300                }
301            }
302
303            // Stabilitás számítása
304            if current_load > 0.9 {
305                metrics.stability_score *= 0.99;
306            }
307            if metrics.failed_requests as f64 / metrics.total_requests.max(1) as f64 > 0.1 {
308                metrics.resilience_score *= 0.95;
309            }
310        }
311
312        // Metrikák számítása
313        if !latencies.is_empty() {
314            latencies.sort_by(|a, b| a.total_cmp(b));
315            let len = latencies.len();
316            metrics.avg_latency_ms = latencies.iter().sum::<f64>() / len as f64;
317            metrics.p95_latency_ms = latencies[(len as f64 * 0.95) as usize];
318            metrics.p99_latency_ms = latencies[(len as f64 * 0.99) as usize];
319        }
320
321        metrics.throughput_req_per_sec = metrics.total_requests as f64 / config.duration_secs;
322        metrics.error_rate = metrics.failed_requests as f64 / metrics.total_requests.max(1) as f64;
323
324        // CPU, memória, hálózat kihasználtság
325        let avg_loads: Vec<f64> = component_loads
326            .values()
327            .map(|loads| loads.iter().sum::<f64>() / loads.len() as f64)
328            .collect();
329
330        if avg_loads.len() >= 3 {
331            metrics.cpu_utilization = avg_loads[0];
332            metrics.memory_utilization = avg_loads[1 % avg_loads.len()];
333            metrics.network_utilization = avg_loads[2 % avg_loads.len()];
334        }
335
336        // Szűk keresztmetszetek azonosítása
337        for (comp_id, loads) in &component_loads {
338            let avg_load = loads.iter().sum::<f64>() / loads.len() as f64;
339            if avg_load > 0.8 {
340                metrics.bottleneck_components.push(comp_id.clone());
341            }
342        }
343
344        // Eredmények tárolása
345        let mut results = crate::sync_guard::write_lock(&self.simulation_results);
346        results
347            .entry(arch_id.to_string())
348            .or_default()
349            .push(metrics.clone());
350
351        // Tanulás a szimulációból
352        self.learn_from_simulation(&metrics);
353
354        Some(metrics)
355    }
356
357    /// Stresszteszt: fokozatosan növeli a terhelést a töréspont megtalálásáig
358    pub fn run_stress_test(&self, arch_id: &str) -> Option<StressTestResult> {
359        let _arch = {
360            let architectures = crate::sync_guard::read_lock(&self.architectures);
361            architectures.get(arch_id).cloned()?
362        };
363
364        let mut result = StressTestResult {
365            architecture_id: arch_id.to_string(),
366            breaking_point_load: 0.0,
367            recovery_time_ms: 0.0,
368            graceful_degradation: true,
369            cascade_failures: Vec::new(),
370            recommendations: Vec::new(),
371        };
372
373        let mut load = 0.1;
374        let mut previous_error_rate = 0.0;
375        let mut cascade_started = false;
376
377        while load <= 1.0 {
378            let config = SimulationConfig {
379                duration_secs: 10.0,
380                time_step_ms: 50.0,
381                max_concurrent_requests: 1000,
382                load_pattern: "linear".to_string(),
383                peak_load: load,
384                enable_fault_injection: true,
385                fault_rate: 0.001,
386            };
387
388            if let Some(metrics) = self.run_simulation(arch_id, &config) {
389                // Töréspont detektálása
390                if metrics.error_rate > 0.5 && result.breaking_point_load == 0.0 {
391                    result.breaking_point_load = load;
392
393                    // Kaszkád hibák detektálása
394                    if metrics.error_rate > previous_error_rate * 2.0 {
395                        cascade_started = true;
396                        result.cascade_failures.push(format!(
397                            "Cascade failure at load {:.2}: error rate jumped from {:.2} to {:.2}",
398                            load, previous_error_rate, metrics.error_rate
399                        ));
400                    }
401                }
402
403                // Graceful degradation ellenőrzése
404                if metrics.error_rate > 0.8 {
405                    result.graceful_degradation = false;
406                }
407
408                previous_error_rate = metrics.error_rate;
409            }
410
411            load += 0.1;
412        }
413
414        // Ha nem találtunk töréspontot, a maximális terhelésnél sincs probléma
415        if result.breaking_point_load == 0.0 {
416            result.breaking_point_load = 1.0;
417            result
418                .recommendations
419                .push("Architecture is stable up to maximum load".to_string());
420        } else {
421            result.recommendations.push(format!(
422                "Breaking point at {:.0}% load — consider scaling or optimization",
423                result.breaking_point_load * 100.0
424            ));
425        }
426
427        if !result.graceful_degradation {
428            result
429                .recommendations
430                .push("Implement circuit breaker pattern for graceful degradation".to_string());
431        }
432
433        if cascade_started {
434            result
435                .recommendations
436                .push("Add bulkhead isolation to prevent cascade failures".to_string());
437        }
438
439        // Eredmények tárolása
440        let mut stress_results = crate::sync_guard::write_lock(&self.stress_test_results);
441        stress_results
442            .entry(arch_id.to_string())
443            .or_default()
444            .push(result.clone());
445
446        Some(result)
447    }
448
449    /// Összehasonlít két architektúrát
450    pub fn compare_architectures(
451        &self,
452        arch_id_a: &str,
453        arch_id_b: &str,
454    ) -> Option<ComparisonResult> {
455        let results = crate::sync_guard::read_lock(&self.simulation_results);
456        let results_a = results.get(arch_id_a)?;
457        let results_b = results.get(arch_id_b)?;
458
459        let latest_a = results_a.last()?;
460        let latest_b = results_b.last()?;
461
462        Some(ComparisonResult {
463            architecture_a: arch_id_a.to_string(),
464            architecture_b: arch_id_b.to_string(),
465            latency_winner: if latest_a.avg_latency_ms < latest_b.avg_latency_ms {
466                arch_id_a.to_string()
467            } else {
468                arch_id_b.to_string()
469            },
470            throughput_winner: if latest_a.throughput_req_per_sec > latest_b.throughput_req_per_sec
471            {
472                arch_id_a.to_string()
473            } else {
474                arch_id_b.to_string()
475            },
476            stability_winner: if latest_a.stability_score > latest_b.stability_score {
477                arch_id_a.to_string()
478            } else {
479                arch_id_b.to_string()
480            },
481            resilience_winner: if latest_a.resilience_score > latest_b.resilience_score {
482                arch_id_a.to_string()
483            } else {
484                arch_id_b.to_string()
485            },
486            recommendations: self.generate_recommendations(latest_a, latest_b),
487        })
488    }
489
490    /// Tanulás a szimulációs eredményekből
491    fn learn_from_simulation(&self, metrics: &SimulationMetrics) {
492        let mut patterns = crate::sync_guard::write_lock(&self.learned_patterns);
493
494        // Magas hibaarány -> negatív minta
495        if metrics.error_rate > 0.1 {
496            let key = format!("high_error_rate_{:.2}", metrics.error_rate);
497            *patterns.entry(key).or_insert(0.0) -= 0.1;
498        }
499
500        // Alacsony késleltetés -> pozitív minta
501        if metrics.avg_latency_ms < 10.0 {
502            let key = format!("low_latency_{:.2}", metrics.avg_latency_ms);
503            *patterns.entry(key).or_insert(0.0) += 0.1;
504        }
505
506        // Szűk keresztmetszetek -> figyelmeztető minta
507        for bottleneck in &metrics.bottleneck_components {
508            let key = format!("bottleneck_{}", bottleneck);
509            *patterns.entry(key).or_insert(0.0) -= 0.05;
510        }
511    }
512
513    /// Generál ajánlásokat két architektúra összehasonlításából
514    fn generate_recommendations(
515        &self,
516        a: &SimulationMetrics,
517        b: &SimulationMetrics,
518    ) -> Vec<String> {
519        let mut recs = Vec::new();
520
521        if a.avg_latency_ms < b.avg_latency_ms * 0.8 {
522            recs.push(format!(
523                "Architecture A has {:.0}% better latency — consider adopting its component layout",
524                (1.0 - a.avg_latency_ms / b.avg_latency_ms) * 100.0
525            ));
526        }
527
528        if a.throughput_req_per_sec > b.throughput_req_per_sec * 1.2 {
529            recs.push(format!(
530                "Architecture A handles {:.0}% more throughput — analyze its parallelization strategy",
531                (a.throughput_req_per_sec / b.throughput_req_per_sec - 1.0) * 100.0
532            ));
533        }
534
535        if a.stability_score > b.stability_score {
536            recs.push("Architecture A is more stable under load".to_string());
537        }
538
539        recs
540    }
541
542    /// Lekérdezi a tanult mintákat
543    pub fn get_learned_patterns(&self) -> HashMap<String, f64> {
544        let patterns = crate::sync_guard::read_lock(&self.learned_patterns);
545        patterns.clone()
546    }
547
548    /// Lekérdezi a szimulációs eseményeket
549    pub fn get_events(&self) -> Vec<SimulationEvent> {
550        let events = crate::sync_guard::read_lock(&self.events);
551        events.clone()
552    }
553
554    /// Törli az összes szimulációs eredményt
555    pub fn clear_results(&self) {
556        crate::sync_guard::write_lock(&self.simulation_results).clear();
557        crate::sync_guard::write_lock(&self.stress_test_results).clear();
558        crate::sync_guard::write_lock(&self.events).clear();
559    }
560}
561
562/// Összehasonlítás eredménye
563#[derive(Debug, Clone)]
564pub struct ComparisonResult {
565    pub architecture_a: String,
566    pub architecture_b: String,
567    pub latency_winner: String,
568    pub throughput_winner: String,
569    pub stability_winner: String,
570    pub resilience_winner: String,
571    pub recommendations: Vec<String>,
572}
573
574// ─── Segédfüggvények ────────────────────────────────────────────────────────
575
576/// Létrehoz egy egyszerű architektúra modellt a megadott paraméterekből
577pub fn create_architecture(
578    name: &str,
579    description: &str,
580    components: Vec<(&str, ComponentType, f64, f64)>, // (name, type, latency_ms, error_rate)
581    connections: Vec<(&str, &str, f64, &str)>,        // (from, to, bandwidth, protocol)
582) -> Architecture {
583    let id = format!("arch_{}", rand::random::<u32>());
584    let mut comp_map = HashMap::new();
585
586    for (i, (name, comp_type, latency, error_rate)) in components.iter().enumerate() {
587        let comp_id = format!("comp_{}", i);
588        comp_map.insert(
589            comp_id.clone(),
590            Component {
591                id: comp_id,
592                name: name.to_string(),
593                component_type: comp_type.clone(),
594                capacity: HashMap::new(),
595                load: 0.0,
596                error_rate: *error_rate,
597                latency_ms: *latency,
598            },
599        );
600    }
601
602    let conns: Vec<Connection> = connections
603        .iter()
604        .enumerate()
605        .map(|(i, (_from, _to, bw, proto))| Connection {
606            from: format!("comp_{}", i),
607            to: format!("comp_{}", i + 1),
608            bandwidth: *bw,
609            protocol: proto.to_string(),
610            latency_ms: 1.0,
611            packet_loss: 0.001,
612        })
613        .collect();
614
615    Architecture {
616        id,
617        name: name.to_string(),
618        description: description.to_string(),
619        components: comp_map,
620        connections: conns,
621        version: 1,
622        cohesion_score: 0.7,
623    }
624}
625
626/// Párhuzamos szimuláció futtatása több architektúrán
627pub fn run_parallel_simulations(
628    simulator: &ArchitectureSimulator,
629    arch_ids: &[&str],
630    config: &SimulationConfig,
631) -> Vec<(String, Option<SimulationMetrics>)> {
632    arch_ids
633        .iter()
634        .map(|id| {
635            let result = simulator.run_simulation(id, config);
636            (id.to_string(), result)
637        })
638        .collect()
639}
640
641#[cfg(test)]
642mod tests {
643    use super::*;
644
645    #[test]
646    fn test_create_and_simulate() {
647        let simulator = ArchitectureSimulator::new();
648
649        let arch = create_architecture(
650            "Test Microservice",
651            "A simple test architecture",
652            vec![
653                ("API Gateway", ComponentType::Software, 5.0, 0.01),
654                ("Auth Service", ComponentType::Software, 10.0, 0.02),
655                ("Database", ComponentType::Storage, 20.0, 0.005),
656            ],
657            vec![
658                ("API Gateway", "Auth Service", 1000.0, "HTTP/2"),
659                ("Auth Service", "Database", 5000.0, "TCP"),
660            ],
661        );
662
663        let arch_id = arch.id.clone();
664        simulator.register_architecture(arch);
665
666        let config = SimulationConfig::default();
667        let result = simulator.run_simulation(&arch_id, &config);
668
669        assert!(result.is_some());
670        let metrics = result.unwrap();
671        assert!(metrics.total_requests > 0);
672        assert!(metrics.avg_latency_ms > 0.0);
673    }
674
675    #[test]
676    fn test_stress_test() {
677        let simulator = ArchitectureSimulator::new();
678
679        let arch = create_architecture(
680            "Stress Test Target",
681            "Architecture for stress testing",
682            vec![
683                ("Load Balancer", ComponentType::Software, 2.0, 0.001),
684                ("Web Server", ComponentType::Software, 15.0, 0.01),
685                ("Cache", ComponentType::Storage, 1.0, 0.001),
686            ],
687            vec![
688                ("Load Balancer", "Web Server", 10000.0, "HTTP/1.1"),
689                ("Web Server", "Cache", 20000.0, "Redis"),
690            ],
691        );
692
693        let arch_id = arch.id.clone();
694        simulator.register_architecture(arch);
695        let result = simulator.run_stress_test(&arch_id);
696
697        assert!(result.is_some());
698        let stress = result.unwrap();
699        assert!(stress.breaking_point_load > 0.0);
700    }
701}