很多人并不理解 bufferbloat 的本质,我引用《计算机网络-自顶向下方法(第 8 版)》第四章的一个解释:
很形象的比喻,buffer 就像盐,不可或缺,适量增味,过量食物就不能吃了。高血压患者更有所感受,一旦摄入过量盐,排盐就不是大量喝水能解决的了。
一旦 buffer 里堆满了数据包,它们就很难排空了,特别是在 aimd 这种 capacity-seeking 的作用力下,下面水流的例子更为直观:
虽然流速一直保持为 v,但相比下图,水流在上图的宽敞处会减慢流速而造成时延增大,如果上游不主动减小流量,水库是不会排空的。
bbr 解决 bufferbloat 之道有两个方法:
- 从模型上保证 inflight 收敛到 bdp;
- 定时 probertt 排空 queue,确保基础 rtt。
为了直观看到这个事实,将模型具象化是高尚的,作为对比,单流 bbr 的 inflight 模型非常简单,设 x 为 bbr 单流 inflight,C 为瓶颈带宽,R 为传播时延,方程如下:
d x d t = C ⋅ R − x \dfrac{dx}{dt}=C\cdot R-x dtdx=C⋅R−x
这是一个典型的负反馈模型,当 x 大于 bdp,inflight 要减小,避免 bufferbloat,当 x 小于 bdp,inflight 要增大,提高带宽利用率。可见,bbr 专为解决 bufferbloat 而生,inflight 就是 bdp。
而 aimd 则是一个 bufferbloat 制造者模型,以下是一个 “连续 md” 的示例:
beta = 0.5
C, R = 50, 2
# x, z 分别为两条流的 cwnd
def dxdt(x, y, t):
if y > 0:
return - beta * x
else:
return 1
def dzdt(z, y, t):
if y > 0:
return - beta * z
else:
return 1
def ydt(a, b, t):
buff = 2 * C * R
if (a + b) > buff:
return 1
elif False and (a + b) > (buff - int(buff / 4)):
ret = 2*random.random() - 1
return ret
return 0
t = np.linspace(0, 800, 8000)
x = np.zeros_like(t)
y = np.zeros_like(t)
z = np.zeros_like(t)
x[0], z[0] = 1, 250
for i in range(1, len(t)):
dt = t[i] - t[i - 1]
dxy = ydt(x[i - 1], z[i - 1], i)
dzy = ydt(z[i - 1], x[i - 1], i)
dx = dxdt(x[i - 1], dxy, t[i - 1])
dz = dzdt(z[i - 1], dzy, t[i - 1])
x[i] = x[i - 1] + (dx) * dt
z[i] = z[i - 1] + (dz) * dt
下图可看出,n 条流的 inflight 之和收敛到 bdp + buffer:
RED 版本结果如下:
buffer 占量降低了,但带宽利用率是代价。
为了快速收敛,避免拥塞加剧,实践中采用离散 md,即经典的锯齿:
for i in range(1, len(t)):
dt = t[i] - t[i - 1]
dy = ydt(x[i - 1], y[i - 1], i)
dx = dxdt(x[i - 1], dy, t[i - 1])
dz = dzdt(z[i - 1], dy, t[i - 1])
if dy > 0:
x[i] = x[i-1] * (1 - beta)
else:
x[i] = x[i - 1] + (dx) * dt
这一次我直接用 bbr 和离散 aimd 对比。bbr 的仿真实现非常简单:
def dzdt(z, y, t):
if y > 0: # 模拟 bbr 不完备实现,丢包时数据包守恒
return 0
inflt = C * R - z
return inflt
下图是没有 RED aimd 支持的:
可见,aimd 不达 bdp + buffer 不罢休,而 bbr 止步于 bdp。这意味着,有多大 buffer,aimd 用多大 buffer,buffer 越大,时延越大,这就是 bufferbloat 的恶果。
RED 轻微缓解了这个问题,但也不很:
多流 bbr 场景,n 条 bbr 流的 inflight 之和收敛到 bdp + probe_size,多日之前我用微分方程建模 bbr 时说过这事(从微分方程组构建 bbr 模型):
浙江温州皮鞋湿,下雨进水不会胖。