Spring Cloud中使用Ribbon(八)

用注解和配置文件的方式引用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

将MyLoadBalanceClient类的@RibbonClient注解注释掉,然后在eureka-consumer的application.yml的文件中配置我们自定义的规则,上一篇博客有讲过,配置规则是:"客户端名称"."命名空间"."属性名",我们需要配置的规则是:NFLoadBalancerRuleClassName,完整的application.yml配置如下:
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

源码点击这里

Spring Cloud系列:

Spring Cloud介绍与环境搭建(一)

Spring Boot的简单使用(二)

Spring Cloud服务管理框架Eureka简单示例(三)

Spring Cloud服务管理框架Eureka项目集群(四)

猜你喜欢

转载自blog.csdn.net/mrspirit/article/details/80215604