负载均衡Ribbon(三)

更多内容参见个人技术博客,无广告欢迎关注

1.1         消费者

1.1.1      创建Maven工程

1.1.2      pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.wood</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wood</groupId>
<artifactId>consumer-client</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer-client</name>
<description>Demo project for Spring Boot</description>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>

1.1.3      application.properties

server.port=8091
spring.application.name=consumer-client
eureka.client.serviceUrl.defaultZone=http://localhost:6001/eureka

   

1.1.4      HelloController.java

RestTemplate是Spring提供的用于访问Rest服务的客户端,

RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,

可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。

ClientHttpRequestFactory接口主要提供了两种实现方式

1、一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接。

2、一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。

RestTemplate对象是在RunApp中声明并创建的,用它才可以实现负载均衡,同时注意url中的地址为VIP虚拟IP,为application.yml中配置的application-name

package com.wood.consumerclient.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
public class HelloController {

/**
* RestTemplate是Spring提供的用于访问Rest服务的客户端,
*
* RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
*
* 调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,
*
* 可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
*
* ClientHttpRequestFactory接口主要提供了两种实现方式
*
* 1、一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接。
*
* 2、一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。
*
* RestTemplate对象是在RunApp中声明并创建的,用它才可以实现负载均衡,同时注意url中的地址为VIP虚拟IP,为application.yml中配置的application-name。
* */
@Autowired
private RestTemplate restTemplate
;

@GetMapping("/hello/{name}")
@ResponseBody
public String hello(@PathVariable String name){
String url = "http://localhost:8081/hello" + name; //直接访问
return this.restTemplate.getForObject(url, String.class);
}
}

1.1.5      ConsumerRunApp.java

重点在启动时要初始化RestTemplate对象,同时设置@LoadBalanced负载均衡

package com.wood.consumerclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
public class ConsumerClientApplication {

@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}


public static void main(String[] args) {
SpringApplication.run(ConsumerClientApplication.class, args);
}

}

1.1.6      测试

package com.wood.consumerclient;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
public class ConsumerClientApplication {

@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(ConsumerClientApplication.class, args);
}

}

执行顺序:

先启动服务端     6001    eureka-server       EurekaServerApplication 

在启动提供者1   8081    provider-a            ProviderAApplication

在启动提供者2   8082    provider-b            ProviderBApplication

最后启动消费者  8091    consumer-client    ConsumerClientApplication

访问Eureka控制台:      http://localhost:6001/

访问请求:               http://localhost:8091/hello/wood

1.2         负载均衡Ribbon

1.2.1      问题

之前我们使用的是直接访问的方式,能否实现提供者端负载均衡呢?

    public String hello(){

        String url = "http://localhost:8091/hello/wood";

        return restTemplate.getForObject(url, String.class);

    }

这是直接访问提供者,只能写死提供者的端口,并未使用Eureka注册中心,这样当服务宕机,我们也无从知道,只能访问超时。同时也无法“多例”服务进行支撑(负载均衡)。

1.2.2      Ribbon

Feignnetflix开发的声明式、模板化的http客户端,在使用时就像调用本地(服务消费者自己)的方法一般,帮助我们更加优雅的调用服务提供者的APIFeign自身支持springMVC,还整合了EurekaRibbon,极大的简化了Feign的使用。就整合Euraka而言,只需和普通的服务配置Eureka server的信息即可。整合Ribbon,就意味着不再需要通过标注@LoadBalanced的实例化后的RestTemplate去调用服务提供者方法了。Feign只需通过简单的定义一个接口即可实现负载均衡。

nginx不同,它是客户端侧负载均衡。

 

1.2.3      负载均衡策略

常见提供的负载均衡算法有三种:

第一种也是默认为轮询

第二种为random随机

第三种为WeightedResponseTimeRule,响应时间

 

1.2.4      导包

无需引入jar包,在spring-cloud-start-euraka已经依赖了ribbonjar包。

   

1.3         消费者Ribbon

1.3.1      修改Maven工程内容

新建子工程 comsumer-client-ribbon,内容和consumer-client一样,修改端口为8092

spring-cloud父工程pom.xml

<!--Maven项目可以继承,三个子工程-->
<modules>
<module>eureka-server</module>
<module>provider-a</module>
<module>provider-b</module>
<module>consumer-client</module>
<module>consumer-client-ribbon</module>
</modules> 

 1.3.2      pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.wood</groupId>
<artifactId>spring-cloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.wood</groupId>
<artifactId>consumer-client-ribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer-client-ribbon</name>
<description>Demo project for Spring Boot</description>

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
</project>

注意:怎么没有依赖ribbonjar包呢?

因为eureka中已经含有对ribbon的支持,不需要额外的添加依赖

 

1.3.3      application.properties

server.port=8092
spring.application.name=consumer-client-ribbon
eureka.client.serviceUrl.defaultZone=http://localhost:6001/eureka
# 定义根目录下日志级别
logging.level.root=INFO

1.3.4      HelloController.java

RestTemplate对象是在RunApp中声明并创建的,用它才可以实现负载均衡,同时注意url中的地址为VIP虚拟IP,为application.yml中配置的application-name

package 

com.wood.consumerclientribbon.controller

;

import

org.springframework.beans.factory.annotation.

Autowired;
import

org.springframework.web.bind.annotation.

GetMapping;
import

org.springframework.web.bind.annotation.

PathVariable;
import

org.springframework.web.bind.annotation.

ResponseBody;
import

org.springframework.web.bind.annotation.

RestController;
import

org.springframework.web.client.RestTemplate

;

@RestController
public class

HelloController {

/**
* RestTemplate是Spring提供的用于访问Rest服务的客户端,
*
* RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
*
* 调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,
*
* 可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
*
* ClientHttpRequestFactory接口主要提供了两种实现方式
*
* 1、一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接。
*
* 2、一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。
*
* RestTemplate对象是在RunApp中声明并创建的,用它才可以实现负载均衡,同时注意url中的地址为VIP虚拟IP,为application.yml中配置的application-name。
* */
@Autowired
private

RestTemplate

restTemplate;

@GetMapping

(

"/hello/{name}"

)

@ResponseBody
public

String

hello

(

@PathVariable 

String name){

// VIP虚拟IP,提供者的application-name:provider-user
String url = "http://provider-user/hello/"+name
;
return this

.

restTemplate

.getForObject(url

, 

String.

class

)

;

}
}

1.3.5      ConsumerClientRibbonApplication.java

重点在启动时要初始化RestTemplate对象,同时设置@LoadBalanced负载均衡

package com.wood.consumerclientribbon;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
public class ConsumerClientRibbonApplication {

@Bean
@LoadBalanced //Ribbon负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(ConsumerClientRibbonApplication.class, args);
}

}

1.3.6      测试

执行顺序:

先启动服务端     6001    eureka-server        EurekaServerApplication

在启动提供者1   8081    provider-user         ProviderAApplication

在启动提供者2   8082    provider-user2       ProviderBApplication

最后启动消费者  8092    consumer-client-ribbon  ConsumerClientRibbonApplication

访问Eureka控制台:      http://localhost:6001/

 

访问请求:               http://localhost:8092/hello/wood

交替出现1:wood2:wood,说明两个提供者交替执行。这里注意有时可能提供者2还未准备好不能工作,多刷一会就正常了。可以看出Ribbon默认的负载均衡策略是轮询。

服务提供者A:wood

服务提供者B:wood 

1.3.7      小结:怎么把普通的消费者改为Ribbon消费者

    Controller  

    @RequestMapping("/hello")

    public String hello(){

        //provider-user就是Eureka中提供服务

        String url = "http://provider-user/hello";

        //发起对Eureka中某个服务进行访问,返回值类型和业务返回值类型一致

        return restTemplate.getForObject(url, String.class);

    }

启动类

@EnableEurekaClient

@SpringBootApplication

public class CustomerClientRunApp {

    //初始化RestTemplate对象,Spring就初始化这个beand,就可以在Controller中注入

    @Bean

    @LoadBalanced    //实现负载均衡

    public RestTemplate restTemplate(){

        return new RestTemplate();

    }

1.4         拓展:Ribbon随机负载算法

1.4.1      RibbonRuleConfig.java

自定义规则扩展对象

package com.wood.config;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;

/**
* <p>
* RibbonRuleConfig
* </p>
* 自定义Ribbon配置
* 规定:这个类不能再@ComponentScan和@SpringBootApplication本包和子包下,否则引起@RibbonClients扫描冲突
* 注意:随机第一次打断点进入,之后多次刷新就不进入,可能由于本地缓存原因
*/
public class RibbonRuleConfig {
@Bean
public IRule ribbonRule(){
return new RandomRule();
}
}

1.4.2      ConsumerClientRibbonApplication.java

增加一个注解@RibbonClient(name="provider-user", configuration=RibbonRuleConfig.class)

package com.wood.consumerclientribbon;

import com.wood.config.RibbonRuleConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="provider-user", configuration=RibbonRuleConfig.class)
public class ConsumerClientRibbonApplication {

@Bean
@LoadBalanced //Ribbon负载均衡
public RestTemplate restTemplate(){
return new RestTemplate();
}

public static void main(String[] args) {
SpringApplication.run(ConsumerClientRibbonApplication.class, args);
}

}

附上代码 demo.zip

https://pan.baidu.com/s/1X8GSuqMSMiyMz747aZtQTw 

原文地址:https://www.cnblogs.com/wood-life/p/10332499.html