Spring Cloud中使用Ribbon(八)
用注解和配置文件的方式引用Spring Cloud整合的Ribbon1.准备工作为了实现负载均衡的效果,我们使用Spring Cloud服务管理框架Eureka简单示例(三)底部的源代码稍加修改使用(如果下面的内容看不懂,可以先查看上面这篇博文),eureka-provider需要启动两个实例,修改启动类ProviderApp的main()方法,通过在控制台输入不同的端口(8082和8083)来启
用注解和配置文件的方式引用Spring Cloud整合的Ribbon
1.准备工作
为了实现负载均衡的效果,我们使用Spring Cloud服务管理框架Eureka简单示例(三)底部的源代码稍加修改使用(如果下面的内容看不懂,可以先查看上面这篇博文),eureka-provider需要启动两个实例,修改启动类ProviderApp的main()方法,通过在控制台输入不同的端口(8082和8083)来启动实例:
package com.init.springCloud;
import java.util.Scanner;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ProviderApp {
public static void main(String[] args) {
@SuppressWarnings("resource")
Scanner scan = new Scanner(System.in);
String port = scan.nextLine();
new SpringApplicationBuilder(ProviderApp.class).properties("server.port=" + port).run(args);
}
}
为了区分服务调用者使用的是哪一个服务,为Person类添加info属性:
package com.init.springCloud;
import lombok.Data;
@Data
public class Person {
private Integer id; //主键ID
private String name; //姓名
private String info; //信息,根据URL地址查看服务的来源
}
同时修改控制器ProviderController,把请求的参数传输到Person类的info属性里:
package com.init.springCloud;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ProviderController {
@RequestMapping(value = "/search/{id}", method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public Person searchPerson(@PathVariable Integer id, HttpServletRequest request){
Person person = new Person();
person.setId(id);
person.setName("Spirit");
person.setInfo(request.getRequestURL().toString());
return person;
}
}
之后,依次启动euraka-server,两个eureka-provider服务(8082和8083端口),eureka-consumer,访问:http://localhost:8081/router,验证我们的配置是否成功,成功的标志是轮询调用两个服务返回结果。
2.使用注解引用Ribbon
在eureka-consumer的com.init.springCloud包下新建MyRule类,来自Ribbon负载均衡器详细介绍(七)中创建的规则,新增一段打印文字,用来显示是否使用了我们的规则,完整代码如下:
package com.init.springCloud;
import java.util.List;
import java.util.Random;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
public class MyRule implements IRule {
private ILoadBalancer lb;
@Override
public Server choose(Object key) {
System.out.println("这是自定义的规则");
Random random = new Random();
Integer num = random.nextInt(10);//在0-9这10个随机数里取值
//获取传输负载均衡器里所有的服务
List<Server> servers = lb.getAllServers();
if(num>7){//返回8082端口服务
return chooseServerByPort(servers,8082);
}
//返回8083端口服务
return chooseServerByPort(servers,8083);
}
private Server chooseServerByPort(List<Server> servers,Integer port){
for (Server server : servers) {
if(server.getPort() == port){
return server;
}
}
return null;
}
@Override
public void setLoadBalancer(ILoadBalancer lb) {
this.lb = lb;
}
@Override
public ILoadBalancer getLoadBalancer() {
return lb;
}
}
之后创建一个MyConfig类,用于返回我们自定义的负载均衡规则:
package com.init.springCloud;
import org.springframework.context.annotation.Bean;
import com.netflix.loadbalancer.IRule;
public class MyConfig {
@Bean
public IRule getMyRule(){
return new MyRule();
}
}
再新建MyLoadBalanceClient类,使用我们的配置去调用自定义规则:
package com.init.springCloud;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
@RibbonClient(name = "eureka-provider", configuration = MyConfig.class)
public class MyLoadBalanceClient {
}
这个时候重启eureka-consumer项目,多次访问:http://localhost:8081/router,我们就会看到调用8083服务明显比8082服务的次数多,控制台也显示调用了我们的自定义规则:
3.使用配置文件引用Ribbon
server:
port: 8081
spring:
application:
name: eureka-consumer
eureka-provider:
ribbon:
NFLoadBalancerRuleClassName: com.init.springCloud.MyRule
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
重新启动eureka-consumer项目,多次访问:http://localhost:8081/router,我们就会看到调用8083服务明显比8082服务的次数多,控制台同样也显示调用了我们的自定义规则。
使用Spring Cloud封装好的Ribbon
Spring Cloud将Ribbon整合之后,使用了一个叫做LoadBalancerClient的客户端来做服务调用,这个客户端有一个choose的方法,传入服务的ID就可以依据规则从对应的服务实例中获取到服务,在com.init.springCloud下的ConsumerController控制器新建getMyDefinedService方法并访问http://localhost:8081/service:
@Autowired
private LoadBalancerClient client;
@GetMapping(value = "/service")
@ResponseBody
public void getMyDefinedService(){
ServiceInstance instance = client.choose("eureka-provider");
System.out.println("地址:"+instance.getHost()+",端口:"+instance.getPort());
}
可以看到LoadBalancerClient使用了我们自定义的负载均衡规则:
我们也可以去探寻一下LoadBalancerClient底层默认使用了什么样的负载均衡器,又使用了什么样的负载规则。引入SpringClientFactory,获取默认的负载均衡器类和对应的规则方法,同样在ConsumerController控制器里添加方法:
@Autowired
private SpringClientFactory factory;
@GetMapping(value = "/rule")
@ResponseBody
public void getMyDefinedRule(){
ILoadBalancer balancer = factory.getLoadBalancer("default");
System.out.println("Spring Cloud默认使用的均衡器:"+balancer);
DynamicServerListLoadBalancer balancer2 = (DynamicServerListLoadBalancer)factory.getLoadBalancer("default");
System.out.println("默认使用的规则:"+balancer2.getRule().getClass().getName());
DynamicServerListLoadBalancer balancer3 = (DynamicServerListLoadBalancer)factory.getLoadBalancer("eureka-provider");
System.out.println("eureka-provider使用的规则:"+balancer3.getRule().getClass().getName());
}
访问:http://localhost:8081/rule,控制台输出了Spring Cloud整合Ribbon默认使用的负载均衡器和负载均衡规则,以及eureka-provider使用的我们自定义负载均衡规则。
这里Spring Cloud默认使用的ZoneAvoidanceRule规则,在上一篇博客中也提到了,它是指使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone的所有server,AvailabilityPredicate用于过滤掉连接数过多的Server。
如果我们要覆盖默认的负载均衡规则,只需要在配置文件中将Ribbon配置的客户端名称改为“default”就OK了:
default:
ribbon:
NFLoadBalancerRuleClassName: com.init.springCloud.MyRule
最后,大家有什么不懂的或者其他需要交流的内容,也可以进入我的QQ讨论群一起讨论:654331206
Spring Cloud系列:
Spring Cloud服务管理框架Eureka简单示例(三)
更多推荐
所有评论(0)