grpc-go 默认的负载均衡策略是什么?round_robin 和它差在哪里?后端被停掉、地址列表更新、有一个后端很慢,分别会怎样?这篇用三个本机后端逐项实测。
pick_first 三个后端收到的次数 [300 0 0] round_robin 三个后端收到的次数 [100 99 101]
默认策略:按地址顺序试,连上第一个能用的就只用它,其余是备份。连接没断就不换,即使地址列表里加了新后端。
客户端 1:1 2 0 1 2 0 1 2 0 客户端 2:0 2 0 1 2 0 1 2 0 客户端 3:0 2 0 1 2 0 1 2 0 客户端 4:0 2 0 1 2 0 1 2 0 客户端 5:2 0 1 2 0 1 2 0 1 客户端 6:2 2 0 1 2 0 1 2 0
给每个地址建一个子连接,在就绪的子连接中轮流选。顺序的起点随机,只在已就绪的后端里选。
pick_first 前 8 次之后停掉后端 0、等 50 ms:0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 pick_first 停掉后端 0 之后马上继续调用,重复 20 次、共 320 次调用:有失败的有 15 次,失败的调用共 15 个;第一个失败 code=Unavailable message="error reading from server: read tcp 127.0.0.1:58184->127.0.0.1:9806: read: connection reset by peer" round_robin 前 8 次之后停掉后端 0、等 50 ms:1 1 1 2 0 1 2 0 1 2 1 2 1 2 1 2 1 2 1 2 1 2 1 2 round_robin 停掉后端 0 之后马上继续调用,重复 20 次、共 320 次调用:有失败的有 5 次,失败的调用共 5 个;第一个失败 code=Unavailable message="error reading from server: EOF"
两种策略都会自动切到别的后端。切换完成之前正好发出去的调用会失败(Unavailable),需要靠重试(第 18 篇)兜底。
pick_first 地址 [0 1] 三个后端收到的次数 [60 0 0] pick_first 加入 2 → [0 1 2] 三个后端收到的次数 [60 0 0] pick_first 去掉 0 → [1 2] 三个后端收到的次数 [0 60 0] round_robin 地址 [0 1] 三个后端收到的次数 [30 30 0] round_robin 加入 2 → [0 1 2] 三个后端收到的次数 [20 20 20] round_robin 去掉 0 → [1 2] 三个后端收到的次数 [0 30 30]
round_robin 会立即把新地址纳入轮询,pick_first 不会。想让新加的后端分到流量,不能用 pick_first。
慢的是后端 0:pick_first 30 次共 3042.4 ms;各后端次数 [30 0 0] 慢的是后端 0:round_robin 30 次共 1014.7 ms;各后端次数 [10 10 10] 慢的是后端 2:pick_first 30 次共 3.4 ms;各后端次数 [30 0 0] 慢的是后端 2:round_robin 30 次共 1016.4 ms;各后端次数 [10 10 10]
round_robin 不看后端响应快慢,慢后端分到的比例和快的一样。需要感知负载要用 least_request 或带权重的策略(本篇没有测)。
默认 三个后端收到的次数 [30 0 0] shuffleAddressList=true 三个后端收到的次数 [12 9 9]
pick_first 可以配置 shuffleAddressList,让不同客户端挑选不同的第一个地址,减轻“所有客户端都连同一个后端”的问题。