提供 Eureka Client 服务的应用名是: eureka-client
Ribbon + Eureka 使用的时候,通过 RestTemplate 会刨除以下错误:
2021-03-08 11:31:10.214 ERROR 26501 --- [nio-8781-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.Illeg
alStateException: No instances available for eureka-client] with root cause
java.lang.IllegalStateException: No instances available for eureka-client
at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:119) ~[spring-cloud-netflix-ribbon-2.2.7.RELEASE.jar:2.2.7.RELEASE]
at org.springframework.cloud.netflix.ribbon.RibbonLoadBalancerClient.execute(RibbonLoadBalancerClient.java:99) ~[spring-cloud-netflix-ribbon-2.2.7.RELEASE.jar:2.2.7.RELEASE]
at org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor.intercept(LoadBalancerInterceptor.java:56) ~[spring-cloud-commons-3.0.1.jar:3.0.1]
at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:93) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:77) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-5.3.4.jar:5.3.4]
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) ~[spring-web-5.3.4.jar:5.3.4]
找了很久, 非常头疼, 网上找的的文章 核对过无数次,并没有发现自己少做什么, 但是问题依然无法解决, 于是只能自己动手解决了。
经过尝试后, 发现:
如果使用的是 spring-cloud-starter-ribbon 没有太大的问题, 但是 spring-cloud-starter-ribbon 已经作废了。 eureka, eureka-server 也是类似的。
Spring Cloud Starter Ribbon
Spring Cloud Starter Ribbon (deprecated, please use spring-cloud-starter-netflix-ribbon)
改用了 spring-cloud-starter-netflix-ribbon 以后, loadBalancerClient.choose("eureka-client") 是 null, 并没有获取已经注册的 eureka-client。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
<version>LATEST</version>
</dependency>
restTemplate.getForObject 被调用的时候, 就会出现以上错误(原因和上面一样, 是 RibbonLoadBalancerClient.choose() = null):
但是 discoveryClient.getInstances("eureka-client") 是可以获取到注册的 Eureka 服务的.
解决方法一
在 RibbonEurekaClientConfig 中添加代码后就可以了:
@Bean
public ServerList<Server> getServerList(IClientConfig config) {
return new ServerList<Server>() {
@Override
public List<Server> getInitialListOfServers() {
return new ArrayList<>();
}
@Override
public List<Server> getUpdatedListOfServers() {
List<Server> serverList = new ArrayList<>();
List<ServiceInstance> list = discoveryClient.getInstances(config.getClientName());
for (ServiceInstance instance : list) {
serverList.add(new Server(instance.getHost(), instance.getPort()));
}
return serverList;
}
};
}
原因是因为没有获取到已经注册的 eureka-client 的服务。 添加以下代码, 在初始化 ServerList<Server> 的时候, 会使用自己实现的 getUpdatedListOfServers() 方法
解决方法二
通过读源码,找到了关键的地方
DynamicServerListLoadBalancer.initWithNiwsConfig()
@Override
public void initWithNiwsConfig(IClientConfig clientConfig) {
try {
super.initWithNiwsConfig(clientConfig);
String niwsServerListClassName = clientConfig.getPropertyAsString(
CommonClientConfigKey.NIWSServerListClassName,
DefaultClientConfigImpl.DEFAULT_SEVER_LIST_CLASS);
ServerList<T> niwsServerListImpl = (ServerList<T>) ClientFactory
.instantiateInstanceWithClientConfig(niwsServerListClassName, clientConfig);
this.serverListImpl = niwsServerListImpl;
...
关键的地方是 serverListImpl, 默认的是 com.netflix.loadbalancer.ConfigurationBasedServerList, 这个类获取的是配置中的 listOfServers (不用 Eureka的场景).
initWithNiwsConfig() --> restOfInit() --> updateListOfServers()
com.netflix.loadbalancer.ConfigurationBasedServerList 是通过配置 IClientConfig 中的 NIWSServerListClassName 的值反射而来的, 通过在 application.yml 中配置可以改变:
ribbon:
NIWSServerListClassName: com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList
com.netflix.niws.loadbalancer.DiscoveryEnabledNIWSServerList 这个类是包 ribbon-eureka 中的类. 在 pom.xml 中引入:
<dependency>
<groupId>com.netflix.ribbon</groupId>
<artifactId>ribbon-eureka</artifactId>
<version>2.3.0</version>
</dependency>
这里的版本需要注意一下, spring-cloud-starter-netflix-ribbon 中的 ribbon-core 的版本是 2.3.0, 所以这里的版本就是 2.3.0. 这里的版本不一致可能会导致错误。
这时在 RibbonEurekaClientConfig.java 中只修改方法 getServerList :
@Bean
public ServerList<Server> getServerList(IClientConfig config) {
DynamicServerListLoadBalancer<Server> serverDynamicServerListLoadBalancer = new DynamicServerListLoadBalancer<>();
serverDynamicServerListLoadBalancer.initWithNiwsConfig(config);
return serverDynamicServerListLoadBalancer.getServerListImpl();
}
注意这里主要修改的文件有 3 个:
- pom.xml
- application.yml
- RibbonEurekaClientConfig.java
本文介绍了解决Ribbon+Eureka环境下服务发现失败的问题,详细分析了错误产生的原因及两种解决方案,一种是自定义ServerList,另一种是通过配置DiscoveryEnabledNIWSServerList来替换默认的ConfigurationBasedServerList。

380

被折叠的 条评论
为什么被折叠?



