背景
技术线,springcloud,ribbon, eureka
错误配置方式
@Bean
public IRule myRule() {
// 定义为随机
return new RandomRule();
}
在springBoot工程中加入如上配置,有多个下游service服务的时候。通过org.springframework.web.client.RestTemplate调用下游服务时。com.netflix.loadbalancer.ILoadBalancer#chooseServer就无法发现服务地址,从而会报No instances available for ***异常。
原因分析
netflix的spring ApplicationContext容器是每个远程service对应一个,ApplicationContext维护在如下map中:
org.springframework.cloud.context.named.NamedContextFactory#contexts
private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();
而ILoadBalancer,IRule 实例维护,是每个远程service对应的ApplicationContext管理各自的实例。
那么在springBoot工程中@Bean方式申明IRule实例,因为此实例会在父springContext中实例化,最后导致所有远程service对应的ApplicationContext都只使用此一个IRule.
而IRule会关联ILoadBalancer执行路由chooseServer操作。从而导致有的服务就会服务A的请求会被路由到服务B上去。(如此便导致了路由错乱)
假如服务B没有可用地址,那么就会导致No instances available for B错误。
正确配置方式
ribbon: NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule 这种方式配置的IRule,可以保证每个远程service对应的ApplicationContext各自实例化自己的RandomRule。