学习客户端负载均衡 - Ribbon
什么是负载均衡
负载均衡是高可用网络基础架构的关键组件,通常用于将工作负载分布到多个服务器来提高网站、应用、数据库或其他服务的性能和可靠性。
-
一个没有用负载均衡的web架构类似下图:
在这里用户是直连到 web 服务器,如果这个服务器宕机了,那么用户自然也就没办法访问了。另外,如果同时有很多用户试图访问服务器,超过了其能处理的极限,就会出现加载速度缓慢或根本无法连接的情况。
从图里可以看到,用户访问负载均衡器,再由负载均衡器将请求转发给后端服务器。在这种情况下,单点故障现在转移到负载均衡器上了。这里又可以通过引入第二个负载均衡器来缓解。
负载均衡算法
负载均衡算法决定了后端的哪些健康服务器会被选中。几个常用的算法:
-
Round Robin(轮询):为第一个请求选择列表中的第一个服务器,然后按顺序向下移动列表直到结尾,然后循环。
-
Least Connections(最小连接):优先选择连接数最少的服务器,在普遍会话较长的情况下推荐使用。
-
Source:根据请求源的 IP 的散列(hash)来选择要转发的服务器。这种方式可以一定程度上保证特定用户能连接到相同的服务器。
如果你的应用需要处理状态而要求用户能连接到和之前相同的服务器。可以通过 Source 算法基于客户端的 IP 信息创建关联,或者使用粘性会话(sticky sessions)。
Ribbon的负载均衡
Eureka内部集成了Ribbon, 而Ribbon是一个典型的客户端负载均衡器。使用方法:
在创建RestTemplate的时候声明@LoadBalanced
Ribbon会获取到所有的服务地址,根据内部的负载均衡算法获取到本次请求的有效地址
使用restTemplate调用远程微服务: 不需要拼接微服务的URL,以待请求的服务名替换IP地址
Ribbon负载均衡案例
准备两个商品微服务
-
商品微服务A,端口8081
server:
port: 8091
spring:
application:
name: service-product
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop?useUnicode=true&characterEncoding=utf8
username: root
password: root
jpa:
database: MySQL
show-sql: true
open-in-view: true
eureka:
client:
service-url:
defaultZone: http://localhost:9000/eureka/
instance:
prefer-ip-address: true
instance-id: ${spring.cloud.client.ip-address}:${server.port}
lease-renewal-interval-in-seconds: 5
lease-expiration-duration-in-seconds: 10
- 商品微服务B,端口8091 (除了端口不一样,其他都一样)
server:
port: 8091
订单系统中远程以负载均衡方式调用商品微服务
-
修改启动类
增加注解@LoadBalanced, 该注解提供了Ribbon的负载均衡工具
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; @SpringBootApplication @EntityScan("cn.itcast.order.entity") public class OrderApplication { @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } public static void main(String[] args) { SpringApplication.run(OrderApplication.class, args); } }
-
启动Eureka服务server,启动两个商品微服务,启动订单微服务。
-
测试调用接口 (我们在商品类中获取商品的时候些了当前调用时从那个IP和端口过来的)
我们在测试的时候可以发现,不断的调用同一个订单微服务去连接商品微服务的时候,
有时候连的是8081,有时候是8091, 这个就是Ribbon内部做的负载均衡导致的。
因为Ribbon负载均衡的策略是轮询,所以我们可以观察到调用是从这两个端口轮流来的。
Ribbon负载均衡策略
-
com.netflix.loadbalancer.RoundRobinRule: 轮询方式进行负载均衡,默认策略
-
com.netflix.loadbalancer.RandomRule: 随机策略
-
com.netflix.loadbalancer.RetryRule: 重试策略
-
com.netflix.loadbalancer.weightedResponseTimeRule: 权重策略,会计算每个服务的权重,越高的被调用可能性越大
-
com.netflix.loadbalancer.BestAvailableRule: 最佳策略,遍历所有服务实例,过滤掉故障的,返回请求最少的
-
com.netflix.loadbalancer.availabilityFilteringRule: 可用过滤策略,过滤故障和请求超过阀值的服务,剩下的轮询
策略选择推荐
-
如果每个及其配置都一样,建议不修改默认策略 (推荐)。
-
如果部分机器配置强,可改为权重策略,将高配机器权重设置高点。
如何修改策略
yml配置项增加下面的部分 (例子是将策略改为随机策略):
service-product:
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
Ribbon的重试机制
配置重试
引入请求重试依赖
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
配置请求重试机制
service-product:
ribbon:
#NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
ConnectionTimeout: 250
ReadTimeout: 10000
OkToRetryOnAllOperations: true
MaxAutoRetriesNextServer: 1
MaxAutoRetries: 1
参数解释:
ConnectionTimeout: 250 Ribbon的连接超时时间
ReadTimeout: 10000 Ribbon的数据读取超时时间
OkToRetryOnAllOperations: true 是否对所有操作都进行重试
MaxAutoRetriesNextServer: 1 切换实例的重试次数
MaxAutoRetries: 1 对当前实例的重试次数
测试重试步骤
-
启动Eureka Server
-
启动两个商品微服务提供者
-
启动微服务消费者(该消费者已经配置过Ribbon的请求重试参数,并且配置了)
-
调用消费者微服务接口,观察端口变化
-
关闭其中一个商品微服务提供者server
-
再次调用消费者微服务接口,会发现所有请求都转发到了正在启动的那台机器上。并且日志中能够看到重试的相关log
Ribbon相关配置
#服务名
<client-name>:
ribbon:
#配置Ribbon负载均衡规则:IRule
NFLoadBalancerRuleClassName:
#配置Ribbon实例检查策略:IPing
NFLoadBalancerPingClassName:
#配置负载均衡器:ILoadBalancer
NFLoadBalancerClassName:
#配置服务实例清单维护机制:ServerList
NIWSServerListClassName:
#配置服务清单过滤机制:ServerListFilter
NIWSServerListFilterClassName:
#单位ms,请求连接超时时间
ConnectTimeout:
#单位ms,请求处理的超时时间
ReadTimeout:
#对所有操作请求都进行重试
OkToRetryOnAllOperations:
#切换实例的重试次数
MaxAutoRetriesNextServer:
#对当前实例的重试次数
MaxAutoRetries:
推荐阅读
-
Spring Cloud Ribbon实现客户端负载均衡的示例
-
详解Spring Cloud负载均衡重要组件Ribbon中重要类的用法
-
java架构之-负载均衡-Ribbon 的使用
-
Kali学习笔记15:防火墙识别、负载均衡识别、WAF识别
-
Eureka源码探索(一)-客户端服务端的启动和负载均衡
-
撸一撸Spring Cloud Ribbon的原理-负载均衡策略
-
SpringCloud学习系列之二 ----- 服务消费者(Feign)和负载均衡(Ribbon)
-
#nginx学习(5)#nginx的七层负载均衡和四层负载均衡配置
-
SpringCloud-客户端的负载均衡Ribbon
-
spring cloud系列学习(SpringCloud之服务注册之Ribbon负载均衡)