什么是Ribbon?
Spring Cloud Ribbon是一个基于Netflix Ribbon实现的一套客户端负载均衡工具
负载均衡区分了两个类型,Spring Cloud Ribbon实现了客户端的负载均衡
- 服务实例的清单在客户端,客户端进行负载均衡算法分配。
- 客户端可以从Eureka Server中得到一份服务清单,在发送请求时通过负载均衡算法,在多个服务器之间选择一个进行访问
服务准备之前的项目中只有
springcloud-provider-dept-8001
一个服务提供者,为了展示负载均衡的效果,现在再新建一个提供相同服务的服务提供者
springcloud-provider-dept-8002
数据库准备
DB01数据库
create database db01 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
create table dept
(
deptno bigint auto_increment primary key,
dname varchar(50) null,
db_source varchar(50) null
)
INSERT INTO dept (dept.dname,dept.db_source) VALUES
('五部',DATABASE()),
('六部',DATABASE()),
('七部',DATABASE())
DB02数据库
create database db02 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
create table dept
(
deptno bigint auto_increment primary key,
dname varchar(50) null,
db_source varchar(50) null
)
INSERT INTO dept (dept.dname,dept.db_source) VALUES
('五部',DATABASE()),
('六部',DATABASE()),
('七部',DATABASE())
springcloud-provider-dept-8001
服务使用DB01数据库springcloud-provider-dept-8002
服务使用DB02数据库- 两个数据库存储的是相同的内容
db_source
字段是标志,DATABASE()
表示数据来源的数据库名称
服务提供者准备
因为springcloud-provider-dept-8001
和springcloud-provider-dept-8002
提供的是相同的服务,所以编写内容基本一致,
springcloud-provider-dept-8001
配置文件
server:
port: 8001
mybatis:
type-aliases-package: com.springcloud.entity
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
application:
name: spring-provider-dept
datasource:
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db01?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=UTF-8
eureka:
client:
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
instance:
instance-id: springcloud-provider-dept8001
springcloud-provider-dept-8002
配置文件
server:
port: 8002
mybatis:
type-aliases-package: com.springcloud.entity
config-location: classpath:mybatis/mybatis-config.xml
mapper-locations: classpath:mybatis/mapper/*.xml
spring:
application:
name: spring-provider-dept
datasource:
username: root
password: root
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/db02?serverTimezone=Asia/Shanghai&useSSL=true&useUnicode=true&characterEncoding=UTF-8
eureka:
client:
service-url:
defaultZone: http://eureka7002.com:7002/eureka/,http://eureka7001.com:7001/eureka/
instance:
instance-id: springcloud-provider-dept8002
- 因为提供的是同一种服务,所以
spring.application.name
相同
运行springcloud-eureka-7001
测试:
可以发现两个服务都已经成功注册进去了
引入Ribbon
springcloud-consumer-dept-80
工程为消费者,即客户端。首先导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
然后编写配置类ConfigBean
package com.springcloud.config;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
@LoadBalanced
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
RestTemplate
是远程调用服务的HTTP 请求工具@Bean
表示将RestTemplate
注入到IOC容器中@LoadBalanced
表示开启负载均衡
修改后的Controller
package com.springcloud.controller;
import com.springcloud.entity.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.List;
@RestController
public class DeptConsumerController {
@Autowired
private RestTemplate restTemplate;
private static final String REST_URL_PREFIX = "http://SPRING-PROVIDER-DEPT";
// private static final String REST_URL_PREFIX = "http://localhost:8001";
@RequestMapping("/consumer/dept/add")
public boolean add(Dept dept){
return restTemplate.postForObject(REST_URL_PREFIX+"/dept/add",dept,Boolean.class);
}
@RequestMapping("consumer/dept/list")
public List<Dept> list(){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/list",List.class);
}
@RequestMapping("consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id){
return restTemplate.getForObject(REST_URL_PREFIX+"/dept/get/"+id,Dept.class);
}
}
之前springcloud-consumer-dept-80
通过提供方的URL直接向提供者请求服务,但事实上客户端应该向Eureka注册中心请求服务,所以请求的地址应该是Eureka中对应服务的位置,配置文件也许修改
server:
port: 80
spring:
application:
name: springcloud-consumer-dept
eureka:
client:
service-url:
defaultZone: http://localhost:7001/eureka/
register-with-eureka: false
register-with-eureka: false
表示不向Eureka中注册自己
http://localhost/consumer/dept/list
测试:
从db_resource
字段的值可以看出服务是springcloud-provider-dept-8001
提供的,直接刷新页面再测试。
而从db_resource
字段的值可以看出服务是springcloud-provider-dept-8002
提供的。
可以看出负载均衡已经实现,不断地测试可以发现默认的负载均衡算法为轮询算法。