负载均衡Ribbon

1.1         消费者

1.1.1      创建Maven工程

1.1.2      pom.xml

<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>

    <groupId>com.tedu</groupId>

    <artifactId>h1</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.5.4.RELEASE</version>

        <relativePath /> <!-- lookup parent from repository -->

    </parent>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <java.version>1.8</java.version>

    </properties>

    <dependencies>

        <dependency>

             <groupId>org.springframework.cloud</groupId>

             <artifactId>spring-cloud-starter-eureka</artifactId>

        </dependency>

        <dependency>

             <groupId>org.springframework.boot</groupId>

             <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

    </dependencies>

    <dependencyManagement>

        <dependencies>

             <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-dependencies</artifactId>

                 <version>Dalston.SR1</version>

                 <type>pom</type>

                 <scope>import</scope>

             </dependency>

        </dependencies>

    </dependencyManagement>

</project>

1.1.3      application.yml

server:

  port: 8010

spring:

  application:

    name: consumer-client

eureka:

  client:

    serviceUrl:

      defaultZone: http://user:password123@localhost:8761/eureka

logging:

  level:

    root: INFO     

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 cn.tedu.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 {

    @Autowired

    private RestTemplate restTemplate;

   

    @GetMapping("/hello/{name}")

    @ResponseBody

    public String hello(@PathVariable String name){

        String url = "http://localhost:7900/hello";   //直接访问

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

    }

}

1.1.5      ConsumerRunApp.java

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

package cn.tedu;

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 ConsumerRunApp {

    @Bean

    public RestTemplate restTemplate(){

        return new RestTemplate();

    }

   

    public static void main(String[] args) {

        SpringApplication.run(ConsumerRunApp.class, args);

    }

}

1.1.6      测试

执行顺序:

先启动服务端 8761    eureka-server        EurekaServerApp

在启动提供者1   7900    provider-user        ProviderRunApp

在启动提供者2   7901    provider-user2       Provider2RunApp

最后启动消费者   8010    consumer-client  ConsumerRunApp

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

访问请求:               http://localhost:8010/hello/tony

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

1.2         负载均衡Ribbon

1.2.1      问题

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

    public String hello(){

        String url = "http://localhost:7900/hello";

        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工程内容

 

1.3.2      pom.xml

<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>

    <groupId>com.tedu</groupId>

    <artifactId>h1</artifactId>

    <version>0.0.1-SNAPSHOT</version>

    <parent>

        <groupId>org.springframework.boot</groupId>

        <artifactId>spring-boot-starter-parent</artifactId>

        <version>1.5.4.RELEASE</version>

        <relativePath /> <!-- lookup parent from repository -->

    </parent>

    <properties>

        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>

        <java.version>1.8</java.version>

    </properties>

    <dependencies>

        <dependency>

             <groupId>org.springframework.cloud</groupId>

             <artifactId>spring-cloud-starter-eureka</artifactId>

        </dependency>

        <dependency>

             <groupId>org.springframework.boot</groupId>

             <artifactId>spring-boot-starter-web</artifactId>

        </dependency>

    </dependencies>

    <dependencyManagement>

        <dependencies>

             <dependency>

                 <groupId>org.springframework.cloud</groupId>

                 <artifactId>spring-cloud-dependencies</artifactId>

                 <version>Dalston.SR1</version>

                 <type>pom</type>

                 <scope>import</scope>

             </dependency>

        </dependencies>

    </dependencyManagement>

</project>

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

因为eureka中已经含有对ribbon的支持

 

1.3.3      application.yml

server:

  port: 8010

spring:

  application:

    name: consumer-client

eureka:

  client:

    serviceUrl:

      defaultZone: http://user:password123@localhost:8761/eureka

logging:

  level:

    root: INFO

1.3.4      HelloController.java

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

package cn.tedu.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 {

    @Autowired

    private RestTemplate restTemplate;

   

    @GetMapping("/hello/{name}")

    @ResponseBody

    public String hello(@PathVariable String name){

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

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

    }

}

1.3.5      ConsumerRunApp.java

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

package cn.tedu;

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 ConsumerRunApp {

    @Bean

    @LoadBalanced    //Ribbon负载均衡

    public RestTemplate restTemplate(){

        return new RestTemplate();

    }

   

    public static void main(String[] args) {

        SpringApplication.run(ConsumerRunApp.class, args);

    }

}

1.3.6      测试

执行顺序:

先启动服务端 8761    eureka-server        EurekaServerApp

在启动提供者1   7900    provider-user        ProviderRunApp

在启动提供者2   7901    provider-user2       Provider2RunApp

最后启动消费者   8010    consumer-client  ConsumerRunApp

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

 

访问请求:               http://localhost:8010/hello/tony

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

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 cn.config;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import com.netflix.loadbalancer.IRule;

import com.netflix.loadbalancer.RandomRule;

/**

 *

 * 自定义Ribbon配置

 * 规定:这个类不能再@ComponentScan@SpringBootApplication本包和子包下,否则引起@RibbonClients扫描冲突

 * 注意:随机第一次打断点进入,之后多次刷新就不进入,可能由于本地缓存原因

 */

@Configuration

public class RibbonRuleConfig {

    @Bean

    public IRule ribbonRule(){

        return new RandomRule();

    }

}

1.4.2      ConsumerRunApp.java

增加一个注解@RibbonClient即可

package cn.tedu;

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;

import cn.config.RibbonRuleConfig;

@SpringBootApplication

@EnableEurekaClient

@RibbonClient(name="provider-user", configuration=RibbonRuleConfig.class)

public class ConsumerRunApp {

    @Bean

    @LoadBalanced    //Ribbon负载均衡

    public RestTemplate restTemplate(){

        return new RestTemplate();

    }

   

    public static void main(String[] args) {

        SpringApplication.run(ConsumerRunApp.class, args);

    }

}


 

猜你喜欢

转载自www.cnblogs.com/wood-life/p/10332499.html