Ribbon-自定义Rule时遇到的问题

引言

在微服务架构中,服务治理是一个关键的组成部分。Ribbon是Spring Cloud中的一个重要组件,用于实现客户端负载均衡。有时候,我们需要自定义Ribbon的负载均衡规则,但在这个过程中,可能会遇到一些问题。本文将讨论在自定义Ribbon规则时可能遇到的问题,并提供解决方案。

一. 现象

当我们尝试单独配置Ribbon,例如自定义负载均衡规则,并将配置类标记为@Configuration,然后使用@Bean注解进行配置时,可能会遇到以下错误提示:

1
No qualifying bean of type ‘com.netflix.client.config.IClientConfig’ available

同时,在调用多个provider服务时,可能会出现服务调用错误,如:

1
feign.FeignException$NotFound: status 404

二. 原因

这些问题的根本原因是Ribbon配置类不能包含在主程序的@ComponentScan范围内。每一个ServiceId都应该有它自己专属的SpringContext,但错误使用@Bean注解会导致负载均衡规则被多个服务共享,实际上只存在一个配置对象。

三. 修改方式

要解决这些问题,可以通过以下方式之一进行修改:

1. 使用YAML配置

在配置文件中增加对服务provider的rule配置,示例:

1
2
3
base-service:
ribbon:
NFLoadBalancerRuleClassName: com.xxxx.common.Rule

2. 使用System.setProperty()

在应用启动时,可以使用System.setProperty()方法来设置负载均衡规则类,示例:

1
System.setProperty("base-service.ribbon.NFLoadBalancerRuleClassName", Rule.class.getName());

四. 参考资料

补充

官网描述

在[Ribbon]官网中对于自定义指定Rule有如下描述:

官网描述

这个自定义配置类不能放在@ComponentScan扫描的当前包以及子包中,否则这个自定义的IRule会被所有的Ribbon客户端共享,会导致一系列的问题。

常规处理方式

根据官网的描述,不能放在当前包及其子包中被扫描到,因此可以采取以下常规处理方式:

  1. 新建一个独立的package,将自定义的Rule规则类放入其中。
  2. 在主启动类中使用@RibbonClient注解,并指定configuration为自定义规则类的.class文件。

这种方式相对繁琐,但是是一种有效的解决方案。

推荐的方式

为了更简单地解决这个问题,可以考虑使用Spring中bean的不同作用域(scope)。默认情况下,Spring bean是singleton单例模式的,这意味着所有Ribbon客户端在初始化时都会获取到同一个对象。但实际上,还有prototype这一scope可供选择配置,可以将自定义的IRule配置为prototype,示例伪代码如下:

1
2
3
4
5
@Bean
@Scope(value = "prototype")
public IRule myRule() {
return new MyRule();
}

这样,每个Ribbon客户端都会得到一个独立的规则实例,解决了共享规则的问题。

结论

通过采用上述方式,可以顺利解决在自定义Ribbon规则时可能遇到的问题,让您可以继续愉快地编写代码。