4、负载均衡:Ribbon、Feign
Ribbon:负载均衡(基于客户端)
1、负载均衡以及Ribbon
Ribbon是什么?
- Spring Cloud Ribbon 是基于Netflix Ribbon 实现的一套客户端负载均衡的工具。
- 简单的说,Ribbon 是 Netflix 发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将 Netflix 的中间层服务连接在一起。Ribbon 的客户端组件提供一系列完整的配置项,如:连接超时、重试等。简单的说,就是在配置文件中列出 LoadBalancer (简称LB:负载均衡) 后面所有的及其,Ribbon 会自动的帮助你基于某种规则 (如简单轮询,随机连接等等) 去连接这些机器。我们也容易使用 Ribbon 实现自定义的负载均衡算法!
Ribbon能干嘛?
- LB,即负载均衡 (LoadBalancer) ,在微服务或分布式集群中经常用的一种应用。
- 负载均衡简单的说就是将用户的请求平摊的分配到多个服务上,从而达到系统的HA (高用)。
- 常见的负载均衡软件有 Nginx、Lvs 等等。
- Dubbo、SpringCloud 中均给我们提供了负载均衡,SpringCloud 的负载均衡算法可以自定义。
- 负载均衡简单分类:
- 集中式LB
- 即在服务的提供方和消费方之间使用独立的LB设施,如Nginx(反向代理服务器),由该设施负责把访问请求通过某种策略转发至服务的提供方!
- 进程式 LB
- 将LB逻辑集成到消费方,消费方从服务注册中心获知有哪些地址可用,然后自己再从这些地址中选出一个合适的服务器。
- Ribbon 就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址!
- 集中式LB
2、集成Ribbon
1、springcloud-provider-dept-80(客户端)向pom.xml中添加Ribbon和Eureka依赖:
<!--Ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency>
2、在yaml中添加eureka配置
server:
port: 80
# Eureka配置
eureka:
client:
register-with-eureka: false # 不向 Eureka注册自己
service-url: # 从三个注册中心中随机取一个去访问
defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/
3、修改自定义Spring配置类:MyConfig.java 配置负载均衡实现RestTemplate
@Configuration public class MyConfig { @Bean @LoadBalanced //配置负载均衡实现RestTemplate // 通过rest模板去访问服务创建者的方法 public RestTemplate restTemplate() { return new RestTemplate(); } }
4、修改controller
//Ribbon:我们这里的地址,应该是一个变量,通过服务名来访问 //private static final String REST_URL_PREFIX = "http://localhost:8001"; private static final String REST_URL_PREFIX = "http://SPRINGCLOUD-PROVIDER-DEPT";
SPRINGCLOUD-PROVIDER-DEPT-8001:是服务发现8001端口中的项目配置中的:
5、主启动类加上@EnableEurekaClient注解,开启Eureka
// 开启eureka客户端 @EnableEurekaClient @SpringBootApplication public class ConsumerRun_80 { public static void main(String[] args) { SpringApplication.run(ConsumerRun_80.class, args); } }
6、测试
开启7001、7002服务注册。
开启服务提供8001端口。
开启80(客户端)
(查询所有部门:配置80端口所以不需要写端口号):localhost/consumer/dept/query/all
Ribbon实现负载均衡(数据查询时候的轮询操作)
1、流程图
2、搭建数据库
新建两个数据库db02、db03进行环境搭建
dept表的信息都是一样的:
DROP TABLE IF EXISTS `dept`; CREATE TABLE `dept` ( `dno` bigint(20) NOT NULL AUTO_INCREMENT, `dname` varchar(60) DEFAULT NULL, `db_source` varchar(60) DEFAULT NULL, PRIMARY KEY (`dno`) ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; -- ---------------------------- -- Records of dept -- ---------------------------- INSERT INTO `dept` VALUES ('1', '开发部', DATABASE()); INSERT INTO `dept` VALUES ('2', '人事部', DATABASE()); INSERT INTO `dept` VALUES ('3', '市场部', DATABASE()); INSERT INTO `dept` VALUES ('4', '财务部', DATABASE());
3、新建服务提供者
既然我们想查询数据库中的数据,然后通过轮询(负载均衡算法)来实现,就创建服务提供者:
springcloud-provider-dept-8002、springcloud-provider-dept-8003。对应db02,db03数据库
跟springcloud-provider-dept-8001代码一样,只需:
1.修改端口
server:
port: 8001
2.修改Eureka上的默认描述信息
instance-id: springcloud-provider-dept-8001
3.修改spring连接的数据库
url: jdbc:mysql://localhost:3306/db01
4、测试(根据自己电脑量力而行)
开启服务注册中心(我这里就开一个测试):springcloud-eureka-server-7001
开启服务提供:springcloud-provider-dept-8001、8002、8003
开启客户端:springcloud-provider-dept-80
获取到服务列表
地址栏访问:localhost:/consumer/dept/query/all
通过负载均衡算法来决定访问哪个数据库
Feign:负载均衡(基于服务端)
Feign简介
Feign是声明式Web Service客户端,它让微服务之间的调用变得更简单,类似controller调用service。SpringCloud集成了Ribbon和Eureka,可以使用Feigin提供负载均衡的http客户端
只需要创建一个接口,然后添加注解即可~
Feign,主要是社区版,大家都习惯面向接口编程。这个是很多开发人员的规范。调用微服务访问两种方法
- 微服务名字 【ribbon】
- 接口和注解 【feign】
Feign能干什么?
- Feign旨在使编写Java Http客户端变得更容易
- 前面在使用Ribbon + RestTemplate时,利用RestTemplate对Http请求的封装处理,形成了一套模板化的调用方法。但是在实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多处调用,所以通常都会针对每个微服务自行封装一个客户端类来包装这些依赖服务的调用。所以,Feign在此基础上做了进一步的封装,由他来帮助我们定义和实现依赖服务接口的定义,在Feign的实现下,我们只需要创建一个接口并使用注解的方式来配置它 (类似以前Dao接口上标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解),即可完成对服务提供方的接口绑定,简化了使用Spring Cloud Ribbon 时,自动封装服务调用客户端的开发量。
Feign默认集成了Ribbon
- 利用Ribbon维护了MicroServiceCloud-Dept的服务列表信息,并且通过轮询实现了客户端的负载均衡,而与Ribbon不同的是,通过Feign只需要定义服务绑定接口且以声明式的方法,优雅而简单的实现了服务调用。
Feign的使用:
1、创建模块:springcloud-provider-dept-80-feign
实际就是将springcloud-provider-dept-80模块的完整代码复制过来一份然后修改:
添加pom依赖:
<!--Feign的依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.6.RELEASE</version> </dependency>
<dependencies> <!--实体类--> <dependency> <groupId>com.zhixi</groupId> <artifactId>springcloud-01-api</artifactId> <version>1.0-SNAPSHOT</version> </dependency> <!--web--> <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> <!--Ribbon--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-ribbon</artifactId> <version>1.4.6.RELEASE</version> </dependency> <!--Eureka: Ribbon需要从Eureka服务中心获取要拿什么--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> <version>1.4.6.RELEASE</version> </dependency> </dependencies>
修改controller:
@RestController public class DeptConsumerController { // 消费者不应该有service层,这里我们直接调用 // 提供多种便捷访问http服务的方法 @Autowired private DeptClientService service; // 根据id查询 // 通过这个请求,实际请求的是8081服务注册中的请求 @RequestMapping("/consumer/dept/query/{id}") public Dept getDeptById(@PathVariable("id") Long id) { return service.queryDeptById(id); } // 查询所有部门 @RequestMapping("/consumer/dept/query/all") public List<Dept> getDeptAll() { return service.queryAllDept(); } // 添加部门 // 因为在服务创建者的形参中添加了@RequestBody注解,所以在这李添加用户时能够被成功添加的 @RequestMapping("/consumer/dept/add") public boolean addDept(Dept dept) { return service.addDept(dept); } }
修改启动类:添加@EnableFeignClients
// 开启eureka客户端 @EnableEurekaClient @SpringBootApplication
// feign客户端注解,并指定要扫描的包以及配置接口DeptClientService @EnableFeignClients(basePackages = {"com.zhixi.service"}) public class ConsumerRun_Feign_80 { public static void main(String[] args) { SpringApplication.run(ConsumerRun_Feign_80.class, args); } }
2、修改实体类springcloud-01-api模块
添加 pom依赖:
<!--Feign依赖--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> <version>1.4.6.RELEASE</version> </dependency>
添加service层接口:DeptClientService
// @FeignClient:微服务客户端注解,value:指定微服务的名字,这样就可以使Feign客户端直接找到对应的微服务 @FeignClient(value = "SPRINGCLOUD-PROVIDER-DEPT") public interface DeptClientService { // 添加用户 @GetMapping("/dept/add") boolean addDept(Dept dept); // 根据id查询用户 @GetMapping("/dept/query/{id}") Dept queryDeptById(Long id); // 查询全部用户 @GetMapping("/dept/query/all") List<Dept> queryAllDept(); }
3、测试
开启注册中心:springcloud-eureka-server-7001、
开启服务创建:springcloud-provider-dept-8001、8002
开启Feign客户端:springcloud-provider-dept-80-feign
访问:http://localhost/consumer/dept/query/all
Feign和Ribbon如何选择?
根据个人习惯而定,如果喜欢REST风格使用Ribbon;如果喜欢社区版的面向接口风格使用Feign.
Feign 本质上也是实现了 Ribbon,只不过后者是在调用方式上,为了满足一些开发者习惯的接口调用习惯!