一、Ribbon(负载均衡+RestTemplate调用)
总结:Ribbon其实就是一个软负载均衡的客户端组件。运用在消费者模块中
导依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
注:spring-cloud-starter-netflix-eureka-client中包含以上依赖。
1、LB(负载均衡)
- 集中式LB(服务器负载均衡)
- 进程内LB(本地负载均衡)
2、RestTemplate
@Configuration
public class ApplicationContextConfig {
@Bean
@LoadBalanced //开启负载均衡(多个服务在eureka server中服务名相同,通过这个注解开启,当客服端访问的时候可随机访问其中一个服务,默认采用轮询算法(Ribbon))
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
controller中
@RestController
public class OrderController {
// public static final String PAYMENT_URL = "http://localhost:8081";//单机版
public static final String PAYMENT_URL = "http://CLOUD-PROVIDER-PAYMENT";//集群版。需要开启负载均衡,不然不知道对应哪个服务
@Resource
private RestTemplate restTemplate;
//getForObject返回的对象为响应体中数据转化的对象,基本上可以理解为JSON
@GetMapping("/consumer/payment/getById/{id}")
public Result<Payment> getById(@PathVariable("id")Long id) {
return restTemplate.getForObject(PAYMENT_URL + "/payment/getById/" + id, Result.class);
}
//getForEntity返回对象为ResponseEntity对象,包含了响应的一些重要信息,比如响应头,响应状态码,响应体等
@GetMapping("/consumer/payment/getByEntity/{id}")
public Result<Payment> getPayment(@PathVariable("id") Long id) {
ResponseEntity<Result> forEntity = restTemplate.getForEntity(PAYMENT_URL + "/payment/getById", Result.class);
if (forEntity.getStatusCode().is2xxSuccessful()) {
return forEntity.getBody();
}else {
return new Result<>(444,"查询失败");
}
}
}
3、IRule(根据特定算法中从服务列表中选取一个要访问的服务)
- com.netflix.loadbalancer.RoundRobinRule:轮询
- com.netflix.loadbalancer.RandomRule:随机
- com.netflix.loadbalancer.RetryRule:先按照RoundRobinRule的策略获取服务,如果服务获取失败则在指定时间内会进行重试,获取可用的服务。
- WeightedResponseTimeRule:对RoundRobinRule的扩展,响应速度越快的实例选择权重越大,越容易被选择。
- BestAvailableRule:会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。
- AvailabilityFilteringRule:先过滤掉故障实例,再选择并发较小的实例。
- ZoneAvoidanceRule:默认规则,符合判断server所在区域的性能和server的可用性选择服务器。
Ribon默认IRule是轮询算法
- 替换IRule(代码写在客户端消费者方)
自定义规则配置类不能放在@ComponentScan(启动类@SpringBootApplication中包含的注解)扫描的包下面。否则这个配置类就会被所有的Ribbon客户端所共享,达不到特殊化定制效果了。
- 自定义配置类:com.lyl.myrule.MySelfRule.java(不能和启动类在同一包下面)
@Configuration
public class MySelfRule {
@Bean
public IRule myRule() {
return new RandomRule();//采用随机Rule
}
}
- 启动类中添加@RibbonClient(name = "CLOUD-PROVIDER-PAYMENT",configuration = MySelfRule.class)
其中:CLOUD-PROVIDER-PAYMENT为服务提供者集群
4、负载均衡算法
- rest接口第几次请求数 % 服务器集群总数量(提供者模块)= 实际调用服务器位置下标。
- 每次服务重启动后rest接口计数从1开始
二、OpenFeign
openFeign是一个声明式的Web服务客户端,让编写Web服务客户端变得非常容易,只需创建一个接口并在接口上添加注解即可。
1、实现负载均衡的代码(写于消费者方)
-pom.xml中
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
- application.yml配置
server:
port: 80
eureka:
client:
register-with-eureka: false
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka
-启动类:添加@EnableFeignClients
-service/OrderFeignService
@Component
@FeignClient("CLOUD-PROVIDER-PAYMENT") //去eureka中查找服务名称为CLOUD-PROVIDER-PAYMENT的服务,并查找该服务中的/payment/getById/{id}的方法
public interface OrderFeignService {
//与提供者controller中的方法一致
@GetMapping("/payment/getById/{id}")
Result<Payment> getPayment(@PathVariable("id") Long id);
}
- controller/OrderController
@RestController
public class OrderController {
@Resource
private OrderFeignService orderFeignService;
//getForObject返回的对象为响应体中数据转化的对象,基本上可以理解为JSON
@GetMapping("/consumer/payment/getById/{id}")
public Result getById(@PathVariable Long id) {
return orderFeignService.getPayment(id);
}
}
访问:
2、超时控制
默认Feign客户端只等待一秒钟,但是服务端处理需要超过1秒钟,导致Feign客户端不想等待了,直接返回报错。避免出现这种情况,需要设置Feign客户端的超时控制。
- 服务提供方controller
@RestController
@RequestMapping("/payment")
public class PaymentController {
@Value("${server.port}")
private String serverPort;
@GetMapping("/timeout")
public String feignTimeOut() {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return serverPort;
}
}
- 消费者方
- server/OrderFeignService
@Component
@FeignClient("CLOUD-PROVIDER-PAYMENT") //去eureka中服务名称为CLOUD-PROVIDER-PAYMENT的服务,并查找该服务中的/payment/getById/{id}的方法
public interface OrderFeignService {
@GetMapping("/payment/timeout")
String feignTimeOut();
}
- controller/OrderController
@RestController
public class OrderController {
@Resource
private OrderFeignService orderFeignService;
@GetMapping("/consumer/payment/timeout")
public String feignTimeOut() {
return orderFeignService.feignTimeOut();//客户端一般默认等待1秒钟
}
}
访问结果:openfeign默认等待一秒,超时后报错
- 解决办法:设置超时时间
- application.yml
#设置feign客户端超时时间(OpenFeign默认支持ribbon)
ribbon:
ReadTimeout: 5000 #指的是建立连接所用时间,适用于网络状况正常的情况下,两端连接所用的时间
ConnectTimeout: 5000 #指的是建立连接后从服务器读取到可用资源所用的时间
3、日志打印功能
对Feign接口的调用情况进行监控和输出
日志级别:
- NONE:默认的,不显示任何日志
- BASIC:仅记录请求方、URL、响应状态码及执行时间
- HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息
- FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。
- cofig/FeignConfig
@Configuration
public class FeignConfig {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL;
}
}
- application.yml
logging:
level:
//OrderFeignService是带有@FeignClient的接口
com.lyl.springcloud.service.OrderFeignService: debug #feign日志以社么级别监控哪个接口
运行: