前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Cloud 系列-Ribbon

Spring Cloud 系列-Ribbon

原创
作者头像
3号攻城狮
发布2018-07-23 19:21:18
4420
发布2018-07-23 19:21:18
举报

背景

最近在系统性的学习Spring Cloud方面的知识点。

强推一波:https://segmentfault.com/ls/1650000011386794

上面是大佬小马哥的教学视频。

今天的内容是学习完章节七后的课后总结。

负载均衡

负载均衡(Load Balance): 建立在现有网络结构之上,它提供了一种廉价有效透明的方法扩展网络设备和服务器的带宽、增加吞吐量、加强网络数据处理能力、提高网络的灵活性和可用性。其意思就是分摊到多个操作单元上进行执行,例如Web服务器、FTP服务器、企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务。

1、服务端负载均衡:客户端请求到负载均衡服务器,负载均衡服务器根据自身的算法将该请求转给某台真正提供业务的服务器,该服务器将响应数据给负载均衡服务器,负载均衡服务器最后将数据返回给客服端。(nginx)

2、客服端负载均衡:基于客户端的负载均衡,简单的说就是在客户端程序里面,自己设定一个调度算法,在向服务器发起请求的时候,先执行调度算法计算出向哪台服务器发起请求,然后再发起请求给服务器。

基于客户端负载均衡的特点:

由客户端内部程序实现,不需要额外的负载均衡器软硬件投入。

程序内部需要解决业务服务器不可用的问题,服务器故障对应用程序的透明度小。

程序内部需要解决业务服务器压力过载的问题。

搭建demo

核心依赖

代码语言:txt
复制
<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>

服务提供方

代码语言:txt
复制
@RestController
@RequestMapping(value = "/users")
public class DemoController {

    private User providerUser = null;

    @PostMapping
    public Object save(@RequestBody User user) {
        providerUser = user;
        return providerUser;
    }

    @GetMapping
    public Object get() {
        return providerUser;
    }
}

提供一个save方法,便于我们区分我们访问的服务信息,在测试的时候,provider端我们会同时启动两个实例.分别赋予不同的值.

application.properties配置

代码语言:txt
复制
## 用户服务提供方应用信息
spring.application.name = ribbon-provider
## 关闭 Eureka Client,显示地通过配置方式注册 Ribbon 服务地址
eureka.client.enabled = false
image.png
image.png
image.png
image.png

配置两个实例并启动,通过saveAPI分别赋值。

image.png
image.png
image.png
image.png

服务调用方

代码语言:txt
复制
@SpringBootApplication
@RibbonClient("ribbon-provider")//与application.properties文件中的配置呼应
public class ClientApplication {
    public static void main(String[] args) {
        SpringApplication.run(ClientApplication.class, args);
    }
}

application.properties

代码语言:txt
复制
## 用户 Ribbon 客户端应用
spring.application.name = ribbon-client

## 服务端口
server.port = 8080

## 提供方服务名称
provider.service.name = ribbon-provider
## 提供方服务主机
provider.service.host = localhost
## 提供方服务端口
provider.service.port1 = 9090
provider.service.port2 = 9091

## 关闭 Eureka Client,显示地通过配置方式注册 Ribbon 服务地址
eureka.client.enabled = false

## 定义 user-service-provider Ribbon 的服务器地址
## 为 RibbonLoadBalancerClient 提供服务列表
ribbon-provider.ribbon.listOfServers = \
  http://${provider.service.host}:${provider.service.port1} ,\
   http://${provider.service.host}:${provider.service.port2}

核心代码

代码语言:txt
复制
@RestController
@RequestMapping(value = "/client")
public class ClientController {

    /**
     * 负载均衡器客户端
     */
    @Autowired
    private LoadBalancerClient loadBalancerClient;

    @Value("${provider.service.name}")
    private String providerServiceName;
    
    @GetMapping
    public User index() throws IOException {
        // 选择指定的 service Id
        ServiceInstance serviceInstance = loadBalancerClient.choose(providerServiceName);
        return loadBalancerClient.execute(providerServiceName, serviceInstance, instance -> {
            //服务器实例,获取 主机名(IP) 和 端口
            String host = instance.getHost();
            int port = instance.getPort();
            String url = "http://" + host + ":" + port + "/users";
            RestTemplate restTemplate = new RestTemplate();
            return restTemplate.getForObject(url,  User.class);
        });
    }
}

访问客户端API:

image.png
image.png
image.png
image.png

默认配置下,ribbon提供的负载均衡方式是轮训,从访问的结果也可以看出来

整体项目概览

image.png
image.png

Ribbon的负载均衡策略

代码语言:txt
复制
1. RoundRobinRule(轮询模式)ribbon的默认策略;
2. RandomRule(随机策略) public class RandomRule extends AbstractLoadBalancerRule 随机选择一个server 在index上随机,选择index对应位置的server。
3. BestAvailableRule(并发量) public class BestAvailableRule extends ClientConfigEnabledRoundRobinRule 选择一个最小的并发请求的server 逐个考察Server,如果Server被tripped了,则忽略,在选择其中ActiveRequestsCount最小的server
4.AvailabilityFilteringRule(服务器状态) public class AvailabilityFilteringRule extends PredicateBasedRule 过滤掉那些因为一直连接失败的被标记为circuit tripped的后端server,并过滤掉那些高并发的的后端server(active connections 超过配置的阈值) 使用一个AvailabilityPredicate来包含过滤server的逻辑,其实就就是检查status里记录的各个server的运行状态 
4. WeightedResponseTimeRule(根据响应时间) public class WeightedResponseTimeRule extends RoundRobinRule 根据响应时间分配一个weight,相应时间越长,weight越小,被选中的可能性越低。 一个后台线程定期的从status里面读取评价响应时间,为每个server计算一个weight。Weight的计算也比较简单responsetime 减去每个server自己平均的responsetime是server的权重。当刚开始运行,没有形成statas时,使用roubine策略选择server。
5. ZoneAvoidanceRule(Zone状态+服务状态)	public class ZoneAvoidanceRule extends PredicateBasedRule	复合判断server所在区域的性能和server的可用性选择server	使用ZoneAvoidancePredicate和AvailabilityPredicate来判断是否选择某个server,前一个判断判定一个zone的运行性能是否可用,剔除不可用的zone(的所有server),AvailabilityPredicate用于过滤掉连接数过多的
Server。

切换漏由策略

代码语言:txt
复制
ribbon-provider.ribbon.NFLoadBalancerRuleClassName= \
  com.netflix.loadbalancer.RandomRule

在ClientApplication.java 中加入

代码语言:txt
复制
    @Bean
    public IRule ribbonRule() {
        return new RandomRule();//这里配置策略,和配置文件对应
    }

其他漏由方式与此一致

自定义规则

代码语言:txt
复制
public class MyRule extends AbstractLoadBalancerRule {

    public MyRule() {
    }

    @SuppressWarnings({"RCN_REDUNDANT_NULLCHECK_OF_NULL_VALUE"})
    public Server choose(ILoadBalancer lb, Object key) {
        //自定义获取Server逻辑 可以参考其他规则的获取方式
        return null;
    }

    public Server choose(Object key) {
        return this.choose(this.getLoadBalancer(), key);
    }

    public void initWithNiwsConfig(IClientConfig clientConfig) {
    }
}

自定义规则的使用方式与官方提供的其他规则使用方式一致

健康检查机制

阅读源码可知,ribbon的健康检查机制实现了

代码语言:txt
复制
package com.netflix.loadbalancer;

import com.netflix.loadbalancer.Server;

public interface IPing {
    boolean isAlive(Server var1);
}

自定义MyPing

代码语言:txt
复制
/**
 * 实现 {@link IPing} 接口:检查对象 /health 是否正常状态码:200
 * 
 * 如何实现可以根据实际情况考虑
 */
public class MyPing implements IPing {

    @Override
    public boolean isAlive(Server server) {
        String host = server.getHost();
        int port = server.getPort();
        // /health endpoint
        // 通过 Spring 组件来实现URL 拼装
        UriComponentsBuilder builder = UriComponentsBuilder.newInstance();
        builder.scheme("http");
        builder.host(host);
        builder.port(port);
        builder.path("/health");
        URI uri = builder.build().toUri();
        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity responseEntity = restTemplate.getForEntity(uri, String.class);
        // 当响应状态等于 200 时,返回 true ,否则 false
        return HttpStatus.OK.equals(responseEntity.getStatusCode());
    }
}

使用MyPing

代码语言:txt
复制
## 扩展 IPing 实现
ribbon-provider.ribbon.NFLoadBalancerPingClassName = \
  pikachu.com.ping.MyPing

总结

以上为该课程后的小结,如有不正确的地方,小伙伴么评论区QAQ.

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景
  • 负载均衡
  • 搭建demo
    • 核心依赖
      • 服务提供方
        • 服务调用方
        • 整体项目概览
        • Ribbon的负载均衡策略
          • 切换漏由策略
            • 自定义规则
              • 健康检查机制
                • 自定义MyPing
                  • 使用MyPing
                  • 总结
                  相关产品与服务
                  负载均衡
                  负载均衡(Cloud Load Balancer,CLB)提供安全快捷的流量分发服务,访问流量经由 CLB 可以自动分配到云中的多台后端服务器上,扩展系统的服务能力并消除单点故障。负载均衡支持亿级连接和千万级并发,可轻松应对大流量访问,满足业务需求。
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档