你写了个订单服务,它得调用库存服务扣减数量;又写了用户服务,登录后要拉取权限配置——可问题来了:库存服务部署在哪儿?IP是多少?端口几号?是192.168.3.12:8081,还是k8s集群里的svc-inventory:9002?总不能每次上线都手动改配置吧?
服务发现,就是给服务“打电话前先查114”
服务发现不是什么黑科技,本质就一件事:让一个服务能动态知道另一个服务的网络地址。就像你打客服电话前得先查号码,程序调用前也得先问一句:“库存服务现在在哪儿?”这个“问”的动作,就是服务发现API调用。
常见做法是向注册中心发HTTP请求,比如用curl查Consul:
curl -X GET http://consul-server:8500/v1/health/service/inventory?passing=true返回里会有一组健康实例,挑一个IP+Port,就能发起真实调用了。
代码里怎么调?举个真实片段
Java项目用Spring Cloud时,Ribbon或LoadBalancer自动完成服务发现。但底层其实悄悄调了Eureka API:
GET http://eureka-server/eureka/apps/INVENTORY返回XML或JSON,里面包含所有存活的inventory实例列表。你写的Feign接口像这样:
@FeignClient(name = "inventory-service")
public interface InventoryClient {
@GetMapping("/api/v1/stock/{sku}")
StockResponse getStock(@PathVariable String sku);
}调用inventoryClient.getStock("SKU-001")那一刻,框架已帮你查完地址、选好节点、发出去了。
别硬编码,也别全靠框架
有些场景框架包不进去——比如你用Go写了个脚本,要临时调一下配置中心服务。那就得自己拼URL、处理JSON、做重试和缓存:
resp, _ := http.Get("http://nacos-server:8848/nacos/v1/ns/instance/list?serviceName=config-service")
defer resp.Body.Close()
var result map[string]interface{}
json.NewDecoder(resp.Body).Decode(&result)
// 从result["hosts"]里取第一个healthy host注意:别忘了加超时、判断status code、跳过不健康的节点。这些细节,才是API调用真正落地的地方。
服务发现API调用不是玄学,它就藏在每次远程调用之前那0.1秒里——看不见,但少了它,整个系统就失联了。