注册中心挂了,服务还互相调得动吗
先回答一个高频面试题:Nacos 整个挂了,线上服务会挂吗?不会立刻挂。调用方本地缓存着实例列表,注册中心不在调用路径上——它只在实例变化时提供新列表。真正会坏的是两件事:新扩容的实例进不了列表,已下线的实例摘不掉。所以注册中心的可用性要求是"挂了尽快修",不是"永远不许挂",但有个前提:调用方一定要开本地缓存兜底,别每次调用都现查注册中心。
临时实例与持久实例:选错模式症状很迷惑
Nacos 里两类实例:临时实例靠客户端心跳续约,实例挂了心跳停,几秒内被剔除——适合会弹性伸缩的业务服务;持久实例不做心跳,由注册中心主动探测健康状态,不健康只是标记、不会删——适合数据库、消息队列这类不常动但可能短暂失联的基础设施。
选错的代价都藏在故障时刻:把弹性服务注册成持久实例,会出现"实例明明没了,列表里还在,调用方持续报错"的迷惑现象;反过来把 MySQL 注册成临时实例,网络抖一下就被剔除,恢复后还要重新注册。先想清楚实例的生命周期,再选模式。
spring:
cloud:
nacos:
discovery:
server-addr: nacos:8848
ephemeral: true # 业务服务用临时实例(默认)
heart-beat-interval: 5000 # 心跳间隔 ms
heart-beat-timeout: 15000 # 超时未续约 -> 标记不健康
ip-delete-timeout: 30000 # 再超时 -> 剔除保护阈值:宁可旧列表,不要空列表
网络抖动或注册中心 GC 时,大量心跳可能同时超时,正常实例被批量误杀,调用方拿到一个空列表——这是注册中心侧的雪崩。保护阈值的逻辑是:健康实例占比低于阈值时,宁可不剔除不健康实例,也要把完整列表给出去,让调用方去撞重试和超时,而不是集体无实例可用。生产上建议打开(比如 0.8),并配合调用方的故障转移一起用。
优雅上下线:上线预热,下线告别
上线瞬间实例刚起来就被打满,是冷启动打喷嚏:JIT 没热、连接池没建好、本地缓存是空的。解法是延迟注册或权重渐增,让流量爬坡。下线更要讲究:kill -9 直接掐掉,注册中心要等心跳超时才摘除,这段窗口内调用方还在往死实例上打。正确姿势是先主动注销、排空存量请求、再关资源退出,K8s 里对应 preStop 钩子加就绪探针。
@PreDestroy
public void shutdown() {
// 1. 先主动注销,让新流量不再进来
namingService.deregisterInstance("inventory", "10.2.3.15", 8080);
// 2. 排空存量请求(最多等 10s)
drainRequests(10_000);
// 3. 最后关闭连接池、线程池等资源
closeResources();
}集群部署与几个容量细节
Nacos 生产至少三节点集群加 MySQL 存储,注册与配置共用集群但用命名空间隔离环境。几个容易忽略的细节:连接数上限——客户端与注册中心是长连接,几千实例规模时要关注;磁盘——推送轨迹日志很占空间,要配清理策略;版本——注册中心不是追新的地方,停在官方推荐稳定线,升级前先在测试环境演练。下一篇转到配置中心:改个配置为什么要发版,以及怎么让它不发。
评论 (0)