1.负载均衡算法
Ribbon内置7种负载均衡算法,每种算法对应了一个算法类如下:
内置负载均衡规则类 | 规则描述 |
RoundRobinRule(默认) | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule | 对以下两种服务器进行忽略:(1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。可以通过修改配置loadbalancer..connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。(2)并发数过高的服务器。并发连接数的上线,可以由客户端的..ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule | 为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。 |
BestAvailableRule | 忽略哪些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
Retry | 重试机制的选择逻辑 |
1.1配置负载均衡算法
Ribbon可以进行全局负载均衡算法配置,也可以针对于具体的服务做不同的算法配置。同时可以使用注解方式和yml配置方式来实现上面两种情况。
1.注解全局配置
随机算法的效果最好演示,我们把负载均衡算法修改成随机算法,只需要RandomRule配置成Bean即可,修改主配置类如下:
/**
* 订单的启动类
* @EnableEurekaClient: 标记该应用是 Eureka客户端
*/
@SpringBootApplication
@EnableEurekaClient
public class OrderServerApplication1020 {
public static void main(String[] args) {
SpringApplication.run(OrderServerApplication1020.class);
}
//配置一个RestTemplate ,Spring封装的一个机遇Restful风格的http客户端 工具
@Bean
@LoadBalanced
public RestTemplate restTemplate(){
return new RestTemplate();
}
//负载均衡算法
@Bean
public RandomRule randomRule(){
return new RandomRule();
}
}
2.配置具体服务的负载均衡
参照官方文档:https://cloud.spring.io/spring-cloud-static/Greenwich.SR5/multi/multi_spring-cloud-ribbon.html#_customizing_the_ribbon_client
3.负载均衡底层源码
负载均衡算法底层都有choose方法,例如轮询:
//modulo服务器数量,例如3台模出来取余始终是0,1,2,达到轮询效果
do {
current = this.nextServerCyclicCounter.get();
next = (current + 1) % modulo;
}
4.yml方式配置负载均衡算法
配置全局Ribbon算法
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
配置某个服务的Ribbon算法
user-server:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
2.客户端负载均衡 - Feign
Feign:基于Ribbon封装,简化url,参数的拼接过程
1.Feign代码实战
官方参考文档:OpenFeign
搭建新工程“支付服务”来演示Feign
1.1导入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--2.导入Feign的包-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!--web包-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 依赖公共模块 -->
<dependency>
<groupId>com.jcy</groupId>
<artifactId>springcloud-netflix-pojo-user</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
2.配置类
配置类增加@EnableFeignClients标签,开启feign支持
3.yml配置
#注册到EurekaServer
eureka:
client:
serviceUrl:
defaultZone: http://localhost:1010/eureka/
instance:
instance-id: pay-server-1040
spring:
application:
name: pay-server
server:
port: 1040
logging:
level:
com.jcy: debug
4.编写Feign的客户端接口
Feign的客户端接口是用来调用微服务的
@FeignClient(“user-server”) : user-server是用户服务的服务名字,Feign根据服务名能够在注册中心找到目标服务的通信地址
@FeignClient(value = "user-server",fallbackFactory = UserFeignClientFallbackFactory.class)
public interface UserFeignClient {
//订单服务来调用这个方法 http://user-server/user/1
@GetMapping(value = "/user/{id}")
User getById(@PathVariable("id") Long id);
}
5.编写Controller使用Feign接口
注入UserFeignClient ,直接调用UserFeignClient.getById方法,该接口已经被Feign代理,我们发起调用时其实在像Feign接口配置的目标服务发起调用。
/**
* 支付服务
*/
@RestController
public class PayController{
@Autowired
private UserFeignClient userFeignClient;
//浏览器调用
@RequestMapping("/pay/{id}")
public User getById(@PathVariable("id")Long id){
//使用Feign调用用户服务获取User
return userFeignClient.getById(id);
}
}
6.测试
依次启动注册中心springcloud-eureka-server-1010 ,两个用户服务springcloud-user-server-1020 , 启动支付服务 springcloud-pay-server-1040
通过浏览器访问pay-server的controller:http://localhost:1040/pay/1,多次请求发现依然默认使用了轮询策略
7.Feign的工作原理
要使用Feign,我们除了导入依赖之外,需要主配置类通过@EnableFeignClients(value="")注解开启Feign,也可以通过value属性指定了Feign的扫描包。同时我们需要为Feign编写客户端接口,接口上需要注解@FeignClient标签。 当程序启动,注解了@FeignClient的接口将会被扫描到然后交给Spring管理。
当请求发起,会使用jdk的动态代理方式代理接口,生成相应的RequestTemplate,Feign会为每个方法生成一个RequestTemplate同时封装好http信息,如:url,请求参数等等
最终RequestTemplate生成request请求,交给Http客户端(UrlConnection ,HttpClient,OkHttp)。然后Http客户端会交给LoadBalancerClient,使用Ribbon的负载均衡发起调用。
8.feign开启日志打印
yml配置feign日志打印级别
logging:
level:
com.jcy: debug
Feign配置类
/**
* feign日志
*/
@Configuration
public class FeignConfiguration {
@Bean
Logger.Level feignLoggerLevel() {
return Logger.Level.FULL; //打印Feign的所有日志
}
}