SpringCloud-负载均衡(Ribbon)_服务调用_负载均衡(OpenFeign)
Ribbon
what
https://github.com/netflix/ribbon
SpringCloud Ribbon 是基于Netflix Ribbon实现的一套 客户端 负载均衡的工具;
主要功能
提供 客户端软件 负载均衡算法、服务调用;
Ribbon客户端组件 提供一系列的配置项(连接超时、重试等);
{简单来讲,就是在配置文件中列出负载均衡的所有机器,Ribbon会基于某种规则(简单轮询、随机连接等)去连接配置的机器}
Ribbon处于维护状态,替代方案

Ribbon负载均衡LoadBalance
what
将用户的请求 平均分配到 多个服务上,从而达到系统的高可用;
常见的负载均衡软件:Nginx、LVS、硬件F5等;
Ribbon负载均衡与Nginx负载均衡的差异
Nginx是服务器负载均衡,客户端所有的请求都会交给Nginx,由Nginx负责请求转发(服务端实现);
Ribbon是本地负载均衡,在调用服务时,在注册中心获取注册的服务列表缓存到本地,从而在本地实现RPC调用(客户端实现);
集中式LB
在 服务的提供方与消费方之间 使用独立的LB设施(可以是软件Nginx、LVS、硬件F5等),由设施 将请求根据某种规则转发至服务提供方;
进程内LB
将LB逻辑 集成到服务消费方,消费方从注册中心获取可用的服务,然后根据某种规则选择一个服务提供方进行调用;
Ribbon架构说明

Ribbon pom
org.springframework.cloud#spring-cloud-dependencies Hoxton.SR1版本的 org.springframework.cloud#spring-cloud-netflix-dependencies的 org.springframework.cloud#spring-cloud-starter-netflix-eureka-client 已经集成了org.springframework.cloud#spring-cloud-starter-netflix-ribbon
Ribbon核心组件IRule
what
根据特定算法 从服务列表中 选择一个要访问的服务;
com.netflix.loadbalancer.IRule
// Interface that defines a "Rule" for a LoadBalancer. 负载均衡的规则
// A Rule can be thought of as a Strategy for loadbalacing.
// Well known loadbalancing strategies include Round Robin, Response Time based etc.
public interface IRule{
/*
* choose one alive server from lb.allServers or
* lb.upServers according to key
*
* @return choosen Server object. NULL is returned if none
* server is available
*/
public Server choose(Object key);
public void setLoadBalancer(ILoadBalancer lb);
public ILoadBalancer getLoadBalancer();
}
Ribbon预定义实现IRule
com.netflix.loadbalancer.RoundRobinRule
轮询
com.netflix.loadbalancer.RandomRule
随机
com.netflix.loadbalancer.RetryRule
先按照 轮询策略 获取服务,如果获取服务失败,则在指定时间内进行重试;
com.netflix.loadbalancer.WeightedResponseTimeRule
对 轮询策略 的扩展,响应越快的服务获得的权重越大,越容易被选择;
com.netflix.loadbalancer.BestAvailableRule
先过滤掉由于多次访问故障 而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务;
com.netflix.loadbalancer.AvailabilityFilteringRule
先过滤故障服务,再选择并发量较小的服务;
com.netflix.loadbalancer.ZoneAvoidanceRule
默认规则,复合判断 server所在区域的性能、server的可用性 来选择服务;
Ribbon自定义IRule
前言
自定义IRule不能被@ComponentScan扫描;
How
1、自定义IRule
@Configuration
public class MyIRule {
@Bean
public IRule iRule(){
return new RandomRule();
}
}
2、启动类增加@RibbonClient指向自定义IRule
@EnableEurekaClient
@SpringBootApplication
@RibbonClient(name = "payment-service", configuration = MyIRule.class)
public class OrderStarter80 {
public static void main(String[] args) {
SpringApplication.run(OrderStarter80.class, args);
}
}
Ribbon负载均衡算法
轮询算法原理
rest接口第几次请求 % 服务总数 = 实际调用服务的下标;

轮询源码
public class RoundRobinRule extends AbstractLoadBalancerRule {
private AtomicInteger nextServerCyclicCounter;
public RoundRobinRule() {
nextServerCyclicCounter = new AtomicInteger(0);
}
public Server choose(ILoadBalancer lb, Object key) {
if (lb == null) {
log.warn("no load balancer");
return null;
}
Server server = null;
int count = 0;
while (server == null && count++ < 10) {
List<Server> reachableServers = lb.getReachableServers();
List<Server> allServers = lb.getAllServers();
int upCount = reachableServers.size();
int serverCount = allServers.size();
if ((upCount == 0) || (serverCount == 0)) {
log.warn("No up servers available from load balancer: " + lb);
return null;
}
int nextServerIndex = incrementAndGetModulo(serverCount);
server = allServers.get(nextServerIndex);
if (server == null) {
/* Transient. */
Thread.yield();
continue;
}
if (server.isAlive() && (server.isReadyToServe())) {
return (server);
}
// Next.
server = null;
}
if (count >= 10) {
log.warn("No available alive servers after 10 tries from load balancer: "
+ lb);
}
return server;
}
/**
* Inspired by the implementation of {@link AtomicInteger#incrementAndGet()}.
*
* @param modulo The modulo to bound the value of the counter.
* @return The next value.
*/
private int incrementAndGetModulo(int modulo) {
for (;;) {
int current = nextServerCyclicCounter.get();
int next = (current + 1) % modulo;
if (nextServerCyclicCounter.compareAndSet(current, next))
return next;
}
}
}
OpenFeign
https://docs.spring.io/spring-cloud-openfeign/docs/3.1.3/reference/html/
https://github.com/spring-cloud/spring-cloud-openfeign
what
Feign is a declarative web service client.It makes writing web service clients easier.
声明式的web服务client,OpenFeign使得写web服务更容易;
To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations.
使用OpenFeign需要定义一个接口,然后添加注解;Feign注解支持Feign注解和JAX-RS注解;
Feign also supports pluggable encoders and decoders.
Feign支持可插拔的 编码器、解码器;
Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used by default in Spring Web.
SpringCloud 提供了SpringMVC注解支持,默认使用HttpMessageConverters;
Spring Cloud integrates Eureka, Spring Cloud CircuitBreaker, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign.
SpringCloud集成Eureka、CircuitBreaker、LoadBalancer 提供负载均衡;
已经有Ribbon,whyFeign?
Feign旨在让编写http client更简单;
使用Ribbon时,需要Ribbon+RestTemplate,利用RestTemplate对http请求做处理;
但实际开发中,由于对服务依赖的调用可能不止一处,往往一个接口会被多个地方调用,通常会自定义一些client包装这些依赖服务的调用;
所以,Feign在Ribbon基础上做了封装,有Feign来定义和实现依赖服务接口;
在Feign的实现下,只需要创建一个接口 然后注解接口,即可完成对服务提供方的接口绑定,简化了使用Ribbon时,自定义client的开发;
Feign与OpenFeign区别

工程
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2、开启Feign支持
@EnableFeignClients // 开启Feign支持
@SpringBootApplication
public class OpenFeignOrderStarter80 {
public static void main(String[] args) {
SpringApplication.run(OpenFeignOrderStarter80.class, args);
}
}
3、新增FeignClient
@Component
@FeignClient(value = "eureka-payment-service")
public interface PaymentService {
@GetMapping(value = "/get/{id}")
CommonResult<Payment> getById(@PathVariable("id") Integer id);
}
4、test
@RestController
public class OrderController {
@Autowired
private PaymentService paymentService;
@GetMapping(value = "/order/getById/{id}")
public CommonResult<Payment> getById(@PathVariable("id") Integer id){
return paymentService.getById(id);
}
}
OpenFeign超时
what
OpenFeign默认超时1s,如果服务提供方 超过1s,需要设置超时时间;
OpenFeign的超时实际由Ribbon实现(OpenFeign集成了Ribbon);
How
#设置Feign客户端超时 ribbon: ReadTimeout: 5000 #建立连接所用的时间 ConnectTimeout: 5000 #建立连接后,响应结束所用的时间
OpenFeign日志打印
what
OpenFeign提供了日志打印功能,可以通过调整日志级别 了解Feign的HTTP请求的细节;
日志级别
NONE:
默认的,不显示日志;
BASIC:
记录 请求方式、URL、响应状态码、执行时间;
HEADERS:
在BASIC的基础上,增加 请求头、响应头;
FULL:
在HEADERS的基础上,增加了 请求和响应的正文、元数据;
How
@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
#feign日志
logging:
level: #feign日志以什么级别、作用在哪些接口
com.an.service.PaymentService: debug
浙公网安备 33010602011771号