SpringCloud_04 负载均衡及Ribbon、Feign
Ribbon是什么
- SpringCloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡工具。
- Ribbon是Netflix发布的开源项目,主要功能是提供客户端的负载均衡算法,将Netflix的中间层服务连接在一起。 Ribbon的客户端组件提供一系列网站的配置项如:连接超时、重试等。简单的说就是在配置文件中列出LoadBalancer(简称LB:负载均衡)后面所有的基期,Ribbon会自动的帮助你基于某种规则(如简单轮询、随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法!
Ribbon能干嘛
- LB,即负载均衡(Load Balancer),在微服务或分布式集群中经常用到的一种应用。
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA(高可用)。
- 常见的负载均衡软件有:Nginx、Lvs等。
- Dubbo、SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
- 负载均衡简单分类:
- 集中式LB:即在服务的消费方和提供方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方!
- 进程式LB:将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。Ribbon就属于进程内LB,它只是一个类库,继承与消费方进程,消费方通过它来获取到服务提供方的地址!
使用Ribbon实现负载均衡
- 拷贝数据库
- 新建数据库springcloud2,springcloud3。
- 插入数据。
- 在消费端spring-cloud-consumer-dept-80导入Eureka相关依赖(Eureka自带了ribbon,自己导入ribbon会报错)。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 在application.yml配置Eureka
#eureka
eureka:
client:
fetch-registry: true #如果为false表示自己为注册中心
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
register-with-eureka: false #不向Eureka注册自己
- 在配置类配置负载均衡实现RestTemplate。
package com.jiu.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 BeanConfig {
//配置负载均衡实现RestTemplate@LoadBalanced
@Bean
@LoadBalanced //ribbon
public RestTemplate getRestTemplate(){
return new RestTemplate();
}
}
- 在主启动类开启Eureka。
package com.jiu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @CLassName : SpringCloudConsumerDep80
* @Description : TODO Ribbon和Eureka整合以后,客户端可以直接调用,不用关系IP地址和端口号。
* @Author : 九九
* @Date : 2021/7/26,20:26
**/
@SpringBootApplication
@EnableEurekaClient
public class SpringCloudConsumerDep80 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConsumerDep80.class, args);
}
}
- Controller的变化。
- 之前是通过http://localhost:8001访问的。
- 现在使用Ribbon,那么地址应该是一个变量,通过服务名来访问。
package com.jiu.controller;
import com.jiu.pojo.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
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
@RequestMapping("/dept")
public class DeptConsumerController {
private RestTemplate template;
// Ribbon,这里的地址应该是一个变量,通过服务名来访问。
// private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://SPRING-CLOUD-PROVIDER-DEPT";
@Autowired
public void setTemplate(RestTemplate template) {
this.template = template;
}
@GetMapping("/queryAllDept")
public List queryAllDept(){
return template.getForObject(REST_URL_PREFIX+"/dept/queryAllDept", List.class);
}
}
- 测试
- 先启动注册中心spring-cloud-eureka-7001(由于启动过多进程会占用太多内存,所以测试仅启动一个注册中心即可)。
- 分别启动服务提供者spring-cloud-provider-dept-8001、spring-cloud-provider-dept-8002和spring-cloud-provider-dept-8003。
- 可以看到三个服务已经注册进去了:
- 接着启动服务消费者spring-cloud-comsumer-dept-80。
- 使用浏览器访问http://localhost/dept/queryAllDept,结果如下,查询的是数据库springcloud2:
- 再次访问,结果查询的是数据库springcloud3:
- 再次访问,结果是springcloud1:
- 说明Ribbon的默认负载均衡算法是轮询算法。
更改默认负载均衡算法
-
Ribbon默认实现了多种负载均衡算法。
-
AvailabilityFilteringRule : 会过先过滤掉跳闸的服务,对剩下的进行轮询。
-
RoundRobinRule : 轮询。
-
RandomRule : 随机。
-
RetryRule : 按照轮询获取服务~,如果获取失败,会在指定时间内进行重试。
-
更改默认的负载均衡算法只需将组件注册到容器中即可。
@Bean
public IRule myRule(){
return new RandomRule();
}
Feign简介
-
Feign是声明式的web service客户端,它让微服务之间的调用变得更简单了,类似controller调用service。
-
SpringCloud集成了Ribbon和Eureka,可以在使用Feign时提供负载均衡的http客户端。
-
只需要创建一个接口,然后添加注解即可!
-
Feign,主要是社区,大家都习惯面向接口编程,这个是很多开发人员的规范。调用微服务的两种方法:微服务名字(Ribbon)和接口和注解(Feign)。
-
Feign能干什么?
- Feign旨在使编写Java Http客户端变得更容易。
- 前面在使用Ribbon+RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发过程中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一些客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步封装,由他来帮助我们定义和实现依赖服务接口。在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它(类似于Dao接口加上Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用SpringCloud Ribbon时,自动封装服务调用客户端的开发量。
Feign实现
- 创建一个新的模块spring-cloud-comsumer-dept-feign-80,导入相关的依赖。
<dependencies>
<dependency>
<groupId>com.jiu</groupId>
<artifactId>spring-cloud-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- eureka-->
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
</dependencies>
- 编写application.yml文件
server:
port: 80
#eureka
eureka:
client:
fetch-registry: true #如果为false表示自己为注册中心
service-url:
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
register-with-eureka: false #不向Eureka注册自己
- 编写主启动类。
- 在spring-cloud-api模块添加feign依赖。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
- 修改spring-cloud-api模块,添加service层。
- 编写DeptService接口。
package com.jiu.service;
import com.jiu.pojo.Dept;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
@FeignClient(value = "SPRING-CLOUD-PROVIDER-DEPT")
public interface DeptService {
@GetMapping("/dept/queryAllDept")
public List<Dept> queryAllDept();
}
- 在spring-cloud-comsumer-dept-feign-80模块下编写DeptController
package com.jiu.controller;
import com.jiu.service.DeptService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
@RequestMapping("/dept")
public class DeptConsumerController {
private DeptService deptService;
@Autowired
public void setDeptService(DeptService deptService) {
this.deptService = deptService;
}
@GetMapping("/queryAllDept")
public List queryAllDept(){
return deptService.queryAllDept();
}
}
- 在主启动类开启Feign。
package com.jiu;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages = {"com.jiu"}) //开启Feign,并配置扫描的包。
public class SpringCloudConsumerDepFeign80 {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConsumerDepFeign80.class, args);
}
}
- 测试,启动spring-cloud-eureka-7001、spring-cloud-provider-dept-8001、spring-cloud-provider-dept-8002、spring-cloud-provider-dept-8001、spring-cloud-comsumer-dept-feign-80,使用浏览器访问localhost/dept/queryAllDept。
- 结果如下: