当我们连接到一个失败的后端时,通常希望不要立即重试(以避免泛滥的网络或服务器的请求),而是做某种形式的指数backoff。
我们有几个参数:
- INITIAL_BACKOFF (第一次失败重试前后需等待多久)
- MULTIPLIER (在失败的重试后乘以的倍数)
- JITTER (随机抖动因子).
- MAX_BACKOFF (backoff上限)
- MIN_CONNECT_TIMEOUT (最短重试间隔)
建议backoff算法
以指数形式返回连接尝试的起始时间,达到MAX_BACKOFF的极限,并带有抖动。
1 2 3 4 5 6 7
|
ConnectWithBackoff() current_backoff = INITIAL_BACKOFF current_deadline = now() + INITIAL_BACKOFF while (TryConnect(Max(current_deadline, now() + MIN_CONNECT_TIMEOUT))!= SUCCESS) SleepUntil(current_deadline) current_backoff = Min(current_backoff * MULTIPLIER, MAX_BACKOFF) current_deadline = now() + current_backoff + UniformRandom(-JITTER * current_backoff, JITTER * current_backoff)
|
参数默认值MIN_CONNECT_TIMEOUT =20sec INITIAL_BACKOFF =1sec MULTIPLIER =1.6 MAX_BACKOFF =120sec JITTER =0.2
根据的确切的关注点实现(例如最小化手机的唤醒次数)可能希望使用不同的算法,特别是不同的抖动逻辑。
备用的实现必须确保连接退避在同一时间开始分散,并且不得比上述算法更频繁地尝试连接。
重置backoff
backoff应在某个时间点重置为INITIAL_BACKOFF ,以便重新连接行为是一致的,不管连接的是新开始的还是先前断开的连接。
当接收到SETTINGS 帧时重置backoff,在那个时候,我们确定这个连接被服务器已经接受了。
grpc-go
源码位于google.golang.org/grpc/backoff ,代码不多,直接在代码上分析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
|
import ( "math/rand" "time" )
|
如果默认的backoff算法不满足需求的时候,还可以自定义backoff算法,通过实现backoffStrategy接口。
1 2 3 4 5 6 7
|
func withBackoff(bs backoffStrategy) DialOption { return func(o *dialOptions) { o.bs = bs } }
grpc.Dial(addr, grpc.withBackoff(mybackoff))
|
|
请发表评论