Spring Cloud 学习(10) --- Ribbon(一) 负载均衡与 Ribbon

通常所说的负载均衡,一般来说都是在服务器端使用 Ngnix 或 F5 做 Server 的负载均衡策略,在 Ribbon 中提到的负载均衡,一般来说是指的客户端负载均衡,即 ServiceA 调用 ServiceB,有多个 ServiceB 的情况下,由 ServiceA 选择调用哪个 ServiceB。

负载均衡与 Ribbon

负载均衡(Load Balance),是一种利用特定方式,将流量分摊到多个操作单元上的手段,它对系统吞吐量、系统处理能力有着质的提升。最常见的负载均衡分类方式有:软负载、硬负载,对应 Ngnix、F5;集中式负载均衡、进程内负载均衡。集中式负载均衡是指位于网络和服务提供者之间,并负责把忘了请求转发到各个提供单位,代表产品有 Ngnix、F5;进程负载均衡是指从一个实例库选取一个实例进行流量导入,在微服务范畴,实例库一般是存储在 Eureka、Consul、Zookeeper 等注册中心,此时的负载均衡器类似 Ribbon 的 IPC(进程间通信)组件,因此进程内负载均衡也叫做客户端负载均衡。

Ribbon 是一个客户端负载均衡器,赋予了应用一些支配 HTTP 与 TCP 行为的能力,由此可以得知,这里的客户端负载均衡也是进程内负载均衡的一周。 Ribbon 在 SpringCloud 生态内的不可缺少的组件,没有了 Ribbon,服务就不能横向扩展。Feign、Zuul 已经集成了 Ribbon。


示例

Eureka Server 不再赘述,可以直接使用 spring-cloud-eureka-server-simple

Consumer

源码:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-ribbon/spring-cloud-ribbon-consumer

yml:

spring:
  application:
    name: spring-cloud-ribbon-consumer

server:
  port: 9999

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${server.port}

配置类:

@Bean
@LoadBalanced
public RestTemplate restTemplate(){
    return new RestTemplate();
}

@LoadBalanced:对 RestTemplate 启动负载均衡

Consumer Controller

@RestController
public class ConsumerController {

    private final RestTemplate restTemplate;

    @Autowired
    public ConsumerController(RestTemplate restTemplate) {
        this.restTemplate = restTemplate;
    }

    @GetMapping(value = "/check")
    public String checkRibbonProvider(){
        return restTemplate.getForObject("http://spring-cloud-ribbon-provider/check", String.class);
    }

}

provider

源码:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-ribbon/spring-cloud-ribbon-provider

pom 依赖:

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
    </dependency>
</dependencies>

配置文件:

spring:
  application:
    name: spring-cloud-ribbon-provider

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka
  instance:
    prefer-ip-address: true
    instance-id: ${spring.application.name}:${server.port}

ProviderContr

@RestController
public class ProviderController {

    @Value("${server.port}")
    private int port;

    @GetMapping(value = "/check")
    public String providerPort(){
        return "Provider Port: " + port;
    }
}

验证

分别启动 Eureka Server、Consumer、Provider,其中,Provider 以 mvn 形式启动,绑定不同的端口号:

mvn spring-boot:run -Dserver.port=8080
mvn spring-boot:run -Dserver.port=8081

postman 访问 Consumer


第一次请求

第二次请求

可以看到,Provider 两次返回值不一样,验证了负载均衡成功。


负载均衡策略

Ribbon 中提供了 七种 负载均衡策略

策略类 命名 描述
RandomRule 随机策略 随机选择 Server
RoundRobinRule 轮询策略 按照顺序循环选择 Server
RetryRule 重试策略 在一个配置时间段内,当选择的 Server 不成功,则一直尝试选择一个可用的 Server
BestAvailableRule 最低并发策略 逐个考察 Server,如果 Server 的断路器被打开,则忽略,在不被忽略的 Server 中选择并发连接最低的 Server
AvailabilityFilteringRule 可用过滤测试 过滤掉一直连接失败,并被标记未 circuit tripped(即不可用) 的 Server,过滤掉高并发的 Server
ResponseTimeWeightedRule 响应时间加权策略 根据 Server 的响应时间分配权重,响应时间越长,权重越低,被选择到的几率就越低
ZoneAvoidanceRule 区域权衡策略 综合判断 Server 所在区域的性能和 Server 的可用性轮询选择 Server,并判定一个 AWS Zone 的运行性能是否可用,剔除不可用的 Zone 中的所有 Server

Ribbon 默认的负载均衡策略是 轮询策略

设置负载均衡策略

设置全局负载均衡

创建一个声明式配置,即可实现全局负载均衡配置:

@Configuration
public class RibbonConfig {
    /**
     * 全局负载均衡配置:随机策略
     */
    @Bean
    public IRule ribbonRule(){
        return new RandomRule();
    }

}

重启 Consumer,访问测试

基于注解的配置

空注解

声明一个空注解,用于使用注解配置 Ribbon 负载均衡

public @interface RibbonAnnotation {
}

负载均衡配置类

@Configuration
@RibbonAnnotation
public class RibbonAnnoConfig {

    private final IClientConfig clientConfig;

    @Autowired(required = false)
    public RibbonAnnoConfig(IClientConfig clientConfig) {
        this.clientConfig = clientConfig;
    }

    @Bean
    public IRule ribbonRule(IClientConfig clientConfig){
        return new RandomRule();
    }
}

启动类

@SpringBootApplication
@EnableDiscoveryClient

@RibbonClient(name = "spring-cloud-ribbon-provider", configuration = RibbonAnnoConfig.class)
@ComponentScan(excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = RibbonAnnotation.class)})
public class SpringCloudRibbonConsumerApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringCloudRibbonConsumerApplication.class, args);
    }

    @Bean
    @LoadBalanced
    public RestTemplate restTemplate(){
        return new RestTemplate();
    }

}

@RibbonClient:针对 spring-cloud-ribbon-provider 服务,使用负载均衡,配置类是 configuration 标注的类。
@ComponentScan:让 Spring 不去扫描被 @RibbonAnnotation 类标记的配置类,因为我们的配置对单个服务生效,不能应用于全局,如果不排除,启动就会报错

如果需要对多个服务进行配置,可以使用 @RibbonClients 注解

@RibbonClients(value = {
        @RibbonClient(name = "spring-cloud-ribbon-provider", configuration = RibbonAnnoConfig.class)        
})

重启 Consumer,验证基于注解的负载均衡是否成功

基于配置文件的负载均衡策略

语法:

{instance-id}: # instance-id 即被调用服务名称
    ribbon:
        NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

Ribbon 配置

源码:https://gitee.com/laiyy0728/spring-cloud/tree/master/spring-cloud-ribbon/spring-cloud-ribbon-config

超时与重试

HTTP 请求难免会出现请求超时,此时对调用进行时限的控制以及在时限之后的重试尤为重要。对于超时重试的配置如下:

{instance-id}: # instance-id 指的是被调用者的服务名称
  ribbon:
    ConnectTimeout: 30000 # 链接超时时间
    ReadTimeout: 30000 # 读超时时间
    MaxAutoRetries: 1 # 对第一次请求的服务的重试次数
    MaxAutoRetriesNextServer: 1 # 要重试的下一个服务的最大数量(不包括第一个服务)
    OkToRetryOnAllOperations: true # 是否对 连接超时、读超时、写超时 都进行重试

Ribbon 饥饿加载

Ribbon 在进行负载均衡时,并不是启动时就加载上线文,而是在实际的请求发送时,才去请求上下文信息,获取被调用者的 ip、端口,这种方式在网络环境较差时,往往会使得第一次引起超时,导致调用失败。此时需要指定 Ribbon 客户端,进行饥饿加载,即:在启动时就加载好上下文。

ribbon:
  eager-load:
    enabled: true
    clients: spring-cloid-ribbon-provider

此时启动 consumer,会看到控制打印信息如下:

Client: spring-cloid-ribbon-provider instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
Using serverListUpdater PollingServerListUpdater
DynamicServerListLoadBalancer for client spring-cloid-ribbon-provider initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=spring-cloid-ribbon-provider,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@79e7188e

可以看到启动时就加载了 spring-cloid-ribbon-provider,并绑定了LoadBalancer

Ribbon 常用配置

配置项 说明
{instance-id}:ribbon.NFLoadBalancerClassName 指负载均衡器类路径
{instance-id}:ribbon:NFLoadBalancerRuleClassName 指定负载均衡算法类路径
{instance-id}:ribbom:NFLoadBalancerPingClassName 指定检测服务存活的类路径
{instance-id}:ribbon:NIWSServerListClassName 指定获取服务列表的实现类路径
{instance-id}:ribbon:NIWSServerListFilterClassName 指定服务的 Filter 实现类路径

Ribbon 脱离 Eureka

默认情况下,Ribbon 客户端会从 Eureka Server 读取服务注册信息列表,达到动态负载均衡的功能。如果 Eureka 是一个提供多人使用的公共注册中心(如 SpringCloud 中文社区公益 Eureka:http://eureka.springcloud.cn),此时极易产生服务侵入问题,此时就不能从 Eureka 中读取服务列表,而应该在 Ribbon 客户端自行制定源服务地址

ribbon:
  eureka:
    enabled: false # Ribbon 脱离 Eureka 使用

{instance-id}:
  ribbon:
    listOfServers: http://localhost:8888 # 制定源服务地址
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342