一、Ribbon的概述
Spring Cloud Ribbon 是基于 Netflix Ribbon 实现的一套客户端负载均衡的工具;
Ribbon主要功能是提供客户端的软件负载均衡算法,将Netflix的中间服务连接在一起,Ribbon客户端组件提供一系列完善的配置项,如连接超时,重试等。就是在配置文件中列出Loade Balancer(简称LB)后面的所有机器,Ribbon会自动的帮助基于某种规则(轮询,随机等)去连接这些机器。也可以使用 Ribbon 实现自定义的负载均衡算法。
LB,即负载均衡,在微服务或分布式集群中经常用的一种应用;负载均衡简单的说就是将用户的请求平摊到多个服务上,从而达到系统的高可用;常见的负载均衡有:nginx、LVS、硬件F5 等;
相应的中间件,例如:dubbo 和 Spring cloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
二、Ribbon的负载均衡
![](https://img2018.cnblogs.com/blog/1107037/201905/1107037-20190530221814920-1580281918.png)
1、搭建一个eureka集群
Spring Cloud Eureka的集群配置(六);
2、创建3个生产者的工程:
microservicecloud-provider-dept-8001
microservicecloud-provider-dept-8002
microservicecloud-provider-dept-8003
(1)它们的pom.xml文件配置都一样,配置pom.xml文件
<!-- 引入自己定义的api通用包,可以使用Dept部门Entity --> <dependency> <groupId>com.yufeng.springcloud</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> </dependency> <!-- actuator监控信息完善 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- 将微服务provider侧注册进eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- 修改后立即生效,热部署 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency>
(2)application.yml文件的配置
3个服务提供者分别连接了3个数据库,并且都注册到了eureka集群中;
microservicecloud-provider-dept-8001工程: 端口为8001,数据库连接到 cloudDB01 数据库;
microservicecloud-provider-dept-8002工程: 端口为8002,数据库连接到 cloudDB02 数据库;
microservicecloud-provider-dept-8003工程: 端口为8003,数据库连接到 cloudDB03 数据库;
注意:3个生产者服务的 spring.application.name 配置的必须要一样。
此处3个生产者服务的 eureka.instance.instance-id 配置的不一样,每个服务配置了唯一的instance-id;
server:
port: 8001
mybatis:
config-location: classpath:mybatis/mybatis.cfg.xml # mybatis配置文件所在路径
type-aliases-package: com.yufeng.springcloud.entities # 所有Entity别名类所在包
mapper-locations:
- classpath:mybatis/mapper/**/*.xml # mapper映射文件
spring:
application:
name: microservicecloud-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://192.168.172.20:3306/cloudDB01 # 数据库名称
username: root
password: root
dbcp2:
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化连接数
max-total: 5 # 最大连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间
eureka:
client: # 客户端注册进eureka内
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
instance:
instance-id: microservicecloud-provider-dept-8001
prefer-ip-address: true # 访问路径可以显示IP
info:
app.name: yufeng-microservicecloud
company.name: www.yufeng.com
build.artifactId: $project.artifactId$
build.version: $project.version$
(3)启动类中增加 @EnableEurekaClient 注解
@SpringBootApplication
@EnableEurekaClient //本服务启动后自动注册到eureka中
public class DeptProvider8001_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptProvider8001_App.class, args);
}
}
注意:在这里省略了连接数据库从数据库中查询数据的代码,这个比较基础大家都可以完成;
3、创建1个消费者工程
(1)pom.xml增加如下依赖:
<!-- Ribbon相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId> <!-- Eureka 客户端 -->
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
(2)修改application.yml,增加eureka的服务注册地址
server:
port: 80
# eureka 客户端配置
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
(3)对 ConfigBean 进行注解 @LoadBalanced, 获得Rest时加入Ribbon的配置
@Configuration
public class ConfigBean
{
@Bean
@LoadBalanced //Ribbon 是客户端负载均衡的工具;
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
}
(4)启动类添加 @EnableEurekaClient
@SpringBootApplication
@EnableEurekaClient
public class DeptConsumer80_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer80_App.class, args);
}
}
(5)修改客户端访问类
不用关心服务提供方的端口,只需要使用服务提供方的服务名调用;
@RestController
public class DeptController_Consumer
{
//private static final String RETURN_URL_PREFIX = "http://localhost:8001";
private static final String RETURN_URL_PREFIX = "http://microservicecloud-dept"; //服务提供方的spring.application.name的配置
@Autowired
private RestTemplate restTemplate;
@RequestMapping(value = "/consumer/dept/get/list", method = RequestMethod.GET)
public List<Dept> list()
{
return restTemplate.getForObject(RETURN_URL_PREFIX + "/dept/get/list", List.class);
}
}
三、Ribbon负载均衡的测试
(1)启动eureka集群的3个工程;
(2)启动3个生产者的工程;
随便打开一个eureka地址,看到注册了3个生产者服务,它们的Application都是一样的:
(3)启动消费者工程,因为消费者工程配置的eureka.client.register-with-eureka为false,所以它不会注册到eureka中;
接着,使用浏览器访问 http://localhost/consumer/dept/get/list 3次,分别看到如下信息:
(注意:数据库cloudDB01、cloudDB02、cloudDB02的 dept 表中的db_source字段为数据库名)
第1次:
第2次:
第3次:
从以上结果可以看到,实现了客户端的负载均衡;消费者在轮询的调用3个生产者服务;
结论:Ribbon和Eureka整合之后,消费者可以直接调用生产者的服务名而不用关心生产者的地址和端口号;