Spring Cloud 之 Ribbon 负载均衡

时间:2022-07-25
本文章向大家介绍Spring Cloud 之 Ribbon 负载均衡,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Spring Cloud 之 Ribbon 负载均衡

文章目录

简介

什么是负载均衡

负载均衡(Load Balance), 是利用特定的方式将流量分摊到多个操作单元上的一种手段, 它对系统吞吐量和系统处理能力有质的提升. 可分为软负载和硬负载, 软负载即通过软件的方式实现负载均衡, 软负载有分为客户端负载和服务端负载, Ribbon 属于客户端负载均衡.

简单的入门案例

  • 一个注册中心
  • 一个服务端可以通过修改端口号的形式, 启动多个实例
  • 一个客户端
  • 项目整体结构采用 maven 多 Module 结构: |_ ribbon-demo-ms |_ eureka-server // 注册中心, 给内部服务做服务发现 |_ app-server // 服务提供端, 提供 Restful 接口, 启动多个实例 |_ app-client // 服务调用端, 通过 FeignClient 调用 ribbon-server 的接口

创建一个 Eureka Server

创建一个 AppServer

通过修改端口号的方式, 启动多个实例:

java -Dserver.port=8762 -jar appserver.jar
java -Dserver.port=8763 -jar appserver.jar
  • pom 文件配置 <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies>
  • 编写工程的配置文件: application.yml eureka: client: serverUrl: defaultZone: http://localhost:8761/eureka/ server: port: 8762 spring: application: name: app-server
  • 编写项目的启动类, 在类名上添加 @EnableEurekaClient 注解. 启动项目后, 在服务注册页面可以看到 app-server 的注册信息 @SpringBootApplication @EnableEurekaClient public class EurekaClientApplication { public static void main(String[] args) { SpringApplication.run(EurekaClientApplication.class, args); } }
  • 定义一个 Restful 接口给客户端使用 @GetMapping("/port") public String printRequest(HttpServletRequest request) { // 返回当前实例的端口号 return request.getServerPort(); }

创建一个 AppClient 服务

  • pom 配置, 使用 FeignClient 调用 AppServer 的服务, 中间使用到 Ribbon 负载均衡, 所以要引入 Feign 和 Ribbon 的依赖 <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</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> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-ribbon</artifactId> </dependency> </dependencies>
  • 编写工程配置文件 eureka: client: serverUrl: defaultZone: http://localhost:8761/eureka/ instance: lease-renewal-interval-in-seconds: 5 lease-expiration-duration-in-seconds: 15 perfer-in-address: true server: port: 8765 spring: application: name: app-client feign: client: config: default: connectTimeout: 5000 # 连接超时时间 readTimeout: 5000 # 读超时间 loggerLevel: full # 日志内容 logging: level: com.deepflow.clients.api.*: debug # 日志级别
  • 编写项目的启动类, 在类名上添加 @EnableEurekaClient 和 EnableFeignClients 注解. 启动项目后, 在服务注册页面可以看到 app-client 的注册信息 @SpringBootApplication @EnableFeignClients({"com.deepflow.clients.api"}) public class CommentServerApplication { public static void main(String[] args) { SpringApplication.run(CommentServerApplication.class, args); } }
  • 编写 FeignClient 接口, 调用 app-server 的服务, feign 自带了 Ribbon 功能 package com.deepflow.clients.api; @FeignClient(name = "app-server",url="${custom.feign.url}") public interface appServer { @GetMapping(value = "/port", consumes = MediaType.APPLICATION_JSON_VALUE) String printRequest(); }
  • 定义一个 Restful 接口给 Postman 使用 package com.deepflow.controller; @RestController @RequestMapping("/test/ribbon") public class appClientController { @Autowired private appServer appServerService; @GetMapping("/ports") public String getappPort(Integer a, Integer b) { return appServerService.printRequest(); } }

测试效果

用 Postman 调用 http://localhost:8765/test/ribbon/ports, 返回结果 8762 和 8763 依次交替出现. 说明负载均衡已经起到作用了, 并且是按顺序交替把请求分配到 app-server:8762 和 app-server:8763 两个实例上

Ribbon 负载均衡策略

Ribbon 有7种负载均衡策略, 默认的是轮询策略. 补充一下 nginx 常用的负载均衡策略: 轮询(Round Robin)、权重(Weigh)、ip_hash 等

策略类

命名

描述

RandomRule

随机策略

随机选择策略 server

RoundRobinRule

轮询策略

按顺序循环选择 server (Ribbon 默认策略)

RetryRule

重试策略

在一个配置时间段内选择 server 不成功, 则一直尝试选择一个可用的 server (默认重试时间 500 ms, 默认重试策略还是 RoundRobinRule)

ResponseTimeWeightedRule

响应时间加权策略

根据 server 的响应时间分配权重. 响应时间越长, 权重越低. 被选择到的概率就越低; 响应时间越短, 权重越高, 被选择到的概率就越高. 这个策略很贴切, 综合了各种因素, 如: 网络、磁盘、IO等, 这些因素直接影响响应时间

BestAvailableRule

最低并发策略

逐个考察 server, 如果 server 断路器打开, 则忽略, 再选择其中并发链接最低的 server

AvailabilityFilteringRule

可用过滤策略

过滤掉一直失败并被标记为circuit tripped的server,过滤掉那些高并发链接的server(active connections超过配置的阈值)

ZoneAvoidanceRule

区域权重策略

综合判断 server 所在区域的性能, 和 server 的可用性, 轮询选择server 并且判断一个 AWS Zone 的运行性能是否可用, 剔除不可用的Zone 中的所有 server

Ribbon 工作原理

Ribbon 核心接口

接口是一个组件的骨架, 通过了解接口, 能够把握其核心设计及功能, Ribbon 完全是按照这些接口搭建起来的. Ribbon 有 7 个核心接口:

接口

描述

默认实现类

IClientConfig

定义 Ribbon 中管理配置的接口

DefaultClientConfigImpl

IRule

定义 Ribbon 中负载均衡策略的接口

ZoneAvoidanceRule

IPing

定义定期 ping 服务检查可用性接口

DummyPing

ServerList

定义获取服务列表方法的接口

ConfigurationBasedServerList

ServerListFilter

定义特定场景下, 获取服务列表的方法接口

ZonePreferenceServerListFilter

ILoadBalancer

定义负载均衡选择服务的核心方法的接口

ZoneAwareLoadBalancer

ServerListUpdater

为 DynamicServerListLoadBalancer 定义动态更新服务列表的接口

PollingServerListUpdater

性能优化

Ribbon 是懒加载机制, 并不是在项目启动的时候就加载上下文, 而是在实际请求的时候才去创建. 这种情况下, 第一次调用可能会出现用时比较长的现象, 甚至有可能会引起调用超时. 可以通过配置的方式开启饥饿加载

  • application.yaml 配置 ribbon: eager-load: enabled: true clients: joke-server
  • 测试效果 启动项目后, 可以看到打印的堆栈日志, 启动的时候 Ribbon 便加载上了应用程序的上下文 2020-04-21 11:48:57.897 INFO 15668 --- [ main] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client joke-server initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=joke-server,current list of Servers=[localhost:8763],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;] },Server stats: [[Server:localhost:8763; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0] ]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@22d477c2 2020-04-21 11:49:27.865 INFO 15668 --- [mer-joke-server] c.n.l.WeightedResponseTimeRule : Weight adjusting job started

问题

  • 如何更换负载均衡策略?