1. 程式人生 > >eureka的負載均衡、ribbon的原理

eureka的負載均衡、ribbon的原理

ribbon 來完成負載均衡
RibbonLoadBalanceClient 類,是用來 進行負載均衡的;
其中有個 choose 的方法,原始碼如下:
3

意思是,對serverId 進行例項化;
建立測試類;

那麼對其進行詳解下:

RibbonLoadBalanceClient 中有getServer( )這個獲取服務的方法:

	@Override
	public <T> T execute(String serviceId, LoadBalancerRequest<T> request) throws IOException {
ILoadBalancer loadBalancer = getLoadBalancer(serviceId); Server server = getServer(loadBalancer); if (server == null) { throw new IllegalStateException("No instances available for " + serviceId); } RibbonServer ribbonServer = new RibbonServer(serviceId, server, isSecure(server, serviceId)
, serverIntrospector(serviceId).getMetadata(server)); return execute(serviceId, ribbonServer, request); }

s
點選 getServer 跟進去,底層維護了 chooseServer()的一個方法,繼續點

	protected Server getServer(ILoadBalancer loadBalancer) {
		if (loadBalancer == null) {
			return null;
		}
		return loadBalancer.chooseServer
("default"); // TODO: better handling of key }

fg
進入chooseServer 跟蹤到 ILoadBalancer
Ctrl alt B 檢視, 該介面的一個 實現類 BaseLoadBalancer

該介面

public class BaseLoadBalancer extends AbstractLoadBalancer implements PrimeConnectionListener, IClientConfigAware {
    private static Logger logger = LoggerFactory.getLogger(BaseLoadBalancer.class);
    //  rule的預設值 
    private static final IRule DEFAULT_RULE = new RoundRobinRule();
    private static final BaseLoadBalancer.SerialPingStrategy DEFAULT_PING_STRATEGY = new BaseLoadBalancer.SerialPingStrategy();
    private static final String DEFAULT_NAME = "default";
    private static final String PREFIX = "LoadBalancer_";
    // IRule 類
    protected IRule rule;
    protected IPingStrategy pingStrategy;
    protected IPing ping;
    @Monitor(
        name = "LoadBalancer_AllServerList",
        type = DataSourceType.INFORMATIONAL
    )

78

private static final IRule DEFAULT_RULE = new RoundRobinRule();
可以得知,IRule rule 的預設值是 RoundRobinRule 的一個物件,即輪詢的物件,即預設的規則是輪詢的方式;

 public Server choose(Object key) {
        ILoadBalancer lb = this.getLoadBalancer();
        Optional<Server> server = this.getPredicate().chooseRoundRobinAfterFiltering(lb.getAllServers(), key);
        return server.isPresent() ? (Server)server.get() : null;
    }

4

在服務的消費者新增@LoadBalanced 註解;

@SpringBootApplication
@EnableDiscoveryClient
public class ConsumerApplication {

    @Bean
    @LoadBalanced   //新增負載均衡
    public RestTemplate getRestTemplate(){
        return  new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

直接使用服務名來查詢服務:

@RestController
@RequestMapping("consumer")
public class ConsumerController {

    /**
     * 注入  springCloud 的DiscoveryClient
     */
//    @Autowired
//    private DiscoveryClient discoveryClient;

    @Autowired
    private RestTemplate restTemplate;
    @GetMapping("{id}")
    public User get(@PathVariable("id")Long id){

        // 從eureka 中取出一個服務
//        List<ServiceInstance> instances = discoveryClient.getInstances("user-service");
//        ServiceInstance serviceInstance = instances.get(0);
        //  從服務中 獲取 port 以及host 組成url 、 進行查詢
//        String url = String.format("http://%s:%s/user/%s", serviceInstance.getHost(), serviceInstance.getPort(), id);
//        String url="http://localhost:8081/user/"+id;
//        return  restTemplate.getForObject(url, User.class, id);
        String url="http://user-service/user/"+id;
        return   restTemplate.getForObject(url,User.class );
    }
}

訪問 http://localhost:8080/consumer/1
23

建立測試類,重寫RibbonLoadBalanceClient 類 中的choose 方法,進行測試;

/**
 * @auther SyntacticSugar
 * @data 2018/11/29 0029下午 9:04
 */
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ConsumerApplication.class)
public class LoadBalancedTest {

    @Autowired
    RibbonLoadBalancerClient loadBalancerClient;
    @Test
    public void test() {
        for (int i = 0; i < 10; i++) {
            ServiceInstance instance = loadBalancerClient.choose("user-service");
            System.out.println(instance.getPort());
        }
    }
}

執行:
1
可以看到負載均衡預設是採用輪詢的方式;

對配置檔案進行更改,可以更改IRule 的實現類,從而修改規則;

user-service:
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

檢視 IRule 的實現類如下;
s