在一家电商公司的技术团队里,订单、库存、支付各自独立成服务。开发小李刚接手系统重构任务时,最头疼的就是搞清楚订单服务怎么找到支付服务。以前所有功能都在一个大应用里,调个方法就行。现在拆成多个服务,彼此怎么“打招呼”成了问题。
服务发现到底解决了什么
想象你在陌生城市打车,司机问你目的地,你说“去那栋红屋顶的大楼”。但城市里可能有好几栋红屋顶建筑,司机根本找不到。这时候你需要一个精确地址,或者导航定位。服务发现就是微服务世界的“导航系统”。
Dubbo 应用默认不直接写死对方 IP 和端口,而是把服务注册到一个“黄页”里。比如支付服务启动后,主动告诉注册中心:“我上线了,我是 pay-service,地址是 192.168.1.100:20880”。订单服务要调用时,就去查这个“黄页”,拿到可用的支付服务列表。
Dubbo 中的服务发现流程
Dubbo 使用的是典型的三角色模型:服务提供者、服务消费者、注册中心。ZooKeeper 是最常见的注册中心选择。
当支付服务启动时,会向 ZooKeeper 写入节点信息:
/dubbo/com.example.PayService/providers/ <dubbo://192.168.1.100:20880...>
而订单服务作为消费者,则监听这个路径的变化。一旦有新的提供者加入或下线,ZooKeeper 会通知它更新本地缓存。
配置一个带服务发现的 Dubbo 应用
在 Spring Boot 项目中引入 Dubbo 和 ZooKeeper 客户端依赖:
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-x-discovery</artifactId>
<version>5.2.0</version>
</dependency>
然后在 application.yml 中指定注册中心地址:
dubbo:
application:
name: order-service
registry:
address: zookeeper://127.0.0.1:2181
protocol:
name: dubbo
port: 20880
这样,只要服务启动,就会自动完成注册与发现。
实际运行中的细节
有一次线上发布新版本支付服务,运维误操作导致旧实例没完全下线。结果订单服务从注册中心拉到了两个 pay-service 实例。Dubbo 默认使用负载均衡策略,一半请求打到了已关闭的服务上,引发了超时。
后来团队加上了优雅停机配置:
dubbo:
provider:
shutdown.timeout: 10000
确保服务关闭前先从注册中心反注册,避免“僵尸”节点误导消费者。
服务发现不是万能钥匙,它简化了调用方的寻址逻辑,但也引入了注册中心这一新故障点。高可用部署 ZooKeeper 集群、设置合理的重试机制,都是保障稳定的关键。