news 2026/10/1 2:52:46

Python+SUMO+DQN:自适应交通信号灯控制实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python+SUMO+DQN:自适应交通信号灯控制实战指南

简介:这是基于Python与SUMO仿真平台完成的一份交通信号灯相位时间优化源码,核心采用DQN强化学习算法动态调整信号配时,属于答辩评分98分的高分毕业设计,定位清晰。项目面向计算机、通信、人工智能、自动化等专业学生或从业者,可作期末课程设计、课程大作业和毕业设计参考,有较强的二次开发空间。压缩包共32个文件:16个xml负责路网、信号灯、检测器与车辆路由配置,6个osm为地图数据,5个py涵盖DQN主程序、优先经验回放与辅助工具,3个xlsx保存实验结果,另有sumocfg仿真配置和README说明文档,整体约536KB,目录便于按模块查找。目前已有85人浏览学习;代码经调试可运行,能帮助读者贯通从路网构建、交通流生成到智能体与SUMO交互、配时优化的完整流程,并可根据实际场景替换地图或拓展算法。

1. 用 Python 搭 DQN 调 SUMO 信号灯:先搞懂这个高分项目解决什么问题

一个十字路口,早高峰东西向排了两百米长队,南北向却在放空绿灯——固定配时信号灯不认这个账,它只按写死的秒数轮流放行。基于 Python 实现、把 SUMO 作为仿真平台、用强化学习里的 DQN 动态调整信号灯相位时长的方案,要解决的正是这件事:让路口根据实时排队情况自己决定每个相位放多久。这类项目在课程设计、毕设和强化学习入门里出现频率很高,常见叫法就是“基于 SUMO 与 DQN 的自适应交通信号控制”。适合有 Python 基础、想在一个看得见摸得着的物理仿真环境里把深度强化学习从参数跑到训练曲线的从业者和学生。整个方案拆成三块:SUMO 如何被 Python 控制、DQN 如何与仿真环境交互、相位时长如何被调整并被验证有效。

2. SUMO 的信号灯模型与 DQN 的决策闭环:先立住原理再写代码

写代码前,先回答三个问题:信号灯在 SUMO 里到底长什么样、强化学习三件套怎么对应交通语义、DQN 的稳定性机制为什么在这里不可省。这三件事没理顺,后面所有绕过的坑都会在训练曲线里加倍还回来。

2.1 SUMO 里的信号灯是一组相位状态,不是“红黄绿”三个字

在 SUMO 中,路网文件 .net.xml 定义了一堆 lane、edge 和 connection,信号灯则通过 traffic light program 挂在这些 connection 上。一个交叉口的配时方案由多个相位 phase 组成;每个相位由一个状态字符串和持续时间 duration 组成。状态字符串例如"GGgrrrGGgrrr",字符从左到右对应每个受控连接,G 表示机动车绿、g 表示行人绿、r 表示红灯、y 表示黄灯。这个字符串必须和受控连接一一对应,没对齐时轻则某方向不亮,重则相变混乱。

固定配时方案就是一组相位按时长循环执行;感应控制是在检测器触发时延长绿灯或提前切换;基于强化学习的方案要把“当前该让哪个相位放行、放多久”变成决策问题。这里说的“相位时间的调整”,动作就落在相位时长上。常见做法有两种流派:一种是动作空间直接选择下一个相位,另一种是动作空间在当前相位基础上做时长调整,比如延长 5 秒、10 秒、15 秒或直接切换。我一般用后者,动作维度低,训练也更稳定;代码里实际调用的还是 traci 的相位切换或时长设置接口,后面第 3 章会看到这条线。

另一个要立住的选型理由:为什么不自己写个排队模型,非要用 SUMO?因为 SUMO 是微观交通仿真器,内置车辆跟驰模型、随机车流生成和 netedit 路网编辑器,能模拟出“绿灯放行但前车堵住路口导致后车出不去”这类排队论模型画不出来的现象。TraCI 是官方提供的 Python 接口,基于 TCP 通信,端口默认 8813,仿真真实度足够支撑课程设计和论文级实验,这也是这个项目能拿高分的基础。需要注意 SUMO 大版本升级时 traci 接口偶有调整,建议锁定一个已跑通的版本,不要在训练中途顺手升级环境。

2.2 强化学习三件套:把排队、等待、相位切换翻译成状态动作奖励

要把配时问题交给 DQN,首先得把路况翻译成状态、动作、奖励。状态方面,我取四个进口方向车道的数据,拼成一个固定维度的向量:

状态特征TraCI 调用意义与注意点
排队数lane.getLastStepHaltingNumber(lane_id)速度近似为 0 的车辆数,最直观的拥堵指标
总等待时间lane.getWaitingTime(lane_id)累计等待秒数,波动大,需要归一化
平均速度lane.getLastStepMeanSpeed(lane_id)反映通行效率,可与排队数互补
当前相位运行时长trafficlight.getPhaseDuration(tls_id)告诉网络“现在绿灯已亮多久”,辅助决策

动作上我推荐“延长/切换”两分支:动作 0 表示把当前相位时长设为 5 秒,动作 1 表示切换到下一个相位。延长的颗粒度建议取 5 秒而不是 1 秒,整秒数太细时 Q 值难学,太粗又控制得笨拙;单路口实验里 5 秒通常是比较好的中间值。如果后面做多路口扩展,建议各路口动作空间统一,避免动作组合爆炸。

奖励函数是 DQN 效果好坏最大的变量。我用过三种方案:

奖励方案表达式特点
负排队-sum(queue)收敛快,对上游来车不敏感
负等待-sum(waiting_time)更贴近乘客感受,但数值波动大
吞吐量统计通过车辆数可能诱导“只放行主路”,忽略公平性

我现在常用的组合是-(2.0 * queue + 0.5 * wait),排队数权重高于等待时间,因为排队数直接影响通行效率,而等待时间在车流稀疏时会引入大量零值干扰。这两个权重是经验起点,后面避坑章节会讲到怎么调。

动手写代码前,先把上面表格和动作定义抄进一个简单的环境类。你不需要一开始就把状态设得很全,先用“排队数 + 等待时间 + 动作 0/1”把闭环跑通,再加特征。这个顺序能省掉大量调参时间。

2.3 DQN 为什么适配这个场景:状态连续、动作离散、经验回放稳定

Q-learning 打表存不下这种连续状态;DQN 用神经网络近似 Q 函数,天然匹配信号控制场景的“状态连续、动作离散”。但 DQN 容易发散,两个关键机制不可省。

经验回放(Experience Replay):把每次转换(s, a, r, s', done)存进循环队列,训练时随机采样一个小批次,而不是按顺序用。原因在于连续样本高度相关,直接按序更新会让网络朝一个方向偏;打乱后样本分布更接近独立同分布,更新更稳。容量设大一点也不怕,20000 是常见起点。

目标网络(Target Network):Q 值的更新目标是r + γ * max Q(s', a'),如果这个目标用的网络和当前网络是同一个,目标在训练中不停移动,很容易振荡甚至发散。所以复制一份参数冻结起来,每隔几百步同步一次,让目标“慢半拍”,训练才稳。同步步数太勤和太懒都见过翻车,200 步到 500 步之间是常见选择。

超参语义上值得注意:gamma(折扣因子)在交通场景不是越大越好,0.9 到 0.95 比较合适,因为信号控制的影响在十几秒内就能体现,不需要看得太远;epsilon(探索率)建议线性衰减到 0.05 而不是指数,探索太少容易学成“只放行主要道路”的短视策略。

还有一个决策节奏问题:为什么不能每 1 秒决策一次?信号灯相位最短绿灯时间通常在 5 秒以上,行人过街也需要固定时间;如果 1 秒就能切换相位,模型会学会“看到堵就切”,导致频繁换相、损失绿灯利用率和行人安全性。这就是决策间隔必须大于等于最短绿灯时间的深层原因,也是项目里可以写进文档的加分点。如果后续要升级,把 DQN 换成 Dueling DQN 只需要改网络结构的最后几行,改动成本很低,那是后话。

3. 用 Python 通过 TraCI 控制 SUMO 跑 DQN:最小工程骨架与关键代码

原理立住了,下面把最小骨架写出来。我按环境层、智能体层、主循环三层来组织代码,这也是这类源码项目最常见的组织方式。下面的代码可以照抄进一个干净目录,替换成你自己的路网和车流文件即可。

3.1 环境层:用 subprocess 拉起 SUMO,再通过 TraCI 建连与步进

import subprocess import time import traci # 训练时用无界面 sumo,评估可视化时换成 sumo-gui SUMO_BINARY = "sumo" CONFIG_FILE = "data/single_intersection.sumocfg" PORT = 8813 sumo_proc = subprocess.Popen( [SUMO_BINARY, "--remote-port", str(PORT), "--no-warnings"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, ) # 等待 SUMO 进入 TraCI 服务模式,最多等 10 秒 for _ in range(50): try: traci.init(PORT) break except traci.FatalTraCIError: time.sleep(0.2) # 在同一个 SUMO 进程里加载路网和车流 traci.load(["-c", CONFIG_FILE])

逻辑说明:这里的 subprocess 负责把 SUMO 拉起,--remote-port让 SUMO 进入 TraCI 服务模式;启动时故意不带-c参数,路网由 Python 侧的traci.load加载,好处是一个 SUMO 进程可以反复 load 多个训练回合,不用频繁创建子进程,训练速度更快。traci.init通过 TCP 连接端口,等待循环给 SUMO 留出启动时间;如果 10 秒内没连上,多半是端口被占或者 SUMO 没起来,去避坑章查。

参数说明:PORT 默认 8813,被占用时换成 8814、8815,并保证脚本里所有用到端口的地方同步改。SUMO_BINARY换成"sumo-gui"时用于可视化验证。stdout和stderr指向 DEVNULL 可以防止运行日志在终端刷屏,但排错期建议先删掉这两行,直接看标准输出,能少走很多弯路。

3.2 智能体层:DQN 网络、经验池与目标网络更新

import random from collections import deque import torch import torch.nn as nn import numpy as np STATE_DIM = 8 # 4 个进口方向 × (排队数 + 等待时间归一化) ACTION_DIM = 2 # 0: 延长当前相位 5 秒,1: 切换下一相位 class DQN(nn.Module): def __init__(self, state_dim, action_dim, hidden=128): super().__init__() self.net = nn.Sequential( nn.Linear(state_dim, hidden), nn.ReLU(), nn.Linear(hidden, hidden), nn.ReLU(), nn.Linear(hidden, action_dim), ) def forward(self, x): return self.net(x) class ReplayBuffer: def __init__(self, capacity=20000): self.buffer = deque(maxlen=capacity) def push(self, s, a, r, s_next, done): self.buffer.append((s, a, r, s_next, done)) def sample(self, batch_size): batch = random.sample(self.buffer, batch_size) s = torch.FloatTensor([b[0] for b in batch]) a = torch.LongTensor([b[1] for b in batch]) r = torch.FloatTensor([b[2] for b in batch]) s_next = torch.FloatTensor([b[3] for b in batch]) done = torch.FloatTensor([b[4] for b in batch]) return s, a, r, s_next, done def update(self, q_net, target_net, optimizer, batch_size=64, gamma=0.95): if len(self.buffer) < batch_size: return 0.0 s, a, r, s_next, done = self.sample(batch_size) q_values = q_net(s).gather(1, a.unsqueeze(1)).squeeze(1) with torch.no_grad(): q_next = target_net(s_next).max(1)[0] q_target = r + gamma * q_next * (1 - done) loss = nn.MSELoss()(q_values, q_target) optimizer.zero_grad() loss.backward() optimizer.step() return loss.item()

逻辑说明:q_net(s).gather(1, a.unsqueeze(1))取出当前状态下实际执行动作对应的 Q 值;q_next = target_net(s_next).max(1)[0]由目标网络给出下一状态的最优 Q 值;done为 1 时乘以(1 - done)把终止态的目标置零,因为终止态没有未来回报。目标值等于即时奖励加上 gamma 乘未来 Q,与当前网络的输出求 MSE,就是 DQN 的核心更新式。

参数说明:hidden=128对单路口足够,多路口可以考虑加到 256;batch_size=64是稳定性和内存的折中;gamma=0.95对应约 20 秒的视野;capacity=20000在 10 秒决策间隔下约等于 20000 个决策点,覆盖一个训练会话绰绰有余。目标网络的同步不在这个类里做,而是在主循环的每个 episode 末尾拷贝一次参数,见下一个节。

3.3 主循环:一个训练回合的交互时序与关键参数

def get_state(): # 占位 lane id,必须用 netedit 打开路网核对实际 id lane_ids = ["N_0", "S_0", "E_0", "W_0"] queue = [traci.lane.getLastStepHaltingNumber(lid) for lid in lane_ids] wait = [traci.lane.getWaitingTime(lid) for lid in lane_ids] return np.array(queue + wait, dtype=np.float32) / 50.0 def get_reward(): lane_ids = ["N_0", "S_0", "E_0", "W_0"] queue = sum(traci.lane.getLastStepHaltingNumber(lid) for lid in lane_ids) wait = sum(traci.lane.getWaitingTime(lid) for lid in lane_ids) return -(2.0 * queue + 0.5 * wait) TLS_ID = "0" DECISION_INTERVAL = 10 # 每隔 10 秒做一次决策 EPISODES = 400 MAX_STEPS = 360 # 单回合仿真 3600 秒 EPSILON_DECAY = 0.9995 # 每回合衰减一次 q_net = DQN(STATE_DIM, ACTION_DIM) target_net = DQN(STATE_DIM, ACTION_DIM) target_net.load_state_dict(q_net.state_dict()) optimizer = torch.optim.Adam(q_net.parameters(), lr=1e-3) buffer = ReplayBuffer() epsilon = 1.0 for episode in range(EPISODES): traci.load(["-c", CONFIG_FILE]) # 重新加载同一条车流,重置仿真 epsilon = max(0.05, epsilon * EPSILON_DECAY) state = get_state() step_count = 0 total_reward = 0.0 while step_count < MAX_STEPS: if random.random() < epsilon: action = random.randint(0, ACTION_DIM - 1) else: with torch.no_grad(): state_tensor = torch.FloatTensor(state) action = q_net(state_tensor).argmax().item() if action == 0: traci.trafficlight.setPhaseDuration(TLS_ID, 5) else: next_phase = (traci.trafficlight.getPhase(TLS_ID) + 1) % 4 traci.trafficlight.setPhase(TLS_ID, next_phase) # 执行动作后步进一个决策周期 for _ in range(DECISION_INTERVAL): traci.simulationStep(1.0) next_state = get_state() reward = get_reward() done = step_count + DECISION_INTERVAL >= MAX_STEPS buffer.push(state, action, reward, next_state, done) buffer.update(q_net, target_net, optimizer) state = next_state total_reward += reward step_count += DECISION_INTERVAL target_net.load_state_dict(q_net.state_dict()) print(f"episode={episode}, reward={total_reward:.2f}, eps={epsilon:.3f}") traci.close() sumo_proc.terminate()

逻辑说明:get_state里除以 50.0 是关键,排队数和等待时间量级不一样,直接拼进网络会让等待时间主导梯度,归一化到 0 到 1 区间后两者才可比,50 是“单车道峰值排队 50 辆”的经验上限,按你的路网规模调整。动作 0 把当前相位时长设为 5 秒,动作 1 切换到下一个相位;% 4里的 4 是信号灯 program 的相位数量,必须和你的 SUMO 路网定义一致。一个决策周期内步进 10 秒,再取新状态,这样状态与动作之间有时间差,符合真实信号控制“每 10 秒看一次路口”的节奏。

参数说明:EPISODES=400、MAX_STEPS=360相当于单回合仿真 1 小时,这个规模在 CPU 上几分钟能跑完;DECISION_INTERVAL=10是信号控制里比较合理的决策频率,如果发现动作执行效果不明显,先缩到 5 秒;epsilon 随回合衰减,避免后期仍在随机乱探。训练结束后记得traci.close()再 terminate 子进程,否则端口会被残留进程占住,下次实验就会踩 4.1 的坑。

4. 避坑:SUMO 与 DQN 最常见的 5 个翻车现场

代码能跑和项目能交之间隔着一堆坑,下面 5 个是我在这个方案里反复踩过的,按现象、原因、解决的顺序写,遇到相似症状直接对号入座。

4.1 现象:TraCI 连接超时,SUMO 进程秒退或卡死

现象:脚本报FatalTraCIError,或者 SUMO 进程一闪而过,traci.init一直连不上。

原因:启动命令里没带--remote-port;配置里的车流文件为空时 SUMO 会立刻结束仿真;端口被上一次残留进程占用。这三个原因我都碰到过,最常见的是第三种,上一轮训练异常退出,端口没释放。

解决:启动命令必须带--remote-port;启动前先手动跑一次sumo -c xxx.sumocfg确认路网和车流能完整加载;端口冲突时换 8814 并同步改traci.init的端口。调试期保留标准输出,不要 DEVNULL,SUMO 自己会打印出“配置里找不到车辆”这类关键线索。

4.2 现象:信号灯相位切换后车流乱套,绿灯方向没车、红灯方向积压

现象:DQN 明明选择了下一个相位,路口的实际放行方向和你预期完全对不上,绿灯亮着的方向一辆车都没有。

原因:状态字符串和受控连接没对齐,或者getPhase()的相位顺序和你预想的不一致。SUMO 的相位是定义在 connection 集合上的,字符位置错一位,放行方向就完全变,这个错很难靠肉眼发现。

解决:用traci.trafficlight.getControlledLinks(TLS_ID)打印每个信号组控制的 lane 和 connection,逐条核对相位字符串;想精确控制放行方向时,用setRedYellowGreenState按受控连接序列显式设置状态,不要全靠setPhase盲切。另外,如果用setPhase强制切换,可能出现绿灯只亮 2 秒就跳黄的问题,因为切相位不检查最短绿灯时长,建议在动作执行前判断当前相位已运行时间。

4.3 现象:训练几千回合奖励曲线不下降,或者像噪声一样乱飘

现象:total_reward画出来没有下降趋势,或者在一个区间里剧烈抖动,看起来完全没有学到东西。

原因:状态没归一化,多特征量纲悬殊;决策间隔太短,1 秒决策一次时信号灯切换还没来得及影响流量,就被下一个决策覆盖,奖励和动作之间根本没有因果关系;奖励权重设置不合理,比如等待时间权重过高,导致所有动作的奖励都趋近于同一个负值。

解决:状态向量统一除以峰值(参考 3.3 的/ 50.0);决策间隔至少在 5 到 15 秒;奖励做 clip 或调权重。排队 2.0、等待 0.5 只是起点,如果发现模型学成了“永远放行主路”,把排队权重降下来、等待权重提上去,逼它兼顾支路。

4.4 现象:用 sumo-gui 训练慢到以为死机

现象:跑一个 episode 要几分钟,400 回合跑完全天就没了,电脑风扇声比马路上的车还响。

原因:sumo-gui 每帧都在渲染路网、车辆和信号灯,开销远大于无界面模式;而训练要跑几百回合,每回合 3600 步,大部分计算都被可视化拖慢了。

解决:训练阶段用无界面sumo,评估或出图时再用sumo-gui,配合--start --quit-on-end自动加载和退出。仿真步长从 1.0 提到 2.0 也能提速,但要注意步长太大会影响车辆跟驰模型精度,如果实验结果要写进论文,步长保持 1.0,等评估出图时再开 GUI。

4.5 现象:评估结果忽高忽低,训练曲线很漂亮但评估被打回原形

现象:训练奖励曲线稳步下降,一评估平均等待时间却忽大忽小,连跑几次结果差一倍。

原因:评估时 epsilon 没有置 0,模型还在随机探索;不同回合的车流随机性太大,同一套权重在不同随机车流下表现差异明显。

解决:评估写独立脚本,设 epsilon 为 0 纯贪心决策;用固定随机种子,车流文件在训练和评估中保持一致;至少评估 5 次取平均值,并把标准差写进结果里,这是论文和课程设计报告里必写的部分,也能让你的结论从“感觉有效”变成“统计上有差异”。

5. 把“能跑”变成“高分”:评估指标、对比实验和参数微调三件事

项目能跑只是及格线,高分靠的是验证方法和参数微调的细节。

第一件事是跟固定配时做对比。用同一份车流文件,先跑一遍固定配时方案,记录平均等待时间、平均排队长度和通过的车辆总数;再跑 DQN,记录同样三个指标。对比表格三列:方案、平均等待时间(秒/辆)、平均排队长度(辆/方向)。固定配时的周期取 40 秒、主路 25 秒、支路 15 秒这类常见值即可,不需要调最优,因为你要证明的是 DQN 比“没调过的固定配时”更好,而不是比“最强固定配时”更好。如果条件允许,再加一列感应控制做 baseline,说服力更强。

第二件事是画训练曲线。奖励曲线直接画出来会很毛躁,用滑动平均窗口平滑后再展示,窗口取 10 到 20 个 episode。曲线里要能看到两段式:前期探索带来的剧烈波动,后期逐步下行并稳定。如果曲线一直不收敛,多半是第 4.3 条的坑,先回环境层检查,不要死磕网络结构。

第三件事是参数微调。优先动三个参数:决策间隔、epsilon 衰减系数、奖励权重。决策间隔在 5、10、15 秒各跑一遍,选平均等待时间最小的;epsilon 衰减从 0.9995 微调到 0.999,衰减太快探索不足,太慢收敛不上;奖励权重里 queue 的 2.0 让模型偏主路,如果支路被饿死,降到 1.0 并把 wait 权重提到 1.0,让模型兼顾公平性。

我最常犯的错是一上来就拉满 3600 秒、400 回合,跑一个实验半小时,改一个参数又要半小时。正确的顺序是先跑 60 秒仿真、50 回合,把代码流程打通,确认奖励在涨、信号灯在切,再逐步加长到完整实验。先小后大,省下的都是调参时间。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/1 2:50:51

Python+Vue大学生旅游管理系统开发实战:从环境配置到部署全攻略

刚接手“PythonVue的大学生去哪旅游管理系统”这个题目的时候&#xff0c;估计很多人跟我当时的反应一样&#xff1a;这不就是一个典型的课程设计吗&#xff1f;用Django或者Flask写个后端&#xff0c;Vue搭个前端&#xff0c;然后旅游景点增删改查、用户登录注册、路线推荐&am…

作者头像 李华
网站建设 2026/10/1 2:50:38

PSO优化FCM聚类:居民用电负荷分析原理与Matlab实现

直接把这段经历写出来&#xff0c;是因为我觉得很多做电力负荷分析、用户画像的同学&#xff0c;都在用FCM聚类但总被“初值敏感、容易陷局部最优”折磨。做居民用电行为分析&#xff0c;核心是把用户的负荷曲线分成几类&#xff1a;有人白天用电多&#xff0c;有人晚上用电多&…

作者头像 李华
网站建设 2026/10/1 2:50:07

金融增强开源模型:Ling-3.0-flash-Fin,私有化投研Agent新选择

一、模型速览项目说明发布方蚂蚁集团百灵&#xff08;InclusionAI&#xff09;&#xff0c;联合中金公司等金融机构共建参数量124B 总参 / 5.1B 激活&#xff08;细粒度 MoE&#xff0c;bailing_hybrid / BailingMoeV3&#xff09;上下文原生 256K许可证MIT&#xff08;可商用、…

作者头像 李华
网站建设 2026/10/1 2:49:31

NI PXIe-4147 自校准反复失败

测试机上一路 NI PXIe-4147 反复过不了自校准&#xff0c;把这一路单独拿出来、脱离整机再跑一次仍然失败&#xff0c;可功能性的 Self-Test 却能正常通过。判断的关键在两步&#xff1a;先把具体的错误码和描述拿到手&#xff0c;再把前端接线全部脱开重跑&#xff1b;如果这样…

作者头像 李华
网站建设 2026/10/1 2:48:38

全栈开发技术概览:从前端到后端的关键技术栈

全栈开发技术概览&#xff1a;从前端到后端的关键技术栈全栈开发这个东西, 说到底就是一种技能表现, 它要求做开发的这些人, 不仅要对前端技术门儿清, 还要对后端的各个关键部分都摸透才行。想要掌握这种本事, 一般来说, 得看这个人手里有没有下面这几项能力存在:1. 在编程语言…

作者头像 李华
网站建设 2026/10/1 2:48:21

云原生环境下的DDoS防护(实战笔记)最佳实践与踩坑记录

本文深入探讨云原生环境下的DDoS防护&#xff08;实战笔记&#xff09;&#xff0c;涵盖背景分析、原理剖析、实战步骤、配置示例、优化建议和避坑指南。在DDoS与CC防护领域&#xff0c;云原生环境下的DDoS防护&#xff08;实战笔记&#xff09;是开发者和技术负责人持续关注的…

作者头像 李华