常打磨常新,bbr 和 inflight 守恒算法的模型和仿真也在不断优化。
再次给出 bbr 模型,这次修改了 d x d t \dfrac{dx}{dt} dtdx 的表达式,由 g 2 ⋅ x ⋅ r m i n g_2\cdot x\cdot r_{min} g2⋅x⋅rmin计算。同时加入了微观建模 probebw phase 的支持:
C = Bltbw,R = RtProp,T_r = ProbeRTT 周期,T 为 ProbeBW phase cycle 周期,g1 = Startup gain,g2 = ProbeBW gain。设 x = estimated bandwidth,r = round trip time,w = inflight:
g 2 ( t ) = { 1.25 , t m o d T = 1 1 , 1 < t m o d T ≤ T − 1 g_2(t)=\begin{cases} 1.25 ,& t\mod T=1\\\\1,&1<t\mod T\leq T-1 \end{cases} g2(t)=⎩ ⎨ ⎧1.25,1,tmodT=11<tmodT≤T−1
I ( t ) = ∑ i = 0 n g 2 ( t + ϕ i ) ⋅ w i ( t ) I(t)=\displaystyle\sum_{i=0}^n g_2(t+\phi_i)\cdot w_i(t) I(t)=i=0∑ng2(t+ϕi)⋅wi(t)
d x d t = { ( g 1 − 1 ) x , r = R C ⋅ g 2 ( t ) ⋅ x ⋅ r m i n I ( t ) − w x + g 2 ( t ) ⋅ x ⋅ r m i n − x , r > R \dfrac{dx}{dt} = \begin{cases} (g_1-1)x, & r = R \\\\ C\cdot \dfrac{g_2(t)\cdot x\cdot r_{min}}{I(t)-w_x+g_2(t) \cdot x\cdot r_{min}}-x, & r \gt R \end{cases} dtdx=⎩ ⎨ ⎧(g1−1)x,C⋅I(t)−wx+g2(t)⋅x⋅rming2(t)⋅x⋅rmin−x,r=Rr>R
r ( t ) = { I ( t ) C , I ( t ) > C ⋅ R R , I ( t ) ≤ C ⋅ R r(t)=\begin{cases} \dfrac{I(t)}{C} ,& I(t)>C\cdot R\\\\R,&I(t)\leq C\cdot R \end{cases} r(t)=⎩ ⎨ ⎧CI(t),R,I(t)>C⋅RI(t)≤C⋅R
r m i n = min x ∈ [ t , t + T r ] r ( x ) r_{min}=\displaystyle\min\limits_{x\in[t,t+T_r]}r(x) rmin=x∈[t,t+Tr]minr(x)
d w x ( t ) d t = { x ( t ) ⋅ r m i n − w x ( t ) , t m o d T r ≠ 0 4 − w x ( t ) , t m o d T r = 0 \dfrac{dw_x(t)}{dt}=\begin{cases} x(t) \cdot r_{min}-w_x(t),& t\bmod T_r \neq 0 \\\\ 4-w_x(t),& t\bmod T_r = 0 \\ \end{cases} dtdwx(t)=⎩ ⎨ ⎧x(t)⋅rmin−wx(t),4−wx(t),tmodTr=0tmodTr=0
这个模型描述原始的 bbr1 算法,但由于相位差的问题可能会导致不收敛(比如跌入同步 mimd):
bbr 充分考虑到这个问题,于是在每一轮 ProbeRTT 后会随机 place cycle phase 以打破这个局面,bbr 论文中有下列段落:
Furthermore, to improve mixing and fairness, and to reduce queues when multiple BBR flows share a bottleneck, BBR randomizes the phases of ProbeBW gain cycling by randomly picking an initial phase—from among all but the 3/4 phase—when entering ProbeBW. Why not start cycling with 3/4? The main advantage of the 3/4 pacing_gain is to drain any queue that can be created by running a 5/4 pacing_gain when the pipe is already full. When exiting Drain or ProbeRTT and entering ProbeBW, there is no queue to drain, so the 3/4 gain does not provide that advantage. Using 3/4 in those contexts only has a cost: a link utilization for that round of 3/4 instead of 1. Since starting with 3/4 would have a cost but no benefit, and since entering ProbeBW happens at the start of any connection long enough to have a Drain, BBR uses this small optimization. 【避开 0.75 印证了 dw/dt = x*R - w 这个方程的独立性和重要性】
然而原先不同步的流也可能因为这个机制而同步陷入僵局。不管怎样,这种局面一旦陷入,就要僵持一个 ProbeRTT 周期。
同步问题的万能解药就是随机。在 ProbeBW cycle 中直接用随机打破它即可。
为此,需要先做一个函数,它做如下输出,每 8 个时间单位(round-trip)随机输出且仅输出 1 次 1.25,其余输出 1:
-----cycle:0-----
phase: 0 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 1 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 2 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 3 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 4 gain: flow 1:1.00 flow 2:1.00 flow 3:1.25
phase: 5 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 6 gain: flow 1:1.25 flow 2:1.25 flow 3:1.00
phase: 7 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
-----cycle:1-----
phase: 0 gain: flow 1:1.00 flow 2:1.25 flow 3:1.00
phase: 1 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 2 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 3 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 4 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 5 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 6 gain: flow 1:1.25 flow 2:1.00 flow 3:1.25
phase: 7 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
-----cycle:2-----
phase: 0 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 1 gain: flow 1:1.00 flow 2:1.25 flow 3:1.00
phase: 2 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 3 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 4 gain: flow 1:1.25 flow 2:1.00 flow 3:1.25
phase: 5 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 6 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
phase: 7 gain: flow 1:1.00 flow 2:1.00 flow 3:1.00
-----cycle:3-----
...
以下是一个 AI 协助改出来的非常不雅观的 python 函数:
def get_value(i, seed=None):
rng = random.Random(seed)
cycle = i // 8
index_within_cycle = i % 8
if not hasattr(get_value, 'state'):
get_value.state = {}
if seed not in get_value.state:
get_value.state[seed] = {
'cycle': -1,
'values': None,
'rng_state': rng.getstate()
}
if cycle!= get_value.state[seed]['cycle']:
rng.setstate(get_value.state[seed]['rng_state'])
values = [1] * 8
special_index = rng.randint(0, 7)
values[special_index] = 1.25
rng.shuffle(values)
get_value.state[seed]['cycle'] = cycle
get_value.state[seed]['values'] = iter(values)
get_value.state[seed]['rng_state'] = rng.getstate()
value_iter = get_value.state[seed]['values']
try:
value = next(value_iter)
except StopIteration:
rng.setstate(get_value.state[seed]['rng_state'])
values = [1] * 8
special_index = rng.randint(0, 7)
values[special_index] = 1.25
rng.shuffle(values)
value_iter = iter(values)
get_value.state[seed]['values'] = value_iter
get_value.state[seed]['rng_state'] = rng.getstate()
value = next(value_iter)
return value
有了这个随机支持,相位差的同步僵局就解除了,即便某次不巧同步了,下一次就能解除:
g1 = get_value(n, 1)
g2 = get_value(n, 2)
g3 = get_value(n, 3)
x[n] = x[n-1] + dt * (C*g1*x[n-1]*R/(g1*x[n-1]*R + g2*wy[n-1] + g3*wz[n-1]) - x[n-1])
y[n] = y[n-1] + dt * (C*g2*y[n-1]*R/(g2*y[n-1]*R + g1*wx[n-1] + g3*wz[n-1]) - y[n-1])
z[n] = z[n-1] + dt * (C*g3*z[n-1]*R/(g3*z[n-1]*R + g1*wx[n-1] + g2*wy[n-1]) - z[n-1])
wx[n] = wx[n-1] + dt * (x[n-1]*R - wx[n-1])
wy[n] = wy[n-1] + dt * (y[n-1]*R - wy[n-1])
wz[n] = wz[n-1] + dt * (z[n-1]*R - wz[n-1])
r[n] = (wx[n] + wy[n] + wz[n]) / C
if r[n] < R:
r[n] = R
取消了相位差,效果如下:
浙江温州皮鞋湿,下雨进水不会胖。