1. 为什么需要注册发现
服务 A 调服务 B,B 有 5 个实例,地址会变(扩缩容、重启)。把地址写死在配置里维护不动。注册发现让 B 启动时上报、A 运行时查可用实例。
2. 两种发现模式
服务端发现:A 问网关/B 问注册中心,由中间层挑实例(k8s Service 就是)。客户端发现:A 自己从注册中心拿实例列表挑一个(Consul + 客户端负载均衡)。
3. consul 注册
reg := &consul.AgentServiceRegistration{ Name: "order-svc", Port: 8080, Check: &consul.AgentServiceCheck{HTTP: "http:///healthz", Interval: "10s"}, } consul.Agent().ServiceRegister(reg) // 关时注销(第 8 篇优雅停机里调)
健康检查挂 healthz(第 8 篇),不健康的实例被摘掉。
4. 客户端取实例
func pick(service string) string { entries, _ := consul.Health().Service(service, "", true, nil) return entries[rand.Intn(len(entries))].Service.Address + ":" + port }
拿到健康实例随机挑(或轮询)。配合第 2 篇的 gRPC Dial 复用连接。
5. 配置中心
多服务共享的配置(限流阈值、特性开关、下游地址)集中管,改了下发不重启:
kv.Get("order-svc/ratelimit", &cfg) // consul kv 或 nacos;k8s 用 ConfigMap 挂进容器
第 7 篇的热加载对接这里,配置改了各服务热加载生效。
6. k8s 原生替代
上了 k8s 大多不用 consul:Service 名做发现(order-svc.default.svc)自带 DNS 和负载均衡,ConfigMap/Secret 做配置,探针做健康检查。注册发现交给平台,代码里只填服务名:
conn, _ := grpc.Dial("order-svc:8081", ...) // k8s 解析到实例
7. 上线清单
实例地址别写死,用发现或 k8s Service。注册时带健康检查,不健康实例自动摘。配置集中到配置中心或 ConfigMap,改动热下发。k8s 环境优先用原生 Service+ConfigMap,少引独立组件。客户端发现要自己处理实例列表缓存和刷新,别每次请求查注册中心。
六篇走完,第三季从微服务拆分、gRPC、事件驱动、DDD、分布式事务到注册发现,把单个 Gin 服务放到分布式系统里该怎么长讲清了。三季合计从入门到架构,一条完整的学习路径。