这是我参与更文挑战的第 11 天,活动详情查看: 更文挑战
Ribbon
一、概述
- 负载均衡就是将客户的请求平摊到其他服务器上,达到服务高可用。
- 本地负载均衡和服务器负载均衡
- Ribbon是本地负载均衡,调用微服务接口时,先把注册中心的服务缓存到本机JVM上,在本地实现RPC远程调用。
- Nginx是服务器负载均衡,用户的请求都会交给Nginx,再由Nginx实现转发请求,由服务端实现负载均衡。
Ribbon就是负载均衡+ResultTemplate调用
二、负载均衡的规则
默认是轮寻,可以使用自定义配置。
1、Ribbon自带的负载均衡规则(IRule):
- RoundRobinRule: 轮询
- RandomRule: 随机
- RetryRule: 先轮询,如果失败在指定时间重试
- WeightedResponseTimeRule: 响应速度越快权重越大,越容易被选择。
- BestAvailableRule: 过滤掉多次访问故障的服务,然后选择一个并发量最小的服务
- AvailabilityFilteringRule\ZoneAvoidanceRule: 和BestAvailableRule相似
2、负载规则替换
注意:负载规则替换的规则类不能放在@ComponentScan的扫描范围内
规则配置类
@Configuration
public class MySelfRule {
//配置负载规则随机
@Bean
public IRule myRule() {
return new RandomRule();
}
}
复制代码
主启动类加@RibbonClient
@EnableEurekaClient
@SpringBootApplication
//对CLOUD-PAYMENT-SERVICE服务进行负载均衡,使用的规则为MySelfRule
@RibbonClient(name = "CLOUD-PAYMENT-SERVICE", configuration = MySelfRule.class)
public class OrderMain8080 {
public static void main(String[] args) {
SpringApplication.run(OrderMain8080.class, args);
}
}
复制代码
三、负载均衡轮寻算法原理
负载均衡算法:rest接口的请求次数 % 服务器集群数量 = 实际调用服务器位置的下标,每次启动服务rest从1开始。
接口LoadBalancer
public interface LoadBalancer {
ServiceInstance instance(List<ServiceInstance> serviceInstances);
}
复制代码
实现
@Component
public class LoadBalancerImpl implements LoadBalancer {
private AtomicInteger atomicInteger = new AtomicInteger(0);
public ServiceInstance instance(List<ServiceInstance> serviceInstances) {
//获取当前服务的下标
int index = getAndIncrement() % serviceInstances.size();
return serviceInstances.get(index);
}
/**
* 使用CAS自旋锁获取服务访问次数
*
* @return
*/
public final int getAndIncrement() {
int current;
int next;
do {
current = this.atomicInteger.get();
next = current >= Integer.MAX_VALUE ? 0 : current + 1;
} while (!this.atomicInteger.compareAndSet(current, next));
return next;
}
}
复制代码
测试
@RestController
@RequestMapping("/consumer")
public class OrderController {
private final String PAYMENT_URL = "http://CLOUD-PAYMENT-SERVICE";
@Resource
private LoadBalancer loadBalancer;
@Resource
private DiscoveryClient discoveryClient;
@GetMapping("/getPort")
public String getPortLB() {
//根据服务名称查找服务列表
List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
if (instances == null || instances.size() <= 0) {
return null;
}
ServiceInstance serviceInstance = loadBalancer.instance(instances);
URI uri = serviceInstance.getUri();
return restTemplate.getForObject(uri + "/payment/getPort", String.class);
}
}
复制代码
Open Feign
一、概述
Feign是一个声明式的Web服务客户端,让Web Service更加简单,定义一个服务接口然后在上面加上注解,即可完成服务提供方的接口绑定,简化了使用Ribbon时,自动封装服务调用客户端的开发量。
Feign集成了Ribbon,而Feign是以接口绑定的声明式方法调用的。
OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解的下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡和调用其他服务。
二、Open Feign 服务调用
导入依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
复制代码
在启动类上添加注解开启OpenFeign
@SpringBootApplication
@EnableFeignClients
public class OrderFeignMain80 {
public static void main(String[] args) {
SpringApplication.run(OrderFeignMain80.class, args);
}
}
复制代码
创建接口调用服务,标明提供服务的服务名称,并且指定对应的url
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentFeignService {
@GetMapping("/payment/getById/{id}")
ResultDto<Payment> getPaymentById(@PathVariable("id") Long id);
}
复制代码
测试调用
@RestController
public class OrderFeignController {
@Resource
private PaymentFeignService paymentFeignService;
@GetMapping("/consumer/get/payment/{id}")
public ResultDto<Payment> getPaymentById(@PathVariable("id") Long id){
return paymentFeignService.getPaymentById(id);
}
}
复制代码
三、Open Feign 超时控制
演示
//设置服务提供方等待3秒
@GetMapping("/getPort")
public String getPort() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return port;
}
复制代码
Open Feign 客户端默认等待时间为1秒钟,如果超过一秒钟还没有得到提供服务方的响应,就会抛出错误。
为了避免这种情况,需要手动设置超时时间。
配置文件添加
ribbon:
#指建立连接所用时间
ReadTimeout: 5000
#指获取资源所有时间
ConnectTimeout: 5000
复制代码
四、Open Feign 日志增强
Feign提供了日志打印功能,通过配置来调整日志级别,对Feign接口的调用情况进行监控和输出。
日志级别:
- NONE:默认,不显示任何日志;
- BASIC:尽记录请求方法、URL、响应状态及响应时间;
- HEADERS:除了BASIC中记录的内容,还会记录请求和响应头的信息;
- FULL:除了HEADERS中的信息,还会记录请求和响应的正文及元数据
使用配置类配置级别
@SpringBootConfiguration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
复制代码
在配置文件中开启日志
logging:
level:
# feign日志以哪个级别监控哪个接口
cn.yylm.springcloud.service.PaymentFeignService: debug
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END