目录
一 Ribbon
历史
Spring Cloud Ribbon是基于Netflix Ribbon
实现的一套客户端负载均衡
的工具。
简单的说,Ribbon是Netflix发布的开源项目,主要功能是提供客户端的软件负载均衡算法,将Netflix的中间层服务连接在一起。Ribbon客户端组件提供一系列完善的配置
项如连接超时,重试等。简单的说,就是在配置文件中列出Load Balancer(简称LB)后面所有的机器
,Ribbon会自动的帮助你基于某种规则(如简单轮询,随机连接等)去连接这些机器。我们也很容易使用Ribbon实现自定义的负载均衡算法
。
作用
LB,即负载均衡(Load Balance),在微服务或分布式集群中经常
用的一种应用。
负载均衡简单的说就是将用户的请求平摊的分配到多个服务上
,从而达到系统的HA。
常见的负载均衡有软件Nginx,LVS,硬件 F5等。
相应的在中间件,例如:dubbo和SpringCloud中均给我们提供了负载均衡,SpringCloud的负载均衡算法可以自定义。
集中式LB
即在服务的消费方和提供方之间
使用独立的LB设施
(可以是硬件,如F5, 也可以是软件,如nginx), 由该设施负责
把访问请求通过某种策略转发至服务的提供方;
进程内LB
将LB逻辑集成到消费方
,消费方从服务注册中心获知有哪些地址可用
,然后自己再从这些地址中选择
出一个合适的服务器。
Ribbon就属于进程内LB,它只是一个类库,集成于消费方进程,消费方通过它来获取到服务提供方的地址。
资料
https://github.com/Netflix/ribbon/wiki/Getting-Started
二 Ribbon配置初步
修改microservicecloud-consumer-dept-80工程(消费者)
pom修改
新增依赖
<!-- Ribbon相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</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>
修改yml
修改application.yml 追加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/
增加注解@LoadBalanced
对ConfigBean进行新注解@LoadBalanced 获得RestTemplate 时加入Ribbon的配置
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
启动类增加@EnableEurekaClient
修改controller
修改DeptController_Consumer客户端访问类,地址不写ip:端口
,而是应用名
//private static final String REST_URL_PREFIX = "http://localhost:8001";
private static final String REST_URL_PREFIX = "http://MICROSERVICECLOUD-DEPT";
启动顺序与测试
小结
Ribbon和Eureka整合后Consumer可以直接调用服务
而不用再关心地址和端口号
三 实现负载均衡
首先再创建两个服务提供者
结构说明
Ribbon在工作时分成两步
- 第一步先
选择 EurekaServer
,它优先选择在同一个区域内负载较少的server.
- 第二步再根据
用户指定的策略
,在从server取到的服务注册列表中选择一个地址
。(其中Ribbon提供了多种策略:比如轮询、随机和根据响应时间加权。)
再创建两个类似服务
- 参考microservicecloud-provider-dept-8001,新建两份,分别命名为8002,8003
- 再创建
两个
数据库.下面提供一个数据库的脚本,另一个改下脚本
即可
DROP DATABASE IF EXISTS cloudDB02;
CREATE DATABASE cloudDB02 CHARACTER SET UTF8;
USE cloudDB02;
CREATE TABLE dept
(
deptno BIGINT NOT NULL PRIMARY KEY AUTO_INCREMENT,
dname VARCHAR(60),
db_source VARCHAR(60)
);
INSERT INTO dept(dname,db_source) VALUES('开发部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('人事部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('财务部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('市场部',DATABASE());
INSERT INTO dept(dname,db_source) VALUES('运维部',DATABASE());
SELECT * FROM dept;
- 修改yml。
- 端口修改
- 数据库链接修改
- 对外暴露的统一的服务
实例名不要改
- 修改
eureka.instance.instance-id
测试
先启动,启动步骤
- 先启动eureka集群
- 启动3个Dept微服务,
然后自测
(即访问端口:http://localhost:8001/dept/list、http://localhost:8001/dept/list、http://localhost:8003/dept/list) - 启动microservicecloud-consumer-dept-80(消费者服务)
- 多次访问
http://localhost/consumer/dept/list
,会发现db_sourc
不同。
- 多次访问
小结
Ribbon其实就是一个软负载均衡的客户端
组件,
他可以和其他所需请求的客户端结合使用,和eureka结合只是其中的一个实例
四 IRule
策略介绍
IRule:根据特定算法中从服务列表中选取
一个要访问的服务
- RoundRobinRule(轮询)
- RandomRule(随机)
- AvailabilityFilteringRule(会先
过滤
掉由于多次访问故障而处于断路器跳闸状态的服务,
还有并发的连接数量超过阈值的服务,然后对剩余的服务列表按照轮询策略
进行访问) - WeightedResponseTimeRule(根据
平均响应时间
计算所有服务的权重,响应时间越快服务权重越大被选中的概率越高。
刚启动
时如果统计信息不足,则使用RoundRobinRule
策略,等统计信息足够
,
会切换到WeightedResponseTimeRule) - RetryRule(先按照RoundRobinRule的策略获取服务,如果获取服务失败则在
指定时间内会进行重试
,获取可用的服务) - BestAvailableRule(会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务)
- ZoneAvoidanceRule(默认规则,复合判断server所在区域的性能和server的可用性选择服务器)
如何切换策略
注入需要的IRule的bean
@Configuration
public class ConfigBean
{
@Bean
@LoadBalanced
public RestTemplate getRestTemplate()
{
return new RestTemplate();
}
@Bean
public IRule myRule(){
return new RoundRobinRule();
}
}
自定义策略
如果已有策略无法满足需求,还可以自定义策略
但本文就不再记录
了,可以查阅网上的其他资料作为参考
五 Feign组件
下面说一下简单的
整合知识,作为了解。如果想要深入使用,建议查看其他更专业的资料。
官网解释:http://projects.spring.io/spring-cloud/spring-cloud.html#spring-cloud-feign
Feign是一个声明式
WebService客户端。使用Feign能让编写Web Service客户端更加简单, 它的使用方法是定义一个接口
,然后在上面添加注解
,同时也支持JAX-RS标准的注解。Feign也支持可拔插式的编码器和解码器。Spring Cloud对Feign进行了封装
,使其支持了Spring MVC标准注解
和HttpMessageConverters。Feign可以与Eureka和Ribbon组合使用以支持负载均衡
。
场景
前面我们微服务之间都信都是在消费者端配置一个RestTemplate
,通过显示调用rest接口来完成的。
Feign通过接口的方法调用Rest服务
(之前是Ribbon+RestTemplate),
该请求发送给Eureka服务器
(http://MICROSERVICECLOUD-DEPT/dept/list),
通过Feign直接找到服务接口
,由于在进行服务调用的时候融合了Ribbon技术,所以也支持负载均衡作用。
创建一个使用Feign的客户端
- 参考microservicecloud-consumer-dept-80,新建一个microservicecloud-consumer-dept-feign(复制老项目的代码)
- pom.xml修改,主要添加对feign的支持
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
再修改microservicecloud-api工程
3. 也是添加上面的feign依赖
4. 新建DeptClientService接口并新增注解@FeignClient
mvn clean install
继续修改microservicecloud-consumer-dept-feign模块
6. 调整Controller,添加上一步新建的DeptClientService接口
package com.zyc.springcloud.controller;
import com.zyc.springcloud.entitys.Dept;
import com.zyc.springcloud.service.DeptClientService;
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 java.util.List;
@RestController
class DeptController_Feign
{
@Autowired
private DeptClientService service = null;
@RequestMapping(value = "/consumer/dept/get/{id}")
public Dept get(@PathVariable("id") Long id)
{
return this.service.get(id);
}
@RequestMapping(value = "/consumer/dept/list")
public List<Dept> list()
{
return this.service.list();
}
@RequestMapping(value = "/consumer/dept/add")
public Object add(Dept dept)
{
return this.service.add(dept);
}
}
- 启动类调整
package com.zyc.springcloud;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients(basePackages= {"com.zyc.springcloud"})
public class DeptConsumer80_Feign_App
{
public static void main(String[] args)
{
SpringApplication.run(DeptConsumer80_Feign_App.class, args);
}
}