///|
fn main {
println("==================================================")
println(
" MoonSim 微服务网格仿真示例:链路熔断与灰度流量切分 ",
)
println("==================================================")
let sim = @moonsim.Simulation::new()
let topo : @network.NetworkTopology[String] = sim.create_network_topology(
20260708,
)
// 服务拓扑: Gateway -> [ServiceA, ServiceB_v1, ServiceB_v2]
// ServiceA -> [Database]
topo.add_node(1) // API Gateway
topo.add_node(2) // ServiceA (稳定版)
topo.add_node(3) // ServiceB-v1 (老版本, 90%流量)
topo.add_node(4) // ServiceB-v2 (金丝雀版本, 10%流量)
topo.add_node(5) // Database
// 正常延迟链路 (< 5ms)
topo.add_link(1, 2, 0.004, 0.01)
topo.add_link(1, 3, 0.003, 0.01)
topo.add_link(1, 4, 0.003, 0.02) // 金丝雀版本略高丢包率
topo.add_link(2, 5, 0.001, 0.005)
let lat_tracker = @stats.PercentileTracker::new("P2P延迟分布(ms)")
let v1_success = @stats.ThroughputTracker::new("ServiceB-v1成功量", 0.0)
let v2_success = @stats.ThroughputTracker::new("ServiceB-v2成功量", 0.0)
let mut circuit_broken = false
let mut circuit_break_time = 0.0
let mut total_requests = 0
let mut gateway_to_v2_fail = 0
// 发送请求并收集延迟
let mut req_id = 1
let req_steps : Array[(@event.ProcessContext) -> Double?] = [
fn(ctx) {
if req_id <= 20 {
let rid = req_id
req_id = req_id + 1
let now = ctx.clock.now_seconds()
total_requests = total_requests + 1
// 灰度流量切分: 90% -> ServiceB-v1, 10% -> ServiceB-v2
// 用请求 id 模拟: rid mod 10 == 0 -> v2 (10%)
let use_v2 = rid % 10 == 0
if use_v2 && !circuit_broken {
println(
"[\{now}s] [灰度分流] 请求 #\{rid} -> ServiceB-v2 (金丝雀)",
)
let _ = topo.send_packet(1, 4, "REQ #\{rid} -> v2", 5, fn(pkt) {
let delay = (sim.now() - now) * 1000.0
lat_tracker.record(delay)
println(
"[\{sim.now()}s] [ServiceB-v2] 收到 \{pkt.payload}, 延迟: \{delay}ms",
)
v2_success.record(sim.now(), 1)
})
} else if !circuit_broken {
// ServiceB-v1
let _ = topo.send_packet(1, 3, "REQ #\{rid} -> v1", 5, fn(pkt) {
let delay = (sim.now() - now) * 1000.0
lat_tracker.record(delay)
println(
"[\{sim.now()}s] [ServiceB-v1] 收到 \{pkt.payload}, 延迟: \{delay}ms",
)
v1_success.record(sim.now(), 1)
})
} else {
println(
"[\{now}s] [熔断器] 电路熔断中, 请求 #\{rid} 直接返回 fallback!",
)
}
Some(0.4) // 每0.4s发送一个请求
} else {
None
}
},
]
let _ = sim.start_process(
sim.register_process("请求生成器", req_steps),
0.0,
5,
)
// 注入故障: t=2.5s ServiceB-v2 故障率升高(模拟部署缺陷), t=4.5s 触发熔断
let _ = sim.schedule(2.5, 0, fn() {
println(
"\n[!!! 故障注入 !!!] [\{sim.now()}s] ServiceB-v2 发现内存泄漏,丢包率突升至 100%\n",
)
topo.set_node_status(4, @network.Offline)
gateway_to_v2_fail = gateway_to_v2_fail + 1
})
let _ = sim.schedule(4.5, 0, fn() {
println(
"\n[熔断器触发] [\{sim.now()}s] 连续失败达到阈值,ServiceB-v2 熔断激活,所有流量切回 v1\n",
)
circuit_broken = true
circuit_break_time = sim.now()
})
sim.run_until(10.0)
println("\n==================================================")
println(" 微服务网格可观测性分析报告 ")
println("==================================================")
println("仿真总请求数: \{total_requests}")
println("ServiceB-v1 处理成功量: \{v1_success.count}")
println("ServiceB-v2 (金丝雀) 成功量: \{v2_success.count}")
println("金丝雀版本触发熔断时刻: \{circuit_break_time}s")
println("P2P 端到端延迟 P50: \{lat_tracker.p50()}ms")
println("P2P 端到端延迟 P95: \{lat_tracker.p95()}ms")
println("P2P 端到端延迟 P99: \{lat_tracker.p99()}ms")
println("==================================================\n")
}