在项目开发中,除了考虑正常的调用之外,负载均衡和故障转移也是关注的重点,这也是feign + ribbon的优势所在,基于上面两篇文章的基础,接下来我们开展最后一篇原生态fegin结合ribbon服务进行服务远程调用且实现负载均衡机制,也帮助大家学习ribbon奠定基础。
<dependencies>
<dependency>
<groupId>com.netflix.feigngroupId>
<artifactId>feign-coreartifactId>
<version>8.18.0version>
dependency>
<dependency>
<groupId>com.netflix.feigngroupId>
<artifactId>feign-jacksonartifactId>
<version>8.18.0version>
dependency>
<dependency>
<groupId>com.netflix.feigngroupId>
<artifactId>feign-ribbonartifactId>
<version>8.18.0version>
dependency>
<dependency>
<groupId>com.netflix.archaiusgroupId>
<artifactId>archaius-coreartifactId>
dependency>
dependencies>
复制代码
其中feign-core和feign-ribbon是必须的,如果需要在服务消费端和服务生产端之间进行对象交互,建议使用feign-jackson
import com.netflix.config.ConfigurationManager;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.ribbon.RibbonClient;
public class AppRun {
public static void main(String[] args) throws Exception {
User param = new User();
param.setUsername("test");
RemoteService service = Feign.builder().client(RibbonClient.create())
.encoder(new JacksonEncoder())
.decoder(new JacksonDecoder())
.options(new Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3))
.target(RemoteService.class, "http://remote-client/gradle-web");
for (int i = 1; i 10; i++) {
User result = service.getOwner(param);
System.out.println(result.getId() + "," + result.getUsername());
}
}
}
复制代码
现在来看remote-client.properties中的配置项,主要多是RemoteClient的配置机制
remote-client.ribbon.MaxAutoRetries=1
remote-client.ribbon.MaxAutoRetriesNextServer=1
remote-client.ribbon.OkToRetryOnAllOperations=true
remote-client.ribbon.ServerListRefreshInterval=2000
remote-client.ribbon.ConnectTimeout=3000
remote-client.ribbon.ReadTimeout=3000
remote-client.ribbon.listOfServers=127.0.0.1:8080,127.0.0.1:8085
remote-client.ribbon.EnablePrimeConnections=false
复制代码
所有的key都以remote-client开头,表明这些配置项作用于名为remote-client的服务。其实就是与之前绑定RemoteService接口的URL地址的schema相对应。
重点看remote-client.ribbon.listOfServers配置项,该配置项指定了服务生产端的真实地址。
在调用时会被替换为:
@RequestLine指定的地址进行拼接,得到最终请求地址。本例中最终请求地址为:
由于使用的ribbon,所以feign不再需要配置超时时长,重试策略。ribbon提供了更为完善的策略实现。
本例中,服务生产端是一个简单的springMvc,实现如下:
public class UserController {
public User list( User user) throws InterruptedException{
HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
user.setId(new Long(request.getLocalPort()));
user.setUsername(user.getUsername().toUpperCase());
return user;
}
}
复制代码
故障转移是通过remote-client.properties中的配置项进行配置。
负载均衡的策略又是如何设置呢?
import com.netflix.client.ClientFactory;
import com.netflix.client.config.IClientConfig;
import com.netflix.config.ConfigurationManager;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.ZoneAwareLoadBalancer;
import feign.Feign;
import feign.jackson.JacksonDecoder;
import feign.jackson.JacksonEncoder;
import feign.ribbon.LBClient;
import feign.ribbon.LBClientFactory;
import feign.ribbon.RibbonClient;
public class AppRun {
public static void main(String[] args) throws Exception {
ConfigurationManager.loadPropertiesFromResources("remote-client.properties");
User param = new User();
param.setUsername("test");
RibbonClient client = RibbonClient.builder().lbClientFactory(new LBClientFactory() {
public LBClient create(String clientName) {
IClientConfig config = ClientFactory.getNamedConfig(clientName);
ILoadBalancer lb = ClientFactory.getNamedLoadBalancer(clientName);
ZoneAwareLoadBalancer zb = (ZoneAwareLoadBalancer) lb;
zb.setRule(new RandomRule());
return LBClient.create(lb, config);
}
}).build();
RemoteService service = Feign.builder().client(client).encoder(new JacksonEncoder())
.decoder(new JacksonDecoder()).options(new Options(1000, 3500))
.retryer(new Retryer.Default(5000, 5000, 3)).target(RemoteService.class, "http://remote-client/gradle-web");
for (int i = 1; i 10; i++) {
User result = service.getOwner(param);
System.out.println(result.getId() + "," + result.getUsername());
}
}
}
复制代码
private IRule zoneAvoidanceRule() {
return new ZoneAvoidanceRule();
}
private IRule randomRule() {
return new RandomRule();
}
复制代码
不再使用RibbonClient.create()来创建默认的RibbonClient,而是通过RibbonClient.builder()获得feign.ribbon.Builder,进而设置LBClientFactory的实现来定制LBClient,在创建LBClient的过程中即可指定负载策略的具体实现。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tay3QQq8-1691467722037)(https://pic.imgdb.cn/item/64d0dc6a1ddac507cc857b30.png)]
获取以上资源请访问开源项目 点击跳转