负载均衡是分布式系统架构设计必须考虑的因素之一。负载均衡指的是将请求均匀分摊到多个操作单元上执行,关键在于均匀。均与只是负载均衡的策略之一,可以根据不同的策略来达到最佳的性能。
负载均衡有两种模式,一种是集中式负载均衡,在消费者和服务提供方之间使用独立代理进行负载,例如Nginx;另一种是客户端负载,根据自己的请求情况做负载,Ribbon就是Netflix开源的一款负载均衡的软件。客户端负载由客户端决定来调用哪个服务,而集中式负载均衡由独立的代理端来决定调用哪个服务。
Ribbon是Netflix的负载均衡项目,为客户端通信提供支持,有以下的特性
Ribbon有以下主要模块:
在使用的时候,客户端通过负载均衡器,来决定调用哪个集群节点上的服务。
在实际开始使用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);
下面我们来在代码中查看客户端如何使用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();
}
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负责熔断处理。在微服务中,由于存在很多个微服务,各个微服务通过网络进行通讯,难免会出现依赖关系,若某一个单元出现故障,就很容易因依赖关系而引发故障的蔓延,造成“雪崩效应”,最终导致整个系统的瘫痪。
为了解决雪崩效应,我们有以下几种解决方法:
熔断器就像是保险丝,如果保险丝断掉了,电路就无法运行了。正常情况下,熔电器是关闭的,可正常请求依赖服务。当一段时间内,请求失败率到达一定阈值,熔断器就会打开,此时,不会再去请求依赖的服务。熔断器打开一段时间之后,会自动进入半开状态,此时,熔断器可允许一个请求访问依赖的服务,如果请求调用成功,则关闭熔断器,否则继续保持打开。
Hystrix是Netflix开源的一个延迟和容错库,用于隔离访问远程系统、服务或第三方库,防止级联失败,从而提升系统的可用性和易错性。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("服务启动");
}
}
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
后缀。