一、Ribbon简介
Ribbon是一个客户端负载均衡器,它可以很好地控制HTTP和TCP客户端的行为。
Ribbon中的中心概念是指定客户端的概念。每个负载平衡器是组合的组合的一部分,它们一起工作以根据需要联系远程服务器,并且集合具有您将其作为应用程序开发人员(例如使用@FeignClient
注释)的名称。Spring Cloud使用RibbonClientConfiguration
为每个命名的客户端根据需要创建一个新的合奏作为ApplicationContext
。这包含(除其他外)ILoadBalancer
,RestClient
和ServerListFilter
。
在上一篇文章,讲了服务的注册和发现。Springcloud有两种服务调用方式,一种是ribbon+restTemplate,另一种是feign。本篇文章讲解下基于ribbon+rest。
二、创建一个注册中心(ribbon-server)和一个服务消费者(service-ribbon1)
具体创建方式和上篇的“SpringCloud——服务的注册与发现Eureka”,请参考:
地址:https://blog.csdn.net/typ1805/article/details/82621881
项目结构如图:
三、建一个服务消费者(service-ribbon)
1、所依赖的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>
<groupId>com.example.demo.ribbon</groupId>
<artifactId>service-ribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>service-ribbon</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.example.demo</groupId>
<artifactId>springcloud-ribbon</artifactId>
<version>0.0.1-SNAPSHOT</version>
</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.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<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-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2、配置文件application.yml如下:
server:
port: 8083
eureka:
client:
service-url:
defaultZone: http://localhost:8081/eureka/
spring:
application:
name: service-ribbon
在配置文件指定服务的注册中心地址为http://localhost:8081/eureka/,程序名称为 service-ribbon,程序端口为8084 。
3、启动类添加注解@EnableDiscoveryClient向服务中心注册,并且向程序的ioc注入一个bean: restTemplate;并通过@LoadBalanced注解表明这个restRemplate开启负载均衡的功能。
package com.example.demo.ribbon;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
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
@EnableDiscoveryClient
public class ServiceRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceRibbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
}
4、编写一个测试类TestService,通过之前注入ioc容器的restTemplate来消费service-ribbon1服务的“/holle”接口,这里直接用的程序名替代了具体的url地址,在ribbon中它会根据服务名来选择具体的服务实例,根据服务实例在请求的时候会用具体的url替换掉服务名,代码如下:
接口代码:
package com.example.demo.ribbon.service;
/**
* 路径:com.example.demo.ribbon.service
* 类名:
* 功能:《用一句描述一下》
* 备注:
* 创建人:typ
* 创建时间:2018/9/11 14:56
* 修改人:
* 修改备注:
* 修改时间:
*/
public interface TestService {
public String test(String name);
}
实现类代码:
package com.example.demo.ribbon.service.impl;
import com.example.demo.ribbon.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
/**
* 路径:com.example.demo.ribbon.service.impl
* 类名:
* 功能:《用一句描述一下》
* 备注:
* 创建人:typ
* 创建时间:2018/9/11 14:57
* 修改人:
* 修改备注:
* 修改时间:
*/
@Service
public class TestServiceImpl implements TestService {
@Autowired
RestTemplate restTemplate;
@Override
public String test(String name) {
return restTemplate.getForObject("http://SERVICE-RIBBON1/holle?name="+name,String.class);
}
}
4、编写controller类,调用service的服务。
package com.example.demo.ribbon.controller;
import com.example.demo.ribbon.service.TestService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 路径:com.example.demo.ribbon.controller
* 类名:
* 功能:《用一句描述一下》
* 备注:
* 创建人:typ
* 创建时间:2018/9/11 15:00
* 修改人:
* 修改备注:
* 修改时间:
*/
@RestController("/")
public class TestController {
@Autowired
private TestService testService;
@GetMapping("/test")
public String test(String name){
return testService.test(name);
}
}
四、启动工程测试
1、先启动ribbon-server
2、使用多个实例来启动service-ribbon1
如何启动多个实例:
在IDEA上点击Application右边的下三角 ,弹出选项后,点击Edit Configuration
打开配置后,将默认的Single instance only(单实例)的钩去掉
通过修改application文件的server.port的端口,来启动多个实例,需要多个端口,分别启动。
service-ribbon1启动成功如图:
这时会发现:service-ribbon1在ribbon-server注册了2个实例,端口分别为8082和8084这就相当于一个小的集群。
3、启动service-ribbon,在浏览器上多次访问http://localhost:8084/test?name=张三,浏览器交替显示:
holle 张三, port:8084
holle 张三, port:8082
说明通过调用restTemplate.getForObject("http://SERVICE-RIBBON1/holle?name="+name,String.class)方法时,已经做了负载均衡,访问了不同的端口的服务实例。
五、Ribbon的架构与原理
Ribbon的工作 分为两步:
1、第一步优先选择Eureka Server,它优先选择在同一个Zone且负载较少的Server;
2、第二步在根据用户指定的策略,在从Server取到的服务注册列表中选择一个地址。其中Ribbon提供了多重策略,例如轮询round robin、随机Random、根据相应时间加权等。