yudaocode/SpringBoot-Labs · error · IllegalStateException
获取不到实例
Error message
获取不到实例
What it means
The labx-25 Spring Cloud Zookeeper discovery consumer throws IllegalStateException("获取不到实例") when DiscoveryClient.getInstances("demo-provider") returns an empty list — the consumer asked Zookeeper for the service path and found no live instances. With Zookeeper, instances are ephemeral znodes under /services/demo-provider; they vanish when the provider session ends, so a crashed/killed provider is removed immediately (unlike Eureka's lease grace period), making this error appear the instant the provider dies or never registers. The consumer must also have spring-cloud-starter-zookeeper-discovery and a reachable Zookeeper server (spring.cloud.zookeeper.connect-string).
Source
Thrown at labx-25/labx-25-sc-zookeeper-discovery-demo01-consumer/src/main/java/cn/iocoder/springcloud/labx25/zookeeperdemo/consumer/DemoConsumerApplication.java:59
private RestTemplate restTemplate;
@Autowired
private LoadBalancerClient loadBalancerClient;
@GetMapping("/hello")
public String hello(String name) {
// 获得服务 `demo-provider` 的一个实例
ServiceInstance instance;
if (true) {
// 获取服务 `demo-provider` 对应的实例列表
List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
// 选择第一个
instance = instances.size() > 0 ? instances.get(0) : null;
} else {
instance = loadBalancerClient.choose("demo-provider");
}
// 发起调用
if (instance == null) {
throw new IllegalStateException("获取不到实例");
}
String targetUrl = instance.getUri() + "/echo?name=" + name;
String response = restTemplate.getForObject(targetUrl, String.class);
// 返回结果
return "consumer:" + response;
}
}
}
View on GitHub (pinned to 6c12efaed0)
Solutions
- Check Zookeeper directly: run `zkCli.sh` then `ls /services/demo-provider` (path may be /services or /spring-cloud per spring.cloud.zookeeper.discovery.root) — if empty, the provider is not registered; start the demo provider.
- Confirm the provider's spring.application.name is exactly demo-provider and both apps share the same spring.cloud.zookeeper.connect-string and discovery root.
- Ensure the Zookeeper server is up (echo ruok | nc localhost 2181 → imok) and the provider log shows successful Curator connection + registration before calling.
- Wait a moment after provider startup and retry — ephemeral registration is fast but not instantaneous; then guard the empty case explicitly or use LoadBalancerClient.choose with a null check.
Example fix
// before
List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
instance = instances.size() > 0 ? instances.get(0) : null;
if (instance == null) {
throw new IllegalStateException("获取不到实例");
}
// after — explicit empty handling referencing Zookeeper semantics
List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
if (instances.isEmpty()) {
throw new IllegalStateException(
"获取不到实例: no ephemeral nodes for 'demo-provider' in Zookeeper; " +
"verify provider registration at /services/demo-provider");
}
ServiceInstance instance = instances.get(0); Defensive patterns
Strategy: validation
Validate before calling
List<ServiceInstance> instances = discoveryClient.getInstances("demo-provider");
if (instances.isEmpty()) {
// Zookeeper ephemeral node absent: provider down or never registered
throw new ResponseStatusException(HttpStatus.SERVICE_UNAVAILABLE,
"demo-provider 无可用实例 (Zookeeper /services/demo-provider 为空)");
}
ServiceInstance instance = instances.get(0); Type guard
boolean zkServiceRegistered(DiscoveryClient dc, String service) {
List<ServiceInstance> list = dc.getInstances(service);
return list != null && !list.isEmpty();
} Try / catch
catch (IllegalStateException e) {
if ("获取不到实例".equals(e.getMessage())) {
// ephemeral nodes vanish on provider session loss; retry after short backoff
return ResponseEntity.status(503).body("demo-provider unavailable in Zookeeper, retry shortly");
}
throw e;
} Prevention
- Script the environment: start Zookeeper (zkServer.sh start or docker run zookeeper), wait for port 2181, then apps.
- Verify registration with `zkCli.sh ls /services/demo-provider` (adjust for spring.cloud.zookeeper.discovery.root) before calling the consumer.
- Pin spring.cloud.zookeeper.connect-string and discovery root consistently across provider and consumer.
- Remember Zookeeper removes instances immediately on session loss — unlike Eureka's lease grace — so build in retry/backoff for transient gaps.
When it happens
Trigger: Calling the consumer's /echo endpoint when: the Zookeeper provider app is not running (its ephemeral node under /services/demo-provider does not exist); the provider registered under a different name (spring.application.name mismatch with 'demo-provider'); Zookeeper is down or the consumer's connect-string points elsewhere, so CuratorDiscoveryClient queries the wrong ensemble; the provider is still starting and its registration has not completed; or the provider's Zookeeper session expired (network blip) deleting its ephemeral node.
Common situations: Zookeeper not installed/started locally (default localhost:2181) before running the demo; provider registered but with a JSON/metadata or name mismatch so the lookup path differs; starting consumer before provider registration finishes; Docker-mapped Zookeeper ports vs connect-string mismatch; session timeouts after laptop sleep/network change removing ephemeral nodes while Eureka habits suggest the instance would linger.
Related errors
AI-assisted analysis of yudaocode/SpringBoot-Labs@6c12efaed0 (2026-08-14).
Data as JSON: /api/errors/05f250cbfda3e837.
Report an issue: GitHub.