负载均衡
使用微服务后,为了能够承担高并发的压力,同一个服务可能会启动多个实例。这时候消费者就需要负载均衡,把请求分散到各个实例。负载均衡主要有两种设计:
- 服务端负载均衡
- 客户端负载均衡
对于传统的分布式服务来说,大多使用服务端负载均衡。一般会使用Nginx或者ELB等工具作为负载均衡器,如下图:
而在Spring Cloud中,使用的是客户端负载均衡
的方式,使用Ribbon组件来实现客户端的负载均衡。主要引入了微服务注册中心依赖,就会自动引入Ribbon依赖。客户端负载均衡原理如下图:
Ribbon的原理
Ribbon
利用了RestTemplate
的拦截器(接口是ClientHttpRequestInterceptor
)机制,在拦截器中实现的负载均衡。负载均衡的基本实现就是利用从服务注册中心获取可用的服务地址列表,然后通过一定算法负载,决定使用哪一个服务地址来进行HTTP调用。
详情可以查看LoadBalancerInterceptor
这个类,在org.springframework.cloud.client.loadbalancer
包下。
负载均衡策略
查看IRule
接口的实现类,可以看到Ribbon的所有负载均衡策略,查看各实现类顶部的注释可以看到它的具体策略:
- RandomRule:随机选择;
- RoundRobinRule:轮询;
- WeightedResponseTimeRule:根据每个服务的响应时间设置权重,响应时间越长,所占权重越少;
- AvailabilityFilteringRule:过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值);
- ZoneAvoidanceRule:使用
CompositePredicate
根据区域和可用性过滤服务器的规则; - BestAvailableRule:选择一个最小的并发请求的server;
- RetryRule:在现有的策略基础上,添加重试机制,因为
IRule
支持级联。
远程调用(OpenFeign)
Spring Cloud提供了OpenFeign
组件(以前叫Feign)来进行远程的HTTP调用。它是对RestTemplate
的一个封装。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。
- Feign 采用的是基于接口的注解
- Feign 整合了ribbon,具有负载均衡的能力
- 整合了Hystrix,具有熔断的能力
Feign是一个声明式Web Service客户端。使用Feign能让编写Web Service客户端更加简单。Spring Cloud对Feign进行了封装,使其支持了Spring MVC标准注解和HttpMessageConverters。Feign可以与微服务注册中心和Ribbon组合使用以支持负载均衡。
使用OpenFeign
因为Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果,所以已Feign为例。
- 准备:
- 启动
eureka-server
。 - 启动service-client工程,它的端口为8762;然后将service-client的配置文件的端口改为8763,并启动。
- 首先创建一个项目service-feign,引入依赖
spring-cloud-starter-openfeign
、Eureka的起步依赖spring-cloud-starter-netflix-eureka-client
,完整的pom如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bazooka</groupId>
<artifactId>service-feign</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>service-feign</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>com.bazooka</groupId>
<artifactId>Feign-sample</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在工程的配置文件application.yml文件,指定程序名为service-feign,端口号为8765,服务注册地址为http://localhost:8761/eureka/
,完整的application.yml如下
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
server:
port: 8765
spring:
application:
name: service-feign
- 第二步,启动配置,在启动类上添加@EnableFeignClients注解:
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient
@EnableFeignClients
public class ServiceFeignApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceFeignApplication.class, args);
}
}
- 第三步,声明调用接口
@FeignClient("service-client")
public interface UserClient {
@GetMapping("/client")
String sayHello(@RequestParam(value = "name") String name);
}
- 第四步:使用,注解使用
@Autowired
注解注入就可以了:
@RestController
public class HelloController {
@Autowired
UserClient userClient;
@GetMapping("/sayHello")
public String sayHello(@RequestParam String name){
return userClient.sayHello(name);
}
}
- 第五步,启动程序会看到浏览器交替显示如下
hi Beck Wang ,i am from port:8762
hi Beck Wang ,i am from port:8763
- 此时的架构示意图