Spring Cloud 之Ribbon

在微服务架构中,业务都会被拆分成一个独立的服务,服务与服务的通讯是基于http restful的。Spring Cloud有两种服务调用方式,一种是Ribbon+RestTemplate,另一种是Feign。在这里首先讲解下基于Ribbon+Rest。

一、Ribbon简介

Ribbon是Netflix发布的负载均衡器,它有助于控制HTTP和TCP客户端的行为。为Ribbon配置服务提供者地址列表后,Ribbon就可基于某种负载均衡算法,自动地帮助服务消费者去请求。Ribbon默认为我们提供了很多的负载均衡算法,例如轮询、随机等。当然,我们也可为Ribbon实现自定义的负载均衡算法。

Ribbon 已经默认实现了这些配置bean:

  • IClientConfig ribbonClientConfig: DefaultClientConfigImpl

  • IRule ribbonRule: ZoneAvoidanceRule

  • IPing ribbonPing: NoOpPing

  • ServerList ribbonServerList: ConfigurationBasedServerList

  • ServerListFilter ribbonServerListFilter: ZonePreferenceServerListFilter

  • ILoadBalancer ribbonLoadBalancer: ZoneAwareLoadBalancer

二、准备工作

本篇文章基于上一篇的工程,启动了eureka server(服务注册中心)和service hi(服务提供者)两个工程。

编写service hi工程服务,这里我们简单写一下,输出传入的参数和端口号就可以,新建一个HiController,代码如下:

@RestController
@RequestMapping("/hi")
public class HiController {
    @Value("${server.port}")
    private String port;

    @RequestMapping("{name}")
    public String hi(@PathVariable String name){
        return "hi "+name+" i am from port:"+port;
    }
}

现在我们需要启动两个service hi工程,一个端口为9091,另一个为9092,首先点击右上角的 Edit Configurations

Spring Cloud 之Ribbon
可以看到这里有 eureka serverservice hi 两个启动类,我们复制一个 service hi 启动类,在原来的启动类名称加上 9091,新复制的一个加上 9092,便于区分,最后在9092启动类加上参数 -Dport=9092

Spring Cloud 之Ribbon
修改service-hi工程的application.yml文件:

server:
  port: ${port:9091}

spring:
  application:
    name: service-hi

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

port: ${port:9091} 表示port参数有值则使用,没有则使用9091。
我们在9092启动类定义了port参数,这样启动9091启动类时就是9091端口,启动9092启动类就是9092端口

我们分别启动9091和9092

Spring Cloud 之Ribbon
查看Eureka Server监控页面,这时会发现service-hi 注册了两个实例,这样准备工作完成。

Spring Cloud 之Ribbon

三、建一个服务消费者

新建一个springBoot工程,取名为 service-consumer,在pom.xml文件分别引入依赖,spring-cloud-starter-netflix-eureka-clientspring-boot-starter-webspring-boot-starter-test

因为Eureka已经集成了Ribbon,所以我们无需引入Ribbon依赖。

<?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">
    <parent>
        <artifactId>springCloudTest</artifactId>
        <groupId>com.test</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>service-consumer</artifactId>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- Eureka客户端 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
    </dependencies>

</project>

编写application.yml配置文件,指定服务注册中心地址http://127.0.0.1:10086/eureka,服务名称为 service-consumer,端口号为8760。文件如下:

server:
  port: 8760

spring:
  application:
    name: service-consumer

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka

在工程的启动类中,通过@EnableDiscoveryClient向服务中心注册;并且向程序的ioc注入一个bean: restTemplate,并通过@LoadBalanced注解表明这个restTemplate开启负载均衡的功能。

@SpringBootApplication
@EnableDiscoveryClient  //开启eureka客户端发现功能
public class ConsumerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class, args);
    }

    @Bean
    @LoadBalanced	//表明这个restRemplate开启负载均衡的功能
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }
}



写一个测试类HelloController,通过之前注入ioc容器的restTemplate来消费service-hi服务的“/hi”接口。

开启Ribbon负载均衡后,我们直接用服务名称替代了具体的url地址,在Ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名。

代码如下:

@RestController
@RequestMapping("/hello")
public class HelloController {
    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("{name}")
    public String hello(@PathVariable String name){
        String url = "http://service-hi/hi/"+name;
        return restTemplate.getForObject(url,String.class);
    }

}

四、启动测试

分别启动eureka-server、两个service-hi工程(9091、9092),最后启动服务消费者service-consumer,查看Eureka监控页面:

Spring Cloud 之Ribbon
在浏览器上多次访问:http://127.0.0.1:8760/hello/wangYouXiaoFeng 交替显示:

hi wangYouXiaoFeng i am from port:9091
hi wangYouXiaoFeng i am from port:9092

这说明当我们通过调用restTemplate.getForObject(url,String.class);方法时,已经做了负载均衡,访问了不同的端口的服务实例。

五、负载均衡策略

Ribbon默认的负载均衡策略是简单的轮询

在刚刚的测试中,我们不断访问 http://127.0.0.1:8760/hello/wangYouXiaoFeng 发现 9091和9092 端口是交替显示的,说明确实是轮询方式

SpringBoot也帮我们提供了修改负载均衡规则的配置入口,现在我们修改负载均衡策略为随机:

server:
  port: 8760

spring:
  application:
    name: service-consumer

eureka:
  client:
    service-url:
      defaultZone: http://127.0.0.1:10086/eureka
service-hi: #修改Ribbon负载均衡规则,更改为随机算法
  ribbon:
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

格式:{服务名称}.ribbon.NFLoadBalancerRuleClassName,值就是IRule的实现类。

再次测试 http://127.0.0.1:8760/hello/wangYouXiaoFeng :发现9091和9092是随机显示的了。

上一篇:【分布式】SpringCloud(4)--Ribbon负载均衡


下一篇:Ribbon 负载均衡服务调用