实验结果与结论
This commit is contained in:
Binary file not shown.
@@ -56,6 +56,8 @@
|
||||
\input{data/chap02}
|
||||
\input{data/chap03}
|
||||
\input{data/chap04}
|
||||
\input{data/chap05}
|
||||
\input{data/chap06}
|
||||
|
||||
% 参考文献
|
||||
\bibliography{ref/refs} % 参考文献使用 BibTeX 编译
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
% !TEX root = ../bachelor-thesis.tex
|
||||
|
||||
\chapter{引言}
|
||||
\label{chap:引言}
|
||||
|
||||
\section{研究背景}
|
||||
|
||||
@@ -17,6 +18,9 @@
|
||||
|
||||
覆盖网络所承载的媒体多样、复杂,如实时音视频通讯流量、文件下载流量等。这些不同的业务流量对应的用户体验(Quality of Experience, QoE)的影响因素也不尽相同。例如,实时音视频通讯业务如在线会议应用中,参会的用户间有较强的互动,延迟是影响QoE的主要因素;而与之相比,文件下载业务则对延迟不敏感,带宽与下载完成时间是QoE的主要影响因素。覆盖网络需要同时服务这些不同的流量,尽管它们的QoE影响因素各异,但是对网络的服务质量(Quality of Service, QoS)需求是统一的,即需要覆盖网络尽可能地提供低延迟、无丢包、高带宽的链路。
|
||||
|
||||
\nomenclature{QoE}{用户体验(Quality of Experience)}
|
||||
\nomenclature{QoS}{服务质量(Quality of Service)}
|
||||
|
||||
在覆盖网络中,同一条逻辑链路的连接可以由多条物理链路抽象而成,云网络服务商通常同时提供专线与公网链路作为同一条逻辑链路的可选物理链路。通常来讲,专线的质量较高,延迟较低且稳定、丢包率低,能提供较好的传输质量和用户体验,但是高昂的价格对云服务商大规模使用带来挑战;与之相对地,公网链路的价格较低,但是容易受到网络中其它用户的影响,容易发生拥塞和竞争,传输质量容易发生波动,不能提供稳定优质的用户体验。全部使用高价的专线链路自然可以确保优秀的服务质量,但是会导致运营成本高昂;放弃使用专线链路转而使用公网链路会导致链路质量低下,不能满足服务质量需求。因此,研究如何在维持高服务质量的前提下尽可能地降低成本是亟须解决的问题。
|
||||
|
||||
\section{研究现状}
|
||||
@@ -38,7 +42,9 @@
|
||||
|
||||
基于此,本文设计了一套基于交织前向纠错编码(Interleaved Forward Error Correction, Interleaved FEC)的跨国公网链路优化方法。本文提出的方法使用公网实现覆盖网络中所有节点的互联,对覆盖网络中的每一段链路,通过监控链路上的丢包情况,利用马尔科夫链建模网络丢包模型,对低质量的链路动态选择FEC编码参数,并利用交织XOR编码进行编码和丢包恢复,并在解码时对输出速率利用比例-积分控制器进行动态平滑处理。本方法不需要使用专线连接,极大地降低了链路的使用成本,同时又有选择性地在低质量链路上使用冗余编码,避免了在高质量链路上添加额外带宽。另外,应用交织编码技术,将冗余包与数据包间隔其它数据包发送,极大地降低了链路连续丢包对丢包恢复的影响。
|
||||
|
||||
本文作者实现了基于本文提出的分段链路质量优化方法的分布式覆盖网络转发以及针对低质量链路的冗余包计算及丢包恢复算法。经过对真实网络的模拟实验,本文提出的方法将端到端带宽提升了xxx,流完成时间减少了xxx。
|
||||
\nomenclature{FEC}{前向纠错编码(Forward Error Correction)}
|
||||
|
||||
本文作者实现了基于本文提出的分段链路质量优化方法的分布式覆盖网络转发以及针对低质量链路的冗余包计算及丢包恢复算法。经过对真实网络的模拟实验,本文提出的方法相比直接使用公网链路将端到端带宽提升了最高260\%。
|
||||
|
||||
总结而言,本文主要的贡献是:
|
||||
\begin{itemize}
|
||||
@@ -49,4 +55,16 @@
|
||||
|
||||
\section{论文内容}
|
||||
|
||||
(To be filled)
|
||||
本文共分为六章,各章内容安排如下:
|
||||
|
||||
第\ref{chap:引言}章为引言。本章介绍跨域云网络中覆盖网络传输的应用背景,分析专线链路成本高、公网链路质量不稳定所带来的矛盾,概述现有链路调度与冗余编码方法的不足,并给出本文的研究思路与主要贡献。
|
||||
|
||||
第\ref{chap:背景介绍与研究动机}章为背景介绍与研究动机。本章介绍云网络、覆盖网络以及前向纠错编码等必要背景,结合真实测量结果分析现有方法在跨域公网链路场景下的局限,指出低质量公网链路不应仅被规避,而应结合覆盖网络的分段转发能力进行针对性质量修复。
|
||||
|
||||
第\ref{chap:相关工作}章为相关工作。本章分别介绍覆盖网络与隧道技术、链路质量优化方法以及软件定义网络与网络调度相关研究,并分析这些工作与本文研究问题之间的联系和差异。
|
||||
|
||||
第\ref{chap:跨域云网络传输性能提升研究}章为跨域云网络传输性能提升方法。本章介绍本文提出的全公网链路优化系统,包括系统总体架构、交织XOR前向纠错编码设计、基于丢包统计的自适应参数调整方法,以及用于平滑解码端突发输出的速率控制机制。
|
||||
|
||||
第\ref{chap:实验验证与分析}章为实验验证与分析。本章介绍实验环境与实验设置,通过在模拟低质量链路条件下对比直接转发方案和本文方法的端到端吞吐性能,验证本文提出的分段链路质量修复方法的有效性。
|
||||
|
||||
第\ref{chap:结论与展望}章为结论与展望。本章总结全文的主要工作与实验结论,并讨论本文方法仍存在的不足以及未来可进一步优化的方向。
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
% !TEX root = ../bachelor-thesis.tex
|
||||
|
||||
\chapter{背景介绍与研究动机}
|
||||
\label{chap:背景介绍与研究动机}
|
||||
|
||||
本章首先在\ref{sec:背景介绍}节中介绍云网络、覆盖网络和网络编码的基本信息,介绍在维持高质量服务前提下进行成本优化这一核心问题。之后在\ref{sec:实验观察与已有工作不足}节介绍一些本文作者对云网络的观察发现及已有工作在这些新观察下暴露出的不足。最后,在\ref{sec:basic idea}节介绍本文提出的通过对云网络公网进行分段质量修复的基本思路及面临的挑战。
|
||||
|
||||
@@ -78,4 +79,8 @@
|
||||
\item \textbf{如何避免片段级丢包恢复影响端到端传输节奏。} FEC解码通常以编码组为单位恢复数据包,恢复完成后可能在短时间内集中交付多个数据包。这种突发式输出会改变接收端观测到的数据到达节奏,并进一步影响拥塞控制算法的速率估计和实时应用的播放稳定性。因此,系统在修复丢包的同时,还需要对解码后的输出过程进行平滑控制。
|
||||
\end{enumerate}
|
||||
|
||||
\section{本章小结}
|
||||
|
||||
本章围绕跨域云网络中的传输质量与链路成本问题,介绍了云网络、覆盖网络以及前向纠错编码等背景知识。首先,覆盖网络为跨地域云资源互联提供了灵活的虚拟网络抽象,但公网链路质量不稳定、专线链路成本较高,使得服务商需要在传输质量和运营成本之间进行权衡。其次,FEC等网络编码技术能够通过冗余信息恢复部分丢包,为改善低质量公网链路提供了基础。
|
||||
|
||||
在此基础上,本章结合真实网络测量指出现有方法的两点不足:一方面,公网链路质量下降时段与用户流量高峰存在明显重合,使得仅依赖公网分流的链路调度方法难以削减专线峰值成本;另一方面,不同公网链路片段之间质量差异显著,端到端统一添加冗余会在高质量片段上造成额外带宽浪费。基于这些观察,本文提出利用覆盖网络路径可分段、中间节点可控的特点,在全公网互联的前提下对低质量链路片段进行针对性质量修复,并进一步总结了该思路在编码透明性、参数自适应和解码输出平滑等方面面临的设计挑战。
|
||||
@@ -1,6 +1,7 @@
|
||||
% !TEX root = ../bachelor-thesis.tex
|
||||
|
||||
\chapter{相关工作}
|
||||
\label{chap:相关工作}
|
||||
|
||||
本章主要介绍一些与本文工作相关的已有工作。\ref{sec:隧道技术介绍}节主要介绍了当前在工业界得到较为广泛使用的用于构建覆盖网络的几种隧道技术,\ref{sec:链路质量优化相关工作}节介绍了多种常用于进行网络编码的前项纠错编码技术,并比较了他们的异同。最后,\ref{sec:SDN相关工作}介绍了与覆盖网络紧密联系的软件定义网络(Software defined network, SDN)的概念,以及与其相关的一些工作。
|
||||
|
||||
@@ -88,7 +89,7 @@ XOR、R-S等分组码结合交织已经能较好地应对网络中的丢包问
|
||||
尽管现有FEC技术已经能够有效提升低质量网络环境中的数据恢复能力,但大多数研究主要关注编码结构本身的恢复性能、冗余效率以及恢复时延等问题,通常默认数据传输路径已经固定,而较少进一步考虑不同网络链路之间的质量差异与成本差异。在跨域云网络场景下,不同链路可能同时具有显著不同的传输性能与租赁成本,如何结合链路状态动态选择冗余保护策略,并进一步联合流量调度共同优化整体传输性能与网络成本,仍然是值得进一步研究的问题。
|
||||
|
||||
\section{软件定义网络与网络调度}
|
||||
\label{SDN相关工作}
|
||||
\label{sec:SDN相关工作}
|
||||
|
||||
软件定义网络(Software defined networking, SDN)指的是将网络中各个转发设备的数据平面与控制平面解耦,集中进行控制的网络。SDN网络大大简化了网络的管理和控制流程。对于跨域云网络及其中部署的虚拟网络,尽管有部分的网络设备由SDN统一控制,但是各个设备间的跨域互联通常仍仍旧由传统的网络设备提供连接,形成了混合形软件定义网络(hybrid SDN network),如图\ref{fig:混合SDN网络}\cite{amin2018hybridsdnsurvey}。
|
||||
|
||||
@@ -107,3 +108,10 @@ XOR、R-S等分组码结合交织已经能较好地应对网络中的丢包问
|
||||
|
||||
之后的一些研究进一步研究了通过流量调度实现对资源利用的优化。CRONets\cite{cai2016cronets}提出了利用云网络服务商提供的虚拟机网络网络链路建立覆盖网络的方案,并利用多路径TCP在覆盖网络节点间提升性能。在覆盖网络资源规模进一步扩大的背景下,研究者开始关注如何通过集中式调度提升资源利用效率。B4\cite{jain2013b4}则提出了通过流量调度和流量工程,有效分配不同链路的负载以最大化链路使用率的方法。BDS\cite{zhang2018bds}使用统一的中央控制器持续监控不同覆盖网络间节点的可用资源,动态调度传输路径以实现对链路的带宽的充分利用。除了单纯追求更高链路利用率,一些研究开始进一步联合考虑性能与部署成本之间的平衡。Skyplane\cite{jain2023skyplane}则观察到云网络提供商不同地域资源的定价差异,将追求文件传输最大吞吐量与追求更低租赁成本建模为一个线性优化问题,给定其中一个指标的限制,利用算法最优化另一个指标。Titan\cite{kataria2024titan}则针对持续运行的流媒体服务将租用云网络互联资源成本纳入考量,在维持用户体验在一定水平之上的前提下,动态调度流量与计算资源,降低整体的网络部署成本。与此同时,随着实时媒体等对服务连续性要求更高的应用出现,部分工作开始关注链路状态变化时的快速恢复能力。Troia等人\cite{troia2022sdnfastrecovery}利用eBPF技术实时检测各个覆盖网络节点的传输状态,并在检测到链路拥塞或其他链路质量变化事件时,快速重新触发流量调度算法以维持高质量连接。XRON\cite{wu2023xron}则同时结合链路成本优化、资源利用与快速恢复,主动探测可用的公网链路与专线链路质量,结合未来用户流量需求预测,持续计算和更新成本最佳的流量调度策略。为保持所承载音视频通话的服务质量,计算多个备用调度方案以确保故障条件的快速恢复。
|
||||
|
||||
\section{本章小结}
|
||||
|
||||
本章围绕本文研究问题介绍了三类相关工作。首先,覆盖网络隧道技术通过在底层IP网络之上封装二层或三层报文,为云网络中的虚拟互联提供了基础能力。VXLAN、NVGRE和Geneve等协议在封装方式、可扩展性和部署复杂度上各有特点,为构建可控的覆盖网络转发路径提供了工程基础。
|
||||
|
||||
其次,链路质量优化相关工作主要利用FEC等机制缓解低质量链路上的丢包问题。从简单复制冗余、XOR码和R-S码等分组码,到交织编码和流式编码,已有工作在冗余效率、突发丢包恢复能力和恢复延迟之间进行了不同权衡。这些方法能够提升低质量网络中的丢包恢复能力,但通常以端到端路径为对象,较少考虑跨域云网络中不同链路片段之间的质量差异。
|
||||
|
||||
最后,软件定义网络与网络调度相关工作利用集中控制、路径选择和流量工程等方法优化覆盖网络资源使用,并在一定程度上兼顾传输性能和链路成本。然而,这类方法通常倾向于在公网质量下降时规避低质量链路,转而使用专线或其他高质量路径,而较少考虑对低质量公网链路进行修复。与上述工作不同,本文将覆盖网络的分段可控能力与FEC链路修复能力结合起来,在全公网互联的条件下对低质量链路片段进行针对性优化。
|
||||
|
||||
108
data/chap04.tex
108
data/chap04.tex
@@ -1,16 +1,17 @@
|
||||
% !TEX root = ../bachelor-thesis.tex
|
||||
|
||||
\chapter{跨域云网络传输性能提升研究}
|
||||
\label{chap:跨域云网络传输性能提升研究}
|
||||
|
||||
\section{设计目标与总体思路}
|
||||
% \section{设计目标与总体思路}
|
||||
|
||||
前两章的分析表明,跨域云网络中的核心矛盾在于:专线链路能够提供稳定的传输质量,但使用成本较高;公网链路成本低廉、覆盖灵活,却在部分跨域片段上存在明显的丢包和抖动。若继续沿用“公网质量良好时走公网、质量恶化时切回专线”的以资源调度为中心的策略,系统在用户需求高峰期仍将大量依赖专线,成本优化空间十分有限,而已有的前向纠错编码等链路质量优化类工作则又将传输链路当作不可改变的低质量链路,只进行端到端的冗余添加与丢包恢复,没有考虑网络传输过程中不同分段的网络质量不同,需要不同程度的丢包恢复。因此,本文提出,依靠云网络配置灵活、路由选择多样的特点,通过冗余编码对云网络中的部分低质量链路进行针对性的质量修复,以达到传输性能与运营成本的平衡。
|
||||
% 前两章的分析表明,跨域云网络中的核心矛盾在于:专线链路能够提供稳定的传输质量,但使用成本较高;公网链路成本低廉、覆盖灵活,却在部分跨域片段上存在明显的丢包和抖动。若继续沿用“公网质量良好时走公网、质量恶化时切回专线”的以资源调度为中心的策略,系统在用户需求高峰期仍将大量依赖专线,成本优化空间十分有限,而已有的前向纠错编码等链路质量优化类工作则又将传输链路当作不可改变的低质量链路,只进行端到端的冗余添加与丢包恢复,没有考虑网络传输过程中不同分段的网络质量不同,需要不同程度的丢包恢复。因此,本文提出,依靠云网络配置灵活、路由选择多样的特点,通过冗余编码对云网络中的部分低质量链路进行针对性的质量修复,以达到传输性能与运营成本的平衡。
|
||||
|
||||
在可变的用户包大小下设计FEC编码方案->使用block code
|
||||
% 在可变的用户包大小下设计FEC编码方案->使用block code
|
||||
|
||||
在网络质量动态变化的情况下,自适应地选择FEC参数->使用markov链估计网络参数
|
||||
% 在网络质量动态变化的情况下,自适应地选择FEC参数->使用markov链估计网络参数
|
||||
|
||||
FEC解码时出现burst造成速率测量不准,干扰CCA决策->使用PI控制器稳定发送速率
|
||||
% FEC解码时出现burst造成速率测量不准,干扰CCA决策->使用PI控制器稳定发送速率
|
||||
|
||||
% 因此,本研究设计的传输优化系统遵循两项设计原则。第一,云网络节点间的连接全部使用公网链路建立,不再使用专线,从而降低跨域互联的资源使用成本。第二,FEC冗余不在整条端到端路径上无差别启用,而是以链路片段为粒度进行针对性修复。对于质量良好的公网片段,系统保持普通转发,以避免引入额外带宽开销;对于丢包集中、连续丢包显著的低质量片段,系统在该片段的发送端加入冗余编码,并在接收端恢复丢包,从而提升该片段的有效传输质量。
|
||||
|
||||
@@ -18,36 +19,36 @@ FEC解码时出现burst造成速率测量不准,干扰CCA决策->使用PI控
|
||||
|
||||
\section{系统总体架构}
|
||||
|
||||
系统由一个中心控制器(Coordinator)和多个部署在不同地域的转发节点(Node)组成,如图\ref{fig:系统总体架构}所示。中心控制器维护节点和连接状态,为端到端连接分配流标识,向相关节点下发转发表项,并根据解码端上报的丢包统计调整低质量链路片段上的FEC编码参数。转发节点负责数据面的实际转发,在本地根据控制器下发的配置,对不同流分别执行普通转发、FEC编码或FEC解码。
|
||||
为了实现在全公网互联结构下对低质量链路片段进行针对性修复,本工作主要需要解决三个挑战:
|
||||
|
||||
\textbf{挑战一:如何在用户包大小可变的场景下设计链路片段级FEC编码方案。}
|
||||
系统作为通用转发平台,承载的上层应用可能产生任意大小的数据包。当用户数据包接近MTU时,若FEC编码产生的冗余信息追加在用户数据包内一同发送,则封装后的数据包可能超出MTU,导致IP层分片或传输失败。因此,FEC编码方案必须能够在不影响用户数据包大小的情况下独立添加冗余信息。同时,由于本文只在低质量公网片段上进行修复,编码方案还需要在单个链路片段上有效应对连续突发丢包,而不是依赖端到端重传。本文在\ref{sec:fec编码}节设计了交织XOR分组编码方案应对此挑战。
|
||||
|
||||
\textbf{挑战二:如何判断差链路所需的冗余强度并自适应地选择编码参数。}
|
||||
全公网方案不能简单地对所有链路长期使用高冗余率,否则低成本公网节省下来的费用会被额外流量开销抵消。系统承载的应用中又包含实时音视频流媒体等对延迟敏感的业务,FEC编码引入的冗余包不仅占用额外带宽,也会引入解码等待延迟。因此,系统需要根据链路片段上的实时丢包统计,在丢包恢复能力、额外带宽开销和恢复延迟之间取得平衡。由于公网链路的丢包率与丢包模式随时间动态变化,固定的编码参数无法同时适应不同质量状态的链路。本文在\ref{sec:参数调整}节通过建立丢包信道模型并据此进行约束搜索来解决此挑战。
|
||||
|
||||
\textbf{挑战三:如何消除FEC解码按组突发输出对拥塞控制算法的干扰。}
|
||||
FEC解码器按编码组为单位批量恢复和交付数据包。当一个编码组恢复完成后,组内的所有数据包被一次性连续交付给上层应用。这种突发式的输出模式会使得上游的拥塞控制算法收到密集的ACK确认包,从而错误地估计链路可用带宽,引发发送速率的震荡。速率震荡不仅影响应用的传输性能,还会使FEC编码器的输入节奏不稳定,进一步干扰吞吐量统计和参数估计的准确性。本文在\ref{sec:pacer}节中,在解码端设计了基于PI控制器的输出速率控制器来消除此问题。
|
||||
|
||||
本系统的整体架构如图\ref{fig:系统总体架构}所示。系统由一个中心控制器(Coordinator)和多个部署在不同地域的转发节点(Node)组成。中心控制器维护节点和连接状态,为端到端连接分配流标识,向相关节点下发转发表项,并根据解码端上报的丢包统计调整低质量链路片段上的FEC编码参数。转发节点负责数据面的实际转发,在本地根据控制器下发的配置,对不同流分别执行普通转发、FEC编码或FEC解码。
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\fbox{\parbox{0.95\textwidth}{\centering\small\vspace{1.5em}%
|
||||
图片内容:系统总体架构。上方Coordinator通过TCP连接(控制面,虚线)连接多个Node。Node之间通过UDP隧道互联(数据面,实线)。标注一条端到端路径:用户A → TUN → Node1(FEC编码器)→ UDP隧道 → Node2(FEC解码器 + Pacer)→ TUN → 用户B。Coordinator标注"FEC参数计算",数据面上标注编码后数据包传输,控制面上标注丢包统计上报与参数下发。%
|
||||
\vspace{1.5em}}}
|
||||
% \fbox{\parbox{0.95\textwidth}{\centering\small\vspace{1.5em}%
|
||||
% 图片内容:系统总体架构。上方Coordinator通过TCP连接(控制面,虚线)连接多个Node。Node之间通过UDP隧道互联(数据面,实线)。标注一条端到端路径:用户A → TUN → Node1(FEC编码器)→ UDP隧道 → Node2(FEC解码器 + Pacer)→ TUN → 用户B。Coordinator标注"FEC参数计算",数据面上标注编码后数据包传输,控制面上标注丢包统计上报与参数下发。%
|
||||
% \vspace{1.5em}}}
|
||||
\caption{系统总体架构}
|
||||
\label{fig:系统总体架构}
|
||||
\end{figure}
|
||||
|
||||
每个转发节点上为每条端到端连接创建独立的TUN虚拟网络设备,用户应用只感知到一条普通IP链路,而不需要感知底层覆盖网络和FEC机制。节点之间通过UDP隧道传输数据包,每个数据包的头部携带\texttt{flow\_id}以标识所属的数据流。系统为每个\texttt{flow\_id}创建独立的处理线程,线程中包含入方向解码器和出方向编码器:当流量进入一个需要修复的低质量链路片段时,出方向编码器添加FEC冗余;当流量离开该链路片段时,入方向解码器根据收到的数据包和冗余包恢复丢包。对于不需要修复的链路片段,编码器和解码器退化为普通转发逻辑。
|
||||
|
||||
\section{设计挑战}
|
||||
|
||||
在“全公网承载、差链路修复”的总体目标下,系统设计需要进一步回答三个具体问题。首先,FEC机制必须能够插入通用覆盖网络转发路径,而不能改变用户报文本身的大小假设;其次,低质量公网链路的丢包程度会随时间变化,系统需要决定何时启用冗余以及使用多少冗余;最后,FEC解码按组恢复数据会改变报文交付节奏,如果不加处理,可能反过来干扰端系统的拥塞控制。由此,本文需要解决以下三个核心设计挑战。
|
||||
|
||||
\textbf{挑战一:如何在用户包大小可变的场景下设计链路片段级FEC编码方案。}
|
||||
系统作为通用转发平台,承载的上层应用可能产生任意大小的数据包。当用户数据包接近MTU时,若FEC编码产生的冗余信息追加在用户数据包内一同发送,则封装后的数据包可能超出MTU,导致IP层分片或传输失败。因此,FEC编码方案必须能够在不影响用户数据包大小的情况下独立添加冗余信息。同时,由于本文只在低质量公网片段上进行修复,编码方案还需要在单个链路片段上有效应对连续突发丢包,而不是依赖端到端重传。本文采用交织XOR分组编码方案应对此挑战(详见第\ref{sec:fec编码}节)。
|
||||
|
||||
\textbf{挑战二:如何判断差链路所需的冗余强度并自适应地选择编码参数。}
|
||||
全公网方案不能简单地对所有链路长期使用高冗余率,否则低成本公网节省下来的费用会被额外流量开销抵消。系统承载的应用中又包含实时音视频流媒体等对延迟敏感的业务,FEC编码引入的冗余包不仅占用额外带宽,也会引入解码等待延迟。因此,系统需要根据链路片段上的实时丢包统计,在丢包恢复能力、额外带宽开销和恢复延迟之间取得平衡。由于公网链路的丢包率与丢包模式随时间动态变化,固定的编码参数无法同时适应不同质量状态的链路。本文通过建立丢包信道模型并据此进行约束搜索来解决此挑战(详见第\ref{sec:参数调整}节)。
|
||||
|
||||
\textbf{挑战三:如何消除FEC解码按组突发输出对拥塞控制算法的干扰。}
|
||||
FEC解码器按编码组为单位批量恢复和交付数据包。当一个编码组恢复完成后,组内的所有数据包被一次性连续交付给上层应用。这种突发式的输出模式会使得上游的拥塞控制算法收到密集的ACK确认包,从而错误地估计链路可用带宽,引发发送速率的震荡。速率震荡不仅影响应用的传输性能,还会使FEC编码器的输入节奏不稳定,进一步干扰吞吐量统计和参数估计的准确性。本文在解码端设计了基于PI控制器的输出速率控制器来消除此问题(详见第\ref{sec:pacer}节)。
|
||||
|
||||
\section{交织XOR前向纠错编码设计}
|
||||
\label{sec:fec编码}
|
||||
|
||||
本节针对挑战一,介绍链路片段级交织FEC编码方案的设计。核心需求是:FEC冗余信息必须以独立包的形式发送,不嵌入用户数据包内部,从而避免影响用户数据包的大小;同时编码方案需能在低质量公网片段上有效应对连续突发丢包。
|
||||
% 本节针对挑战一,介绍链路片段级交织FEC编码方案的设计。核心需求是:FEC冗余信息必须以独立包的形式发送,不嵌入用户数据包内部,从而避免影响用户数据包的大小;同时编码方案需能在低质量公网片段上有效应对连续突发丢包。
|
||||
|
||||
由于覆盖网络中承载的流量种类多样,
|
||||
|
||||
如第二章所述,现有的前向纠错编码方案主要包括简单复制冗余、XOR码、R-S码以及流式编码等。本文选择基于XOR运算的分组编码结合交织技术作为FEC编码方案,其核心考量如下。
|
||||
|
||||
@@ -55,13 +56,15 @@ FEC解码器按编码组为单位批量恢复和交付数据包。当一个编
|
||||
|
||||
在多种分组码中,本文选择XOR编码而非R-S码,理由是结合交织技术的XOR编码已足以应对公网链路上观察到的丢包模式。根据第一章的分析,公网链路的主要丢包特征是偶发的孤立丢包和有限长度的连续突发丢包。交织技术将连续的突发丢包分散到不同的恢复列中,使得每列至多丢失一个数据包,恰好匹配XOR编码"每列可恢复一个丢包"的能力。同时,XOR编码的编码和解码均只需要按位异或运算,无需有限域上的矩阵运算,计算开销极低,适合高吞吐量的转发场景。
|
||||
|
||||
具体地,本文提出的交织FEC编码将数据包组织为一个二维矩阵结构,如图\ref{fig:交织编码矩阵}所示。设交织深度为$d$,保护包数为$k$,则每个编码组包含$d \times k$个数据包和$d$个冗余包。矩阵共有$d$列、$k+1$行,其中前$k$行为数据包,第$k+1$行为冗余包。每个数据包在矩阵中的位置由其组内序列号唯一确定:对于序列号为$s$的数据包,其所在列号为$s \bmod d$,行号为$\lfloor s / d \rfloor$。每个冗余包通过对同一列中所有数据包进行按位异或运算得到。交织技术的关键优势在于:当网络上发生长度不超过$d$的连续丢包时,由于相邻数据包被分配到不同的列中,这些丢失的数据包被分散到最多$d$个不同的列中,每个列至多丢失一个数据包,因此每个列都可以独立恢复。
|
||||
具体地,本文提出的交织FEC编码将数据包组织为一个二维矩阵结构,如图\ref{fig:交织编码矩阵}所示。设交织深度为$d$,保护包数为$k$,则每个编码组包含$d \times k$个数据包和$d$个冗余包。矩阵共有$d$列、$k+1$行,其中前$k$行为数据包,第$k+1$行为冗余包。每个数据包在矩阵中的位置由其组内序列号唯一确定:对于序列号为$s$的数据包,其所在列号为$s \bmod d$,行号为$\lfloor s / d \rfloor$。每个冗余包通过对同一列中所有数据包进行按位异或运算得到。交织技术的关键优势在于:当网络上发生长度不超过$d$的连续丢包时,由于相邻数据包被分配到不同的列中,这些丢失的数据包被分散到最多$d$个不同的列中,每个列至多丢失一个数据包,因此每个列都可以独立恢复。以图\ref{fig:交织编码矩阵}为例,当$d = 4$时,即使出现了连续四个丢包,由于四个丢包位于四个不同的编码组中(图中以虚线框标出),在每个编码组内部只有一个包丢失,因此接收端仍旧可以完全恢复所有的丢包内容。
|
||||
|
||||
\nomenclature{$d$}{交织FEC编码的交织深度}
|
||||
\nomenclature{$k$}{交织FEC编码中每列保护的数据包数}
|
||||
\nomenclature{$s$}{数据包在编码组内的序列号}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\fbox{\parbox{0.85\textwidth}{\centering\small\vspace{1.5em}%
|
||||
图片内容:交织编码矩阵示意。以$d=4, k=3$为例,矩阵为4列、4行(3行数据+1行冗余)。数据包标注为$D_{0,0}, D_{1,0}, D_{2,0}, D_{3,0}, D_{0,1}, D_{1,1}, \ldots, D_{3,2}$,冗余包标注为$F_0, F_1, F_2, F_3$。其中$F_j = D_{j,0} \oplus D_{j,1} \oplus D_{j,2}$。下方用箭头展示实际发送顺序:$D_{0,0}, D_{1,0}, D_{2,0}, D_{3,0}, D_{0,1}, D_{1,1}, \ldots, F_0, F_1, F_2, F_3$。右侧用虚线框标注一个连续丢包的例子:假设连续丢失$D_{1,0}$和$D_{2,0}$,由于交织深度$d=4$,两个丢包分别落在第1列和第2列,每列恰好只丢失一个包,各自可用$F_1$和$F_2$恢复。%
|
||||
\vspace{1.5em}}}
|
||||
\includegraphics[width=.7\linewidth]{fec_interleave_loss.drawio.pdf}
|
||||
\caption{交织编码矩阵结构示意($d=4, k=3$)}
|
||||
\label{fig:交织编码矩阵}
|
||||
\end{figure}
|
||||
@@ -71,17 +74,22 @@ FEC解码器按编码组为单位批量恢复和交付数据包。当一个编
|
||||
\section{基于丢包统计的自适应参数调整}
|
||||
\label{sec:参数调整}
|
||||
|
||||
本节针对挑战二,介绍如何根据实时丢包统计自适应地选择编码参数。如前所述,本文并不希望在所有公网链路上持续加入固定冗余,而是希望仅在差链路上使用足够但不过量的冗余。因此,FEC编码参数需要同时满足流媒体应用的延迟需求、控制额外带宽开销,并适应链路质量的动态变化。本文的解决思路是:首先为公网链路的丢包行为建立一个数学模型,然后从接收端的丢包观测量中估计模型参数,最后在延迟与残余丢包率的约束下搜索最优编码参数。
|
||||
由于不同公网链路的质量差距大,且单个链路的链路质量也会随着时间变化,本文希望仅在差链路上使用足够但不过量的冗余,以达成对公网链路的充分利用。因此,FEC编码参数需要同时满足多种应用的需求,既包括流媒体应用的延迟需求、也包括文件传输等应用的带宽需求、控制额外带宽开销,并适应链路质量的动态变化。本文的解决思路是:首先为公网链路的丢包行为建立一个数学模型,然后从接收端的丢包观测量中估计模型参数,最后在延迟与残余丢包率的约束下搜索最优编码参数。
|
||||
|
||||
\subsection{丢包信道模型}
|
||||
|
||||
根据第一章中对公网链路丢包特性的分析,公网链路上的丢包行为可以大致分为两类:一类是偶发的孤立丢包,丢失一个包后链路随即恢复正常;另一类是连续的突发丢包,由于链路拥塞等原因连续丢失多个数据包。基于这一观察,本文提出一个简化的三状态丢包信道模型,如图\ref{fig:三状态丢包模型}所示。模型定义三个状态:$S_0$(正常状态,当前数据包正常接收)、$S_1$(孤立丢包状态,丢失一个包后立即恢复)、$S_2$(突发丢包状态,连续丢失多个包)。模型通过三个参数$p_{21}$(孤立丢包触发概率)、$p_{23}$(突发丢包触发概率)和$p_{33}$(突发延续概率)完整描述链路的丢包行为。
|
||||
根据第一章中对公网链路丢包特性的分析,公网链路上的丢包行为可以大致分为两类:一类是偶发的孤立丢包,丢失一个包后链路随即恢复正常;另一类是连续的突发丢包,由于链路拥塞等原因连续丢失多个数据包。基于这一观察,本文提出一个简化的三状态丢包信道模型,如图\ref{fig:三状态丢包模型}所示。模型定义三个状态:$S_1$(孤立丢包状态,丢失一个包后立即恢复)、$S_2$(正常状态,当前数据包正常接收)、$S_3$(连续丢包状态,连续丢失多个包)。模型通过三个参数$p_{21}$(孤立丢包触发概率)、$p_{23}$(连续丢包触发概率)和$p_{33}$(突发延续概率)完整描述链路的丢包行为。
|
||||
|
||||
\nomenclature{$S_1$}{网络孤立丢包状态}
|
||||
\nomenclature{$S_2$}{网络正常状态}
|
||||
\nomenclature{$S_3$}{网络连续丢包状态}
|
||||
\nomenclature{$p_{21}$}{孤立丢包触发概率}
|
||||
\nomenclature{$p_{23}$}{连续丢包触发概率}
|
||||
\nomenclature{$p_{33}$}{突发延续概率}
|
||||
|
||||
\begin{figure}[htbp]
|
||||
\centering
|
||||
\fbox{\parbox{0.8\textwidth}{\centering\small\vspace{1.5em}%
|
||||
图片内容:三状态马尔科夫丢包模型状态转移图。三个状态:$S_0$(正常接收),$S_1$(孤立丢包),$S_2$(突发丢包)。转移概率标注。%
|
||||
\vspace{1.5em}}}
|
||||
\includegraphics[width=.6\linewidth]{markov_state.drawio.pdf}
|
||||
\caption{三状态丢包信道模型}
|
||||
\label{fig:三状态丢包模型}
|
||||
\end{figure}
|
||||
@@ -90,6 +98,8 @@ FEC解码器按编码组为单位批量恢复和交付数据包。当一个编
|
||||
|
||||
解码端通过全局序列号间隔检测丢包,维护一个滑动窗口统计近期的丢包事件,并将统计量定期上报至中心控制器。中心控制器收到统计量后,首先根据丢包事件的突发长度分布估计三状态模型的参数$p_{21}$、$p_{23}$和$p_{33}$,进而得到丢包事件的总发生率$\lambda = p_{21} + p_{23}$。
|
||||
|
||||
\nomenclature{$\lambda$}{丢包事件的总发生率}
|
||||
|
||||
在估计出模型参数后,中心控制器在给定的性能约束下搜索最优的编码参数$(d, k)$。算法考虑交织深度$d \in \{1, 2, 3, 4\}$的候选值,对于每个$d$,确定满足以下两个约束的最大保护包数$k$:
|
||||
|
||||
\begin{enumerate}
|
||||
@@ -113,10 +123,38 @@ FEC解码器按编码组为单位批量恢复和交付数据包。当一个编
|
||||
\label{fig:pacer控制模型}
|
||||
\end{figure}
|
||||
|
||||
Pacer的核心是一个基于缓冲区深度的PI(比例-积分)控制器。FEC解码器恢复后的数据包首先进入一个输出缓冲区,Pacer根据缓冲区的当前深度与目标深度的偏差计算出发包速率,并按照该速率匀速地从缓冲区中取出数据包交付给上层应用。比例项提供快速的瞬态响应:缓冲区超过目标时加快发包消耗积压,低于目标时减慢发包等待新数据。积分项消除稳态误差:即使数据包到达速率发生变化,积分项也能逐步学习新的稳态速率,确保缓冲区深度收敛到目标值。启动时,Pacer先以直通模式运行并测量实际的到达速率,待积累足够的观测后切换到PI控制模式,切换时将测量速率编码为积分项的初始值以实现平滑过渡。
|
||||
输出速率控制器的核心是一个基于缓冲区深度的PI(比例-积分)控制器。FEC解码器恢复后的数据包首先进入一个输出缓冲区,输出速率控制器根据缓冲区的当前深度与目标深度的偏差计算出发包速率,并按照该速率匀速地从缓冲区中取出数据包交付给上层应用。比例项提供快速的瞬态响应:缓冲区超过目标时加快发包消耗积压,低于目标时减慢发包等待新数据。积分项消除稳态误差:即使数据包到达速率发生变化,积分项也能逐步学习新的稳态速率,确保缓冲区深度收敛到目标值。启动时,输出速率控制器先以直通模式运行并测量实际的到达速率,待积累足够的观测后切换到PI控制模式,切换时将测量速率设置为积分项的初始值以实现平滑过渡。
|
||||
|
||||
Pacer与FEC编码的自适应参数调整形成了协同关系。Pacer将突发输出平滑为匀速流,使得CCA能够基于稳定的ACK反馈正确估计带宽,维持稳定的发送速率。稳定的发送速率使得FEC编码器以稳定的节奏填满编码组,进而使吞吐量统计值更加准确,提升了参数调整的准确性。
|
||||
\nomenclature{PI控制器}{比例-积分控制器}
|
||||
|
||||
具体来说,控制器内部维护一个目标缓冲区深度$h_0$,它是5个数据包的深度或是按当前释放速率计算\SI{5}{ms}能排空的缓冲区大小,取二者较大者。同时,控制器内部维护了一个积分值$I$,它在从直通模式切换至PI控制模式时初始化为在直通模式下估计的包到来速率。每次有数据包从缓冲区中释放时,控制器计算当前的缓冲区深度$h$与目标深度的差值:
|
||||
\begin{equation}
|
||||
\increment h = h - h_0
|
||||
\end{equation}
|
||||
同时记录自从上次释放数据包至当前时刻经历的时间$\increment t$,并由上一时刻的积分值$I_\text{prev}$计算新的积分值:
|
||||
\begin{equation}
|
||||
I = I_\text{prev} + \increment h \increment t
|
||||
\end{equation}
|
||||
进一步决定当前的输出速率$v$(以包/秒为单位):
|
||||
\begin{equation}
|
||||
v = K_p \increment h + K_i I
|
||||
\end{equation}
|
||||
其中$K_p$与$K_i$为可以调整的参数。
|
||||
|
||||
\nomenclature{$h_0$}{输出速率控制器目标缓冲区深度}
|
||||
\nomenclature{$h$}{输出速率控制器当前的缓冲区深度}
|
||||
\nomenclature{$\increment h$}{当前缓冲区深度与目标缓冲区深度的偏差}
|
||||
\nomenclature{$\increment t$}{相邻两次释放数据包之间的时间间隔}
|
||||
\nomenclature{$I$}{输出速率控制器内部维护的积分值}
|
||||
\nomenclature{$I_\text{prev}$}{输出速率控制器上一时刻的积分值}
|
||||
\nomenclature{$v$}{输出速率控制器计算得到的数据包释放速率}
|
||||
\nomenclature{$K_p$}{PI控制器的比例系数}
|
||||
\nomenclature{$K_i$}{PI控制器的积分系数}
|
||||
|
||||
在稳态时,缓冲区中的包到来速度与释放速度相等,缓冲区的长度始终稳定在$h_0$附近,$\increment h$接近0,包的输出速度由稳定的$I$决定;当包的到来速度增长时,包从缓冲的释放速度低于包的到来速度增长,缓冲的长度开始增长,长度超过$h$,使得$\increment h$为正,进而使得$I$增长。这共同使得$v$提升以跟随包到来速度的增长。当包到来速度下降时,类似的机制促使$v$也跟随下降,直到输出速率再次达到平衡。通过此设计,包的从缓冲区的离开速率总能匹配包到来的平均速率。
|
||||
|
||||
输出速率控制器与FEC编码的自适应参数调整形成了协同关系。输出速率控制器将突发输出平滑为匀速流,使得拥塞控制算法能够基于稳定的ACK反馈正确估计带宽,维持稳定的发送速率。稳定的发送速率使得FEC编码器以稳定的节奏填满编码组,进而使吞吐量统计值更加准确,提升了参数调整的准确性。
|
||||
|
||||
\section{本章小结}
|
||||
|
||||
本章围绕“全公网承载、差链路修复”的总体思路,介绍了本文提出的跨域公网链路传输优化方法。首先明确了本文不依赖专线兜底,而是在公网覆盖网络中针对低质量链路片段进行FEC修复;随后介绍了集中控制、分布转发的系统总体架构,并将总体目标细化为三个设计挑战。针对通用转发场景下可变包大小与MTU约束的挑战,本文选择了交织XOR分组编码方案,冗余包作为独立包发送不影响用户数据包大小,交织技术则将连续丢包分散到不同的恢复列中。针对满足实时应用延迟需求的同时自适应选择编码参数的挑战,本文提出了三状态丢包信道模型,介绍了从丢包观测量估计模型参数以及在延迟与残余丢包率约束下搜索最优编码参数的方法。最后,针对FEC解码突发输出干扰拥塞控制算法的挑战,本文设计了解码端PI速率控制器,将突发输出平滑为匀速流,并与FEC参数调整机制形成协同。
|
||||
本章围绕全公网互联、差分片修复的总体思路,介绍了本文提出的跨域公网链路传输优化方法。首先明确了本文不依赖专线互联,而是在公网覆盖网络中针对低质量链路片段进行FEC修复;随后介绍了集中控制、分布转发的系统总体架构,并将总体目标细化为三个设计挑战。针对通用转发场景下可变包大小与MTU约束的挑战,本文选择了交织XOR分组编码方案,冗余包作为独立包发送不影响用户数据包大小,交织技术则将连续丢包分散到不同的恢复列中。针对满足实时应用延迟需求的同时自适应选择编码参数的挑战,本文提出了三状态丢包信道模型,介绍了从丢包观测量估计模型参数以及在延迟与残余丢包率约束下搜索最优编码参数的方法。最后,针对FEC解码突发输出干扰拥塞控制算法的挑战,本文设计了解码端PI速率控制器,将突发输出平滑为匀速流,并与FEC参数调整机制形成协同。
|
||||
|
||||
@@ -1,4 +1,45 @@
|
||||
% !TEX root = ../bachelor-thesis.tex
|
||||
|
||||
\chapter{实验验证与分析}
|
||||
\label{chap:实验验证与分析}
|
||||
|
||||
本章主要介绍系统的实现情况及实验结果。\ref{sec:试验环境}节介绍本文提出的设计方案的实现情况及实验环境与实验设置等基本信息,\ref{sec:实验结果}节展示了实验结果,并对其进行了简要的分析。
|
||||
|
||||
\section{实验环境}
|
||||
\label{sec:实验环境}
|
||||
|
||||
本文作者使用Rust语言实现了设计的分布式转发与控制系统,实现了动态FEC编解码、丢包统计及参数自动计算等所有核心设计要点。本文实验在一台配备两颗Intel Xeon E5-2620 v3处理器的服务器上进行,整机共提供12个物理核心、24个逻辑CPU。服务器共搭载\SI{64}{GiB}运行内存。本文中的实验使用Rattan\cite{wang2025rattan}对网络上的丢包,延迟及带宽限速进行模拟。在实验中,多台不同的虚拟机通过虚拟交换机互联,并在每台虚拟机的虚拟出口使用Rattan对网络流量进行处理,以达成对链路延迟、丢包带宽等不同性质的模拟。如图\ref{fig:实验拓扑},在实验中,共使用三台虚拟机(记作A,B,C)作为转发以及用户接入客户端,使用另外一台虚拟机作为控制器。利用控制器建立A经由B到达C的链路,其中AB间的链路为模拟低质量链路,存在丢包,往返时延\SI{50}{ms};BC间的链路为模拟高质量链路,为不丢包的链路,往返时延\SI{50}{ms}。两条链路的带宽均为\SI{100}{Mbps}。通过调整AB间链路的丢包率并测量AC之间的传输性能,可以测量本文提出的方法与直接进行转发的基准方案的性能,并进行对比。
|
||||
|
||||
实验时,分别选取丢包率取从0至2\%的不同值,分别使用本文提出的动态链路优化算法与直接进行转发的方法在A、C间使用iperf3进行测速,持续\SI{60}{s},并记录收端的接收速率。
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\includegraphics[width=.8\linewidth]{exp_topology.drawio.pdf}
|
||||
\caption{实验建立的网络拓扑}
|
||||
\label{fig:实验拓扑}
|
||||
\end{figure}
|
||||
|
||||
\section{实验结果与分析}
|
||||
\label{sec:实验结果}
|
||||
|
||||
实验结果如图\ref{fig:实验结果图}所示。图\ref{fig:吞吐绝对值}展示了不同丢包率下两种方法的端到端吞吐量,图\ref{fig:吞吐相对提升}展示了本文方法相对于直接转发基准方案的吞吐提升程度。
|
||||
|
||||
\begin{figure}[H]
|
||||
\centering
|
||||
\subcaptionbox{不同丢包率下的端到端吞吐量\label{fig:吞吐绝对值}}
|
||||
{\includegraphics[width=0.48\linewidth]{thpt_absolute.pdf}}
|
||||
\hspace{0.02\linewidth}
|
||||
\subcaptionbox{相对于基准方案的吞吐提升\label{fig:吞吐相对提升}}
|
||||
{\includegraphics[width=0.48\linewidth]{thpt_speedup.pdf}}
|
||||
\caption{不同丢包率下本文方法的吞吐性能提升}
|
||||
\label{fig:实验结果图}
|
||||
\end{figure}
|
||||
|
||||
与基线方法相比,本文方法在较高丢包率下仍旧保持了较高的总体带宽,并达到了最高3.6倍带宽提升。通过查阅控制器日志可以发现,本方法正确识别了两条链路中的不同丢包率,并在丢包严重的AB段链路上启用了FEC,在没有丢包的链路上则始终使用普通转发。
|
||||
|
||||
尽管本方法使用了FEC方法对链路丢包进行了恢复,并有效提升了整体吞吐量,但是相比无丢包时仍旧有较大的吞吐性能差距。这一方面是由于添加冗余信息占用了一部分带宽,导致理想状态下应用可用的带宽下降;另一方面是由于由于冗余参数的选取较为保守,即使添加了FEC也有一定概率会出现丢包,导致发送端仍旧不能保证没有丢包发生,这些丢包会导致发送端丢包降低发送速率。最终,冗余带宽占用和残余丢包两种因素叠加导致即使使用了本方法,传输速率仍旧有所下降。
|
||||
|
||||
值得注意的是,虽然从本方法的吞吐量从无丢包至有丢包有较大下降,但是随着丢包率的增高,吞吐量的下降程度明显小于直接转发行为,这是由于本方法的动态FEC参数决定算法动态根据测量得到的丢包率参数决定了合适的冗余度,从而有效地将修复后的丢包率维持在较为固定的范围内,因而尽管底层链路的丢包率持续恶化,但是上层TCP连接感知的丢包率却始终稳定,使得最终的吞吐量也稳定在较为稳定的范围内。
|
||||
|
||||
在丢包率为零的场景下,使用直接转发能达到比使用本方法略高的性能,这主要是由于本方法所使用的FEC算法在不启用冗余时也仍旧需要在数据包中传输少量额外的包头,导致吞吐量相比直接转发有大约1\%的下降,相比于存在丢包场景下的性能提升较小。
|
||||
|
||||
|
||||
22
data/chap06.tex
Normal file
22
data/chap06.tex
Normal file
@@ -0,0 +1,22 @@
|
||||
% !TEX root = ../bachelor-thesis.tex
|
||||
|
||||
\chapter{结论与展望}
|
||||
\label{chap:结论与展望}
|
||||
|
||||
\section{工作总结}
|
||||
|
||||
随着云计算和实时互联网应用的发展,跨地域覆盖网络需要在全球范围内为用户提供稳定的低延迟、高带宽和低丢包传输服务。传统方案通常依赖专线链路保证服务质量,但专线链路价格较高,难以满足大规模跨域覆盖网络的成本优化需求。已有链路调度类方法尝试在公网质量较好时将部分流量迁移至公网链路,以降低专线链路上的承载流量;已有冗余编码类方法则通过端到端前向纠错编码缓解网络丢包对应用体验的影响。然而,本文的测量和分析表明,公网链路质量下降时段往往与用户流量高峰重合,使得基于公网分流的调度方法难以有效削减专线峰值成本;同时,跨域覆盖网络中不同公网链路片段质量差异显著,端到端统一添加冗余会在质量良好的片段上引入不必要的带宽开销。
|
||||
|
||||
针对上述问题,本文提出了一种面向跨域公网链路的分段质量修复方法。本文方法不再依赖专线链路作为后备方案,而是在全公网互联的覆盖网络中识别和修复低质量链路片段。对于质量良好的链路片段,系统保持普通转发,以避免额外开销;对于丢包率较高、存在连续突发丢包的链路片段,系统在片段两端加入前向纠错编码与丢包恢复机制,从而将质量修复限制在真正发生问题的网络范围内。该思路充分利用了覆盖网络中间节点可控、路径可分段的特点,在降低链路成本的同时提升公网链路的有效传输质量。
|
||||
|
||||
围绕这一思路,本文设计并实现了一套分布式覆盖网络转发与链路优化系统。系统采用中心控制器和分布式转发节点相结合的架构,由控制器维护连接状态、下发转发表项并计算FEC参数,由转发节点执行普通转发、FEC编码和FEC解码。为适应通用覆盖网络中用户包大小可变的特点,本文设计了交织XOR分组编码方案,使冗余包以独立数据包形式发送,避免修改用户报文内容;为适应公网链路质量的动态变化,本文建立三状态丢包信道模型,并根据接收端上报的丢包统计动态选择交织深度和保护包数;为避免FEC解码按组恢复造成突发输出,本文进一步设计了基于PI控制器的输出速率控制机制,使解码后的数据包以更平滑的节奏交付给上层传输协议。
|
||||
|
||||
最后,本文使用Rust语言实现了上述系统,并在模拟跨域低质量链路的实验环境中对本文方法进行了验证。实验结果表明,在0至2\%的链路丢包率范围内,本文方法能够正确识别低质量链路片段并在该片段启用FEC修复,在无丢包链路片段上保持普通转发。与直接转发方案相比,本文方法在存在丢包时显著提升了端到端吞吐量,最高实现了约3.6倍的吞吐提升。实验也表明,本文方法在无丢包场景下仅引入较小的额外开销,而在低质量公网链路场景下能够有效缓解丢包对传输性能的影响,验证了分段链路质量修复思路的有效性。
|
||||
|
||||
\section{未来工作展望}
|
||||
|
||||
本文提出的分段链路质量修复方法为全公网覆盖网络提供了一种降低专线依赖、提升跨域传输质量的思路,但仍有若干方向值得进一步研究。
|
||||
|
||||
首先,可以进一步优化FEC参数选择算法。本文当前的参数调整方法基于接收端上报的丢包统计估计链路丢包模型,并在延迟约束和残余丢包率约束下选择编码参数。后续工作可以引入更精细的链路状态建模方法,进一步区分孤立丢包、短突发丢包和长突发丢包等不同模式,并结合在线反馈机制持续修正模型参数。通过更准确地匹配链路的实际丢包特征,系统可以在不显著增加冗余开销的前提下进一步降低FEC恢复失败的概率,从而提高修复后链路质量的稳定性。
|
||||
|
||||
其次,可以在链路片段层面引入轻量级重传机制。FEC能够在不等待端到端反馈的情况下恢复大部分丢包,但在丢包模式超出当前编码参数保护能力时,仍可能出现少量残余丢包。由于本文系统将修复逻辑部署在相邻覆盖网络节点之间,链路片段的往返时延通常显著小于完整端到端路径的往返时延。因此,未来可以在FEC恢复之后,针对剩余的少量未恢复数据包触发链路级快速重传,以较短的链路局部反馈时延补充FEC的恢复能力。FEC与链路级重传相结合,有望在保持较低恢复延迟的同时进一步降低应用层感知到的残余丢包率。
|
||||
53
figures/exp_topology.drawio
Normal file
53
figures/exp_topology.drawio
Normal file
@@ -0,0 +1,53 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram name="Page-1" id="7wZgc77_SXIyXctfrDvy">
|
||||
<mxGraphModel dx="585" dy="353" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-6" edge="1" parent="1" source="ZMe2w7RPpOyb1yNfWZde-1" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;endArrow=none;endFill=0;" target="ZMe2w7RPpOyb1yNfWZde-5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-1" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="A" vertex="1">
|
||||
<mxGeometry height="30" width="50" x="80" y="450" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-7" edge="1" parent="1" source="ZMe2w7RPpOyb1yNfWZde-2" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;endArrow=none;endFill=0;dashed=1;" target="ZMe2w7RPpOyb1yNfWZde-5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-2" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="B" vertex="1">
|
||||
<mxGeometry height="30" width="50" x="240" y="450" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-8" edge="1" parent="1" source="ZMe2w7RPpOyb1yNfWZde-3" style="rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;dashed=1;endArrow=none;endFill=0;" target="ZMe2w7RPpOyb1yNfWZde-5">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-3" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="C" vertex="1">
|
||||
<mxGeometry height="30" width="50" x="390" y="450" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-5" parent="1" style="rounded=1;whiteSpace=wrap;html=1;" value="控制器" vertex="1">
|
||||
<mxGeometry height="30" width="50" x="240" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-9" edge="1" parent="1" source="ZMe2w7RPpOyb1yNfWZde-1" style="endArrow=classic;startArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="ZMe2w7RPpOyb1yNfWZde-2" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="370" y="510" as="sourcePoint" />
|
||||
<mxPoint x="420" y="460" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-11" connectable="0" parent="ZMe2w7RPpOyb1yNfWZde-9" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="可变丢包率<div>50ms RTT</div><div>100Mbps</div>" vertex="1">
|
||||
<mxGeometry relative="1" x="0.0136" y="-2" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-12" edge="1" parent="1" source="ZMe2w7RPpOyb1yNfWZde-2" style="endArrow=classic;startArrow=classic;html=1;rounded=0;exitX=1;exitY=0.5;exitDx=0;exitDy=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="ZMe2w7RPpOyb1yNfWZde-3" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="300" y="450" as="sourcePoint" />
|
||||
<mxPoint x="350" y="400" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="ZMe2w7RPpOyb1yNfWZde-13" connectable="0" parent="ZMe2w7RPpOyb1yNfWZde-12" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" value="无丢包<div>50ms RTT</div><div>100Mbps</div>" vertex="1">
|
||||
<mxGeometry relative="1" x="-0.0524" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
BIN
figures/exp_topology.drawio.pdf
Normal file
BIN
figures/exp_topology.drawio.pdf
Normal file
Binary file not shown.
4
figures/exp_topology.drawio.svg
Normal file
4
figures/exp_topology.drawio.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 58 KiB |
152
figures/fec_interleave_loss.drawio
Normal file
152
figures/fec_interleave_loss.drawio
Normal file
@@ -0,0 +1,152 @@
|
||||
<mxfile host="app.diagrams.net">
|
||||
<diagram name="Page-1" id="BJGi_sJl8OPZm2VTFhUz">
|
||||
<mxGraphModel dx="730" dy="560" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-1" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" value="" vertex="1">
|
||||
<mxGeometry height="240" width="60" x="470.24" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-2" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" value="" vertex="1">
|
||||
<mxGeometry height="240" width="60" x="400.24" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-3" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" value="" vertex="1">
|
||||
<mxGeometry height="240" width="60" x="330.24" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-4" parent="1" style="rounded=1;whiteSpace=wrap;html=1;fillColor=none;dashed=1;" value="" vertex="1">
|
||||
<mxGeometry height="240" width="60" x="260.24" y="170" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-5" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="270.24" y="380" as="sourcePoint" />
|
||||
<mxPoint x="550.24" y="380" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-6" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="270.24" y="319.96" as="sourcePoint" />
|
||||
<mxPoint x="540.24" y="319.76" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-7" edge="1" parent="1" source="cUlYKNuvSnXqOs2f7q_A-13" style="endArrow=classic;html=1;rounded=0;exitX=0;exitY=0.5;exitDx=0;exitDy=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="250.24" y="259.8" as="sourcePoint" />
|
||||
<mxPoint x="540.24" y="259.8" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-8" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="250.24" y="200" as="sourcePoint" />
|
||||
<mxPoint x="540.24" y="200" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-9" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="1" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="270.24" y="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-10" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="2" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="340.24" y="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-11" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#f8cecc;strokeColor=#b85450;" value="3" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="410.24" y="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-12" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#f8cecc;strokeColor=#b85450;" value="4" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="480.24" y="180" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-13" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#f8cecc;strokeColor=#b85450;" value="5" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="270.24" y="240" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-14" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#f8cecc;strokeColor=#b85450;" value="6" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="340.24" y="240" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-15" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="7" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="410.24" y="240" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-16" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="8" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="480.24" y="240" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-17" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="9" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="270.24" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-18" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="10" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="340.24" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-19" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="11" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="410.24" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-20" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=18;fillColor=#dae8fc;strokeColor=#6c8ebf;" value="12" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="480.24" y="300" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-21" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#d5e8d4;strokeColor=#82b366;" value="FEC 1" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="270.24" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-22" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#d5e8d4;strokeColor=#82b366;" value="FEC 2" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="340.24" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-23" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#d5e8d4;strokeColor=#82b366;" value="FEC 3" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="410.24" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-24" parent="1" style="rounded=0;whiteSpace=wrap;html=1;fontSize=16;fillColor=#d5e8d4;strokeColor=#82b366;" value="FEC 4" vertex="1">
|
||||
<mxGeometry height="40" width="40" x="480.24" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-25" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" target="cUlYKNuvSnXqOs2f7q_A-13" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="540.24" y="230" />
|
||||
<mxPoint x="250.24" y="230" />
|
||||
<mxPoint x="250.24" y="260" />
|
||||
</Array>
|
||||
<mxPoint x="540.24" y="200" as="sourcePoint" />
|
||||
<mxPoint x="250.24" y="260" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-26" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="540.24" y="290" />
|
||||
<mxPoint x="250.24" y="290" />
|
||||
<mxPoint x="250.24" y="320" />
|
||||
</Array>
|
||||
<mxPoint x="540.24" y="260" as="sourcePoint" />
|
||||
<mxPoint x="270.24" y="320" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-27" edge="1" parent="1" style="endArrow=classic;html=1;rounded=0;entryX=0;entryY=0.5;entryDx=0;entryDy=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="540.24" y="350" />
|
||||
<mxPoint x="250.24" y="350" />
|
||||
<mxPoint x="250.24" y="380" />
|
||||
</Array>
|
||||
<mxPoint x="540.24" y="320" as="sourcePoint" />
|
||||
<mxPoint x="270.24" y="380" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-28" parent="1" style="text;html=1;whiteSpace=wrap;strokeColor=none;fillColor=none;align=center;verticalAlign=middle;rounded=0;fontSize=14;textDirection=vertical-rl;" value="<font face="Microsoft YaHei">发送顺序</font>" vertex="1">
|
||||
<mxGeometry height="65" width="30" x="220.24" y="167.5" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-29" edge="1" parent="1" style="endArrow=classic;startArrow=classic;html=1;rounded=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="270.24" y="150" as="sourcePoint" />
|
||||
<mxPoint x="520.24" y="150" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-30" connectable="0" parent="cUlYKNuvSnXqOs2f7q_A-29" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];fontSize=14;" value="<font face="Microsoft YaHei">交织间隔</font> <i><font face="Times New Roman">d&nbsp;</font></i>" vertex="1">
|
||||
<mxGeometry relative="1" x="-0.0556" y="2" as="geometry">
|
||||
<mxPoint as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-31" edge="1" parent="1" style="endArrow=classic;startArrow=classic;html=1;rounded=0;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="220.24" y="180" as="sourcePoint" />
|
||||
<mxPoint x="220.24" y="340" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="cUlYKNuvSnXqOs2f7q_A-32" connectable="0" parent="cUlYKNuvSnXqOs2f7q_A-31" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];textDirection=vertical-rl;fontSize=14;" value="<font face="Microsoft YaHei">保护包数 </font><font face="Times New Roman"><i>k&nbsp;</i></font>" vertex="1">
|
||||
<mxGeometry relative="1" x="-0.0556" y="2" as="geometry">
|
||||
<mxPoint x="-7" y="-5" as="offset" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
BIN
figures/fec_interleave_loss.drawio.pdf
Normal file
BIN
figures/fec_interleave_loss.drawio.pdf
Normal file
Binary file not shown.
4
figures/fec_interleave_loss.drawio.svg
Normal file
4
figures/fec_interleave_loss.drawio.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 123 KiB |
Binary file not shown.
82
figures/markov_state.drawio
Normal file
82
figures/markov_state.drawio
Normal file
@@ -0,0 +1,82 @@
|
||||
<mxfile host="app.diagrams.net" agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36">
|
||||
<diagram name="Page-1" id="BU0is68rKEliDe_wEZyr">
|
||||
<mxGraphModel dx="604" dy="463" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="827" pageHeight="1169" math="0" shadow="0">
|
||||
<root>
|
||||
<mxCell id="0" />
|
||||
<mxCell id="1" parent="0" />
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-15" edge="1" parent="1" source="iF11OQuIZuo1F6IyOmSl-1" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=0;exitDx=0;exitDy=0;entryX=0.4;entryY=0.008;entryDx=0;entryDy=0;curved=1;entryPerimeter=0;" target="iF11OQuIZuo1F6IyOmSl-2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-1" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="<span style="font-size: 20px;">S1</span><br><div><font face="Microsoft YaHei" style="font-size: 16px;">孤立丢包</font></div>" vertex="1">
|
||||
<mxGeometry height="80" width="80" x="390" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-16" edge="1" parent="1" source="iF11OQuIZuo1F6IyOmSl-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.44;exitY=0.993;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;curved=1;exitPerimeter=0;" target="iF11OQuIZuo1F6IyOmSl-1">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-2" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="<span style="font-size: 20px;">S2</span><div><font face="Microsoft YaHei" style="font-size: 16px;">正常传输</font></div>" vertex="1">
|
||||
<mxGeometry height="80" width="80" x="480" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-14" edge="1" parent="1" source="iF11OQuIZuo1F6IyOmSl-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=0.5;exitY=1;exitDx=0;exitDy=0;entryX=0.5;entryY=1;entryDx=0;entryDy=0;curved=1;" target="iF11OQuIZuo1F6IyOmSl-2">
|
||||
<mxGeometry relative="1" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-3" parent="1" style="ellipse;whiteSpace=wrap;html=1;aspect=fixed;" value="<span style="font-size: 20px;">S3</span><div><font face="Microsoft YaHei" style="font-size: 16px;">连续丢包</font></div>" vertex="1">
|
||||
<mxGeometry height="80" width="80" x="620" y="360" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-9" edge="1" parent="1" style="endArrow=none;dashed=1;html=1;rounded=0;strokeWidth=1;" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<mxPoint x="610" y="500" as="sourcePoint" />
|
||||
<mxPoint x="610" y="300" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-10" edge="1" parent="1" source="iF11OQuIZuo1F6IyOmSl-3" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=1;entryDx=0;entryDy=0;elbow=vertical;curved=1;" target="iF11OQuIZuo1F6IyOmSl-3">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="688" y="360" />
|
||||
<mxPoint x="720" y="360" />
|
||||
<mxPoint x="720" y="440" />
|
||||
<mxPoint x="688" y="440" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-18" edge="1" parent="1" source="iF11OQuIZuo1F6IyOmSl-2" style="endArrow=classic;html=1;rounded=0;exitX=0.616;exitY=0.003;exitDx=0;exitDy=0;exitPerimeter=0;entryX=0.4;entryY=0.003;entryDx=0;entryDy=0;edgeStyle=orthogonalEdgeStyle;curved=1;entryPerimeter=0;" target="iF11OQuIZuo1F6IyOmSl-3" value="">
|
||||
<mxGeometry height="50" relative="1" width="50" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="529" y="340" />
|
||||
<mxPoint x="652" y="340" />
|
||||
</Array>
|
||||
<mxPoint x="490" y="430" as="sourcePoint" />
|
||||
<mxPoint x="540" y="380" as="targetPoint" />
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-19" edge="1" parent="1" source="iF11OQuIZuo1F6IyOmSl-2" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;exitX=1;exitY=0;exitDx=0;exitDy=0;entryX=1;entryY=1;entryDx=0;entryDy=0;curved=1;" target="iF11OQuIZuo1F6IyOmSl-2">
|
||||
<mxGeometry relative="1" as="geometry">
|
||||
<Array as="points">
|
||||
<mxPoint x="548" y="360" />
|
||||
<mxPoint x="580" y="360" />
|
||||
<mxPoint x="580" y="440" />
|
||||
<mxPoint x="548" y="440" />
|
||||
</Array>
|
||||
</mxGeometry>
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-21" parent="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" value="<font style="font-size: 18px;">p23</font>" vertex="1">
|
||||
<mxGeometry height="30" width="60" x="560" y="316" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-23" parent="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" value="<font style="font-size: 18px;">p22</font>" vertex="1">
|
||||
<mxGeometry height="30" width="60" x="560" y="340" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-24" parent="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" value="<font style="font-size: 18px;">p32</font>" vertex="1">
|
||||
<mxGeometry height="30" width="60" x="560" y="437" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-25" parent="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" value="<font style="font-size: 18px;">p33</font>" vertex="1">
|
||||
<mxGeometry height="30" width="60" x="710" y="385" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-26" parent="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" value="<font style="font-size: 18px;">1</font>" vertex="1">
|
||||
<mxGeometry height="30" width="60" x="439" y="317" as="geometry" />
|
||||
</mxCell>
|
||||
<mxCell id="iF11OQuIZuo1F6IyOmSl-27" parent="1" style="text;html=1;align=center;verticalAlign=middle;whiteSpace=wrap;rounded=0;" value="<font style="font-size: 18px;">p21</font>" vertex="1">
|
||||
<mxGeometry height="30" width="60" x="440" y="437" as="geometry" />
|
||||
</mxCell>
|
||||
</root>
|
||||
</mxGraphModel>
|
||||
</diagram>
|
||||
</mxfile>
|
||||
BIN
figures/markov_state.drawio.pdf
Normal file
BIN
figures/markov_state.drawio.pdf
Normal file
Binary file not shown.
4
figures/markov_state.drawio.svg
Normal file
4
figures/markov_state.drawio.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 91 KiB |
1
figures/pacer_design.drawio
Normal file
1
figures/pacer_design.drawio
Normal file
@@ -0,0 +1 @@
|
||||
<mxGraphModel><root><mxCell id="0"/><mxCell id="1" parent="0"/></root></mxGraphModel>
|
||||
BIN
figures/thpt_absolute.pdf
Normal file
BIN
figures/thpt_absolute.pdf
Normal file
Binary file not shown.
BIN
figures/thpt_speedup.pdf
Normal file
BIN
figures/thpt_speedup.pdf
Normal file
Binary file not shown.
10
ref/refs.bib
10
ref/refs.bib
@@ -430,3 +430,13 @@
|
||||
year={2022},
|
||||
publisher={IEEE}
|
||||
}
|
||||
|
||||
@misc{wang2025rattan,
|
||||
title={Rattan: An Extensible and Scalable Modular Internet Path Emulator},
|
||||
author={Minhu Wang and Yixin Shen and Bo Wang and Haixuan Tong and Yutong Xie and Yixuan Gao and Yan Liu and Li Chen and Mingwei Xu and Jianping Wu},
|
||||
year={2025},
|
||||
eprint={2507.08134},
|
||||
archivePrefix={arXiv},
|
||||
primaryClass={cs.NI},
|
||||
url={https://arxiv.org/abs/2507.08134},
|
||||
}
|
||||
@@ -13,6 +13,8 @@ from matplotlib.lines import Line2D
|
||||
OVERSEAS_CITIES = {"迪拜", "法兰克福", "雅加达", "开普敦"}
|
||||
OVERSEAS_COLOR = "#4285F4"
|
||||
DOMESTIC_COLOR = "#EA4335"
|
||||
BASE_FONT_SIZE = 20
|
||||
CELL_FONT_SIZE = BASE_FONT_SIZE - 5
|
||||
|
||||
|
||||
def leading_group_size(labels: list[str], group: set[str]) -> int:
|
||||
@@ -43,11 +45,11 @@ def configure_fonts() -> None:
|
||||
plt.rcParams["axes.unicode_minus"] = False
|
||||
plt.rcParams.update(
|
||||
{
|
||||
"font.size": 15,
|
||||
"axes.titlesize": 19,
|
||||
"axes.labelsize": 17,
|
||||
"xtick.labelsize": 15,
|
||||
"ytick.labelsize": 15,
|
||||
"font.size": BASE_FONT_SIZE,
|
||||
"axes.titlesize": BASE_FONT_SIZE + 4,
|
||||
"axes.labelsize": BASE_FONT_SIZE + 2,
|
||||
"xtick.labelsize": BASE_FONT_SIZE,
|
||||
"ytick.labelsize": BASE_FONT_SIZE,
|
||||
"figure.dpi": 150,
|
||||
}
|
||||
)
|
||||
@@ -114,7 +116,7 @@ def plot_heatmap(csv_path: Path, output_path: Path) -> None:
|
||||
ax.legend(
|
||||
handles=legend_handles,
|
||||
loc="lower center",
|
||||
bbox_to_anchor=(0.5, 1.15),
|
||||
bbox_to_anchor=(0.5, 1.2),
|
||||
ncol=2,
|
||||
frameon=False,
|
||||
columnspacing=1.4,
|
||||
@@ -130,7 +132,7 @@ def plot_heatmap(csv_path: Path, output_path: Path) -> None:
|
||||
value = float(matrix[row_index, col_index])
|
||||
text = "0" if value == 0 else f"{value:.2f}".rstrip("0").rstrip(".")
|
||||
color = "white" if value > 0.55 * vmax else "#222222"
|
||||
ax.text(col_index, row_index, text, ha="center", va="center", color=color, fontsize=11)
|
||||
ax.text(col_index, row_index, text, ha="center", va="center", color=color, fontsize=CELL_FONT_SIZE)
|
||||
|
||||
sender_split = leading_group_size(senders, OVERSEAS_CITIES)
|
||||
receiver_split = leading_group_size(receivers, OVERSEAS_CITIES)
|
||||
@@ -144,8 +146,8 @@ def plot_heatmap(csv_path: Path, output_path: Path) -> None:
|
||||
ax.tick_params(which="minor", bottom=False, left=False)
|
||||
|
||||
colorbar = fig.colorbar(image, ax=ax, shrink=0.88)
|
||||
colorbar.set_label("平均丢包率", fontsize=14)
|
||||
colorbar.ax.tick_params(labelsize=12)
|
||||
colorbar.set_label("平均丢包率", fontsize=BASE_FONT_SIZE)
|
||||
colorbar.ax.tick_params(labelsize=BASE_FONT_SIZE)
|
||||
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
fig.savefig(output_path, bbox_inches="tight")
|
||||
|
||||
163
scripts/plot_thpt.py
Normal file
163
scripts/plot_thpt.py
Normal file
@@ -0,0 +1,163 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
from matplotlib import font_manager
|
||||
|
||||
|
||||
BASE_FONT_SIZE = 25
|
||||
TITLE_FONT_SIZE = BASE_FONT_SIZE + 1
|
||||
AXIS_LABEL_FONT_SIZE = BASE_FONT_SIZE
|
||||
TICK_FONT_SIZE = BASE_FONT_SIZE - 2
|
||||
LEGEND_FONT_SIZE = BASE_FONT_SIZE - 2
|
||||
BAR_LABEL_FONT_SIZE = BASE_FONT_SIZE - 4
|
||||
MAX_LOSS = 0.02
|
||||
|
||||
|
||||
def configure_fonts() -> None:
|
||||
preferred_fonts = [
|
||||
"Microsoft YaHei",
|
||||
"SimHei",
|
||||
"Noto Sans CJK SC",
|
||||
"Source Han Sans SC",
|
||||
"PingFang SC",
|
||||
"WenQuanYi Micro Hei",
|
||||
"Arial Unicode MS",
|
||||
]
|
||||
installed_fonts = {font.name for font in font_manager.fontManager.ttflist}
|
||||
for font in preferred_fonts:
|
||||
if font in installed_fonts:
|
||||
plt.rcParams["font.sans-serif"] = [font]
|
||||
break
|
||||
plt.rcParams["axes.unicode_minus"] = False
|
||||
plt.rcParams.update(
|
||||
{
|
||||
"font.size": BASE_FONT_SIZE,
|
||||
"axes.titlesize": TITLE_FONT_SIZE,
|
||||
"axes.labelsize": AXIS_LABEL_FONT_SIZE,
|
||||
"xtick.labelsize": TICK_FONT_SIZE,
|
||||
"ytick.labelsize": TICK_FONT_SIZE,
|
||||
"legend.fontsize": LEGEND_FONT_SIZE,
|
||||
"figure.dpi": 150,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def read_throughput(csv_path: Path) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
||||
losses: list[float] = []
|
||||
cubic: list[float] = []
|
||||
fec: list[float] = []
|
||||
|
||||
with csv_path.open("r", encoding="utf-8-sig", newline="") as file:
|
||||
reader = csv.DictReader(file)
|
||||
for row in reader:
|
||||
losses.append(float(row["loss"]))
|
||||
cubic.append(float(row["cubic_thpt_mbps"]))
|
||||
fec.append(float(row["fec_thpt_mbps"]))
|
||||
|
||||
return np.array(losses), np.array(cubic), np.array(fec)
|
||||
|
||||
|
||||
def format_loss_label(loss: float) -> str:
|
||||
if loss == 0:
|
||||
return "0"
|
||||
percent = loss * 100
|
||||
return f"{percent:g}%"
|
||||
|
||||
|
||||
def filter_results(
|
||||
losses: np.ndarray,
|
||||
cubic: np.ndarray,
|
||||
fec: np.ndarray,
|
||||
) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
||||
keep = losses <= MAX_LOSS
|
||||
return losses[keep], cubic[keep], fec[keep]
|
||||
|
||||
|
||||
def plot_absolute_throughput(losses: np.ndarray, cubic: np.ndarray, fec: np.ndarray, output_path: Path) -> None:
|
||||
labels = [format_loss_label(loss) for loss in losses]
|
||||
|
||||
fig, ax = plt.subplots(figsize=(5.6, 5.0), constrained_layout=True)
|
||||
|
||||
ax.plot(losses, cubic, marker="o", linewidth=2.4, markersize=7, label="直接转发", color='#4285F4')
|
||||
ax.plot(losses, fec, marker="s", linewidth=2.4, markersize=7, label="本文方法", color='#EA4335')
|
||||
ax.set_xlabel("丢包率")
|
||||
ax.set_ylabel("吞吐量(Mbps)")
|
||||
ax.set_xticks(losses, labels)
|
||||
plt.setp(ax.get_xticklabels(), rotation=-35, ha="left", rotation_mode="anchor")
|
||||
ax.grid(axis="y", linestyle="--", alpha=0.35)
|
||||
ax.grid(axis="x", linestyle="--", alpha=0.22)
|
||||
ax.legend(frameon=False)
|
||||
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
fig.savefig(output_path, bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def plot_speedup(losses: np.ndarray, cubic: np.ndarray, fec: np.ndarray, output_path: Path) -> None:
|
||||
speedup = fec / cubic
|
||||
labels = [format_loss_label(loss) for loss in losses]
|
||||
category_x = np.arange(len(labels))
|
||||
|
||||
fig, ax = plt.subplots(figsize=(5.6, 5.0), constrained_layout=True)
|
||||
|
||||
bars = ax.bar(category_x, speedup, color="#4285F4", width=0.62)
|
||||
ax.axhline(1.0, color="#444444", linewidth=1.2, linestyle="--")
|
||||
ax.set_xlabel("丢包率")
|
||||
ax.set_ylabel("相对吞吐提升")
|
||||
ax.set_xticks(category_x, labels)
|
||||
ax.grid(axis="y", linestyle="--", alpha=0.35)
|
||||
ax.set_ymargin(0.1)
|
||||
|
||||
for bar, value in zip(bars, speedup):
|
||||
ax.text(
|
||||
bar.get_x() + bar.get_width() / 2,
|
||||
bar.get_height(),
|
||||
f"{value:.1f}x",
|
||||
ha="center",
|
||||
va="bottom",
|
||||
fontsize=BAR_LABEL_FONT_SIZE,
|
||||
)
|
||||
|
||||
output_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
fig.savefig(output_path, bbox_inches="tight")
|
||||
plt.close(fig)
|
||||
|
||||
|
||||
def plot_throughput(csv_path: Path, absolute_output_path: Path, speedup_output_path: Path) -> None:
|
||||
configure_fonts()
|
||||
losses, cubic, fec = read_throughput(csv_path)
|
||||
losses, cubic, fec = filter_results(losses, cubic, fec)
|
||||
plot_absolute_throughput(losses, cubic, fec, absolute_output_path)
|
||||
plot_speedup(losses, cubic, fec, speedup_output_path)
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
parser = argparse.ArgumentParser(description="Plot throughput comparison under different loss rates.")
|
||||
parser.add_argument("--input", type=Path, default=Path("scripts/thpt.csv"), help="Path to throughput CSV.")
|
||||
parser.add_argument(
|
||||
"--absolute-output",
|
||||
type=Path,
|
||||
default=Path("figures/thpt_absolute.pdf"),
|
||||
help="Output path for the absolute throughput figure.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--speedup-output",
|
||||
type=Path,
|
||||
default=Path("figures/thpt_speedup.pdf"),
|
||||
help="Output path for the relative speedup figure.",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
plot_throughput(args.input, args.absolute_output, args.speedup_output)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
9
scripts/thpt.csv
Normal file
9
scripts/thpt.csv
Normal file
@@ -0,0 +1,9 @@
|
||||
loss,cubic_thpt_mbps,fec_thpt_mbps
|
||||
0,92.1,90.9
|
||||
0.002,42.5,61.7
|
||||
0.005,27.9,59.8
|
||||
0.01,18.9,54.8
|
||||
0.02,12.7,45.3
|
||||
0.05,7.58,21.5,
|
||||
0.1,4.78,6.25
|
||||
0.2,0.624,5.61
|
||||
|
Reference in New Issue
Block a user