快速入门全栈 - 13 SpringCloud 负载均衡与熔断器

一、负载均衡

负载均衡是分布式系统架构设计必须考虑的因素之一。负载均衡指的是将请求均匀分摊到多个操作单元上执行,关键在于均匀。均与只是负载均衡的策略之一,可以根据不同的策略来达到最佳的性能。

负载均衡有两种模式,一种是集中式负载均衡,在消费者和服务提供方之间使用独立代理进行负载,例如Nginx;另一种是客户端负载,根据自己的请求情况做负载,Ribbon就是Netflix开源的一款负载均衡的软件。客户端负载由客户端决定来调用哪个服务,而集中式负载均衡由独立的代理端来决定调用哪个服务。

二、SpringCloud Ribbon

1. Ribbon

Ribbon是Netflix的负载均衡项目,为客户端通信提供支持,有以下的特性

  • 负载均衡器,支持插拔式负载均衡规则
  • 支持HTTP、TCP、UCP等协议
  • 继承负载均衡功能的客户端

Ribbon有以下主要模块:

  • ribbon-loadbalancer:负载均衡模块,可独立使用,集成了负载均衡算法
  • ribbon-eureka:基于Eureka封装
  • ribbon-transport:基于Netty实现多协议支持
  • ribbon-httpclient:基于httpclient封装REST客户端,继承了负载均衡模块

在使用的时候,客户端通过负载均衡器,来决定调用哪个集群节点上的服务。

2. RestTemplate

在实际开始使用Ribbon之前,我们再看一下什么是RestTemplate。RestTemplate是Spring提供的访问Rest服务的接口,提供了简单的API来调用Http服务,大大提高客户端编写效率。

Rest是一种软件架构规范,强调HTTP以资源为中心,规范了URI和HTTP请求动作,例如

CRUD请求 普通CRUD restfulCRUD
查询 getStudent student --get
添加 addStudent?xxxx student --post
修改 updateStudent?id=xx student --put
删除 delStudent?id=xx student --delete

RestTemplate本身不具有负载均衡的功能,如果需要,则需要添加@LoadBalanced注解。RestTemplate有如下的方法

HTTP method RestTemplate methods
DELETE delete
GET getForObject
getForEntity
HEAD headForHeaders
OPTIONS optionsForAllow
POST postForLocation
postForObject
PUT put
any exchange
execute

GET请求

// 1.getForObject
User user1 = this.restTemplate.getForObject(uri, User.class);
// 2.getForEntity
ResponseEntity<User> responseEntity1 = this.restTemplate.getForEntity(uri, User.class);
HttpStatus statusCode = responseEntity1.getStatusCode();
HttpHeaders header = responseEntity1.getHeaders();
User user2 = responseEntity1.getBody();
// 3.exchange
RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build();
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
User user3 = responseEntity2.getBody();

POST请求

// 1. postForObject
User user1 = this.restTemplate.postForObject(uri, user, User.class);
// 2. postForEntity
ResponseEntity<User> repsonseEntity1 = this.restTemplate.postForEntity(uri, user, User.class);
// 3.exchange
RequestEntity<User> requestEntity = RequestEntity.post(new URI(uri)).body(user);
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
3. Ribbon + RestTemplate实战

下面我们来在代码中查看客户端如何使用Ribbon和RestTemplate。首先我们新建一个SpringBoot应用并添加依赖

<dependency>
	<groupId>org.springframework.cloudgroupId>
	<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
dependency>

然后我们要写明服务的调用

@Autowired
RestTemplate restTemplate;

String serverUrl = "xxx";

@GetMapping("/consumer")
public String consumer(String word){
	ResponseEntity<String> entity = restTemplate.getForEntity(serverUrl + "/hello?word={1}", 
																String.class, word);
	return "调用服务返回:" + entity.getBody();
}

我们还需要配置RestTemplate

@Bean
@LoadBalanced
RestTemplate restTemplate(){
	return new RestTemplate();
}

三、SpringCloud Feign

Feign是netflix开发的声明式、模块化的HTTP客户端。在SpringCloud中,使用Feign非常的简单,只需要创建一个接口,并且在接口上添加一些注解即可。Spring Cloud对Feign进行了增强,使其支持了Spring MVC的注解,并整合了Ribbon和Eureka。

下面我们在代码中来看如何使用Feign。首先引入依赖

<dependency>
	<groupId>org.springframework.cloudgroupId>
	<artifactId>spring-cloud-starter-feignartifactId>
dependency>

编写接口类

@FeignClient("SERVER-PROVIDE")
public interface HelloFeignService{
	@RequestMapping("/hello")
	public String hello(@RequestParam("word") String word){
		// xxx
	}
}

然后按普通的接口类来调用即可

最后记得要在启动类中添加注解@EnableFeignClients

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@Slf4j
public class ConsumerApplication{
	public static void main(String[] args) throws Exception{
		StringApplication.run(ConsumerApplication.class, args);
		log.info("Consumer服务启动");	
	}
}

四、SpringCloud Hystrix

1. 服务熔断

SpringCloud Hystrix负责熔断处理。在微服务中,由于存在很多个微服务,各个微服务通过网络进行通讯,难免会出现依赖关系,若某一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,造成“雪崩效应”,最终导致整个系统的瘫痪。

为了解决雪崩效应,我们有以下几种解决方法:

  • 请求设置超时时间
  • 使用熔断器模式:防止级联错误,问题服务隔离

熔断器就像是保险丝,如果保险丝断掉了,电路就无法运行了。正常情况下,熔电器是关闭的,可正常请求依赖服务。当一段时间内,请求失败率到达一定阈值,熔断器就会打开,此时,不会再去请求依赖的服务。熔断器打开一段时间之后,会自动进入半开状态,此时,熔断器可允许一个请求访问依赖的服务,如果请求调用成功,则关闭熔断器,否则继续保持打开。

2. SpringCloud Hystrix

Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或第三方库,防止级联失败,从而提升系统的可用性和易错性。Hystrix的容错机制如下:

  • 包裹请求:使用HystrixCommand包裹对以来的调用逻辑,每个命令在独立线程中执行(命令模式)
  • 跳闸机制:当某服务的错误率超过一定阈值的时候,Hystrix可以手动或者自动跳闸,停止请求该服务一段时间
  • 资源隔离:Hystrix为每个以来都维护了一个小型的线程池,如果该线程池已满,发往该以来的请求就立即拒绝,而不是排队等候,从而加速判定失败
  • 监控:Hystrix可以近乎实时的监控运行指标和配置的变化。如成功、失败、超时、被拒绝的请求等
  • 回退机制:当请求失败、超时、被拒绝,或者当断路器打开的时候,执行回退逻辑,可自定义
  • 自我修复:断路器打开一段时间后,会自动进入半开状态,断路器打开、关闭、半开的逻辑转换
3. Hystrix实战

我们在使用Hystrix的时候,首先要定义依赖

<dependency>
	<groupId>org.springframework.cloudgroupId>
	<artifactId>spring-cloud-starter-hystrixartifactId>
dependency>

然后修改控制层,添加@HystrixCommand注解

@GetMapping("/consumer")
@HystrixCommand(fallbackMethod = "consumerFallback")
public String consumer(String word){
	ResponseEntity<String> entity = restTemplate.getForObject(serverUrl + "hello?word={1}",
																		String.class,word);
	return "服务返回值为: " + entity.getBody();
}

public String consumerFallback(String word){
	return "发生熔断";
}

最后要在启动类添加@EnableCircuitBreaker注解

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
@EnableCircuitBreaker
@Slf4j
public ConsumerApplication{
	public static void main(String[] args){
		SpringApplication.run(ConsumerApplication.class, args);
		log.info("服务启动");
	}
}
4. Hystrix Dashboard

Hystrix还有一个监控服务的服务,叫做Dashboard。Dashboard还需要新添加依赖

<dependency>
	<groupId>org.springframework.cloudgroupId>
	<artifactId>spring-cloud-starter-actuatorartifactId>
dependency>

我们在application.yml中定义服务的端口,并在启动类中添加注解@EnableHystrixDashboard。启动服务后,输入URL:http://localhost:端口号/hystrix即可访问Dashboard的主页面,输入要监控的服务URL即可,要记得在URL最后添加.stream后缀。


我和几位大佬建立了一个微信公众号,欢迎关注后查看更多技术干货文章
欢迎加入交流群QQ1107710098

你可能感兴趣的:(快速入门全栈)