最小的注册中心要有什么?租约、心跳和过期怎么写?崩溃的实例多久才会被摘掉?ttl 该是心跳间隔的几倍?实例很多时过期扫描怎么做?这篇自己写一个 40 行的注册中心,把这些量出来。
过期实现 | 最短 | 中位数 | 最长(崩溃后消失用了多久,20 次) -------------+--------+--------+------------------- 惰性(查询时检查) | 2.00 s | 2.01 s | 2.01 s 后台每 1 s 扫描 | 2.05 s | 2.51 s | 2.93 s 后台每 0.2 s 扫描 | 2.03 s | 2.11 s | 2.20 s 对照:主动 deregister 在调用返回时就已经消失(59 µs)。崩溃的实例要靠租约到期:消失时间 = ttl(2 s)再加上一个 0 到扫描间隔之间的延迟(最短和最长之差就是这个延迟的范围);惰性检查没有扫描延迟,但 lookup 之外别的地方(例如统计实例数、通知订阅者)仍然看到旧状态
崩溃的实例靠租约到期消失,延迟是 ttl 加扫描间隔内的随机量;主动注销立刻生效。
ttl | 需要连续丢几个心跳才会过期 | 5 分钟内误摘除次数(1000 个实例) | 理论期望(1000 × 300 × 丢包率^k × 0.9) ------+---------------+----------------------+------------------------------- 1.5 s | 2 | 2652 | 2700.0 2.0 s | 2 | 2652 | 2700.0 3.0 s | 3 | 263 | 270.0 5.0 s | 5 | 3 | 2.7 理论期望是近似值(每个时刻“刚好连续丢了 k 个心跳”的概率)。ttl 是心跳间隔的 1.5 倍和 2 倍时,都只能容忍一次丢包(连续丢两次就过期),每个实例 5 分钟里平均被误摘几次;每多容忍一次连续丢包,误摘除大约降到十分之一(丢包率 10%)
ttl 是心跳间隔的 k 倍,就要连续丢 k 个心跳才误摘除;每多一倍容忍,误摘除降到约十分之一。
实例数 N | 扫描全部 | 最小堆 | 删掉的(扫描) | 删掉的(堆) ----------+----------+----------+---------+------- 10,000 | 0.25 ms | 0.156 ms | 100 | 100 100,000 | 2.58 ms | 0.385 ms | 100 | 100 1,000,000 | 25.58 ms | 0.822 ms | 100 | 100 扫描的代价随 N 线性增长,实例多了就不能每秒全扫一遍;最小堆只处理到期的那几个,代价取决于到期的数量。续约会往堆里推新的条目,旧条目留在堆里直到弹出时被发现已经过期失效(惰性删除),所以堆会比实例数大一些
全扫随实例数线性增长;最小堆只处理到期的。