Spring Cloud 系列-Ribbon

背景

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

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

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

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

负载均衡

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

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

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

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

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

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

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

搭建demo

核心依赖

<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>

服务提供方

@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配置

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

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

image.png
image.png

服务调用方

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

application.properties

## 用户 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}

核心代码

@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

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

整体项目概览

image.png

Ribbon的负载均衡策略

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。

切换漏由策略

ribbon-provider.ribbon.NFLoadBalancerRuleClassName= \
  com.netflix.loadbalancer.RandomRule

在ClientApplication.java 中加入

    @Bean
    public IRule ribbonRule() {
        return new RandomRule();//这里配置策略,和配置文件对应
    }

其他漏由方式与此一致

自定义规则

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的健康检查机制实现了

package com.netflix.loadbalancer;

import com.netflix.loadbalancer.Server;

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

自定义MyPing

/**
 * 实现 {@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

## 扩展 IPing 实现
ribbon-provider.ribbon.NFLoadBalancerPingClassName = \
  pikachu.com.ping.MyPing

总结

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

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

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

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏禁心尽力

如何在分布式环境中同步solr索引库和缓存信息

     搜索无处不在,相信各位每天都免不了与它的亲密接触,那么我想你确实有必要来了解一下它们,就上周在公司实现的一个小需求来给各位分享一下:如何在分布式环境...

24290
来自专栏cloudskyme

hadoop使用(四)

做一个网络爬虫的程序吧,根据客户的需求,要求把相关的内容爬取到本地 最终选择的是apache nutch,到目前为止最新的版本是1.3 1. Nutch是什么?...

41380
来自专栏Java技术栈

分布式服务防雪崩熔断器,Hystrix理论+实战。

Hystrix是什么? hystrix对应的中文名字是“豪猪”,豪猪周身长满了刺,能保护自己不受天敌的伤害,代表了一种防御机制,这与hystrix本身的功能不谋...

50850
来自专栏自由而无用的灵魂的碎碎念

解决因为卸载vmware后键盘不能使用的问题

我之前安装的是vmware workstation 7.1,虽然添加与删除程序里有卸载选项,不过不管用,无奈用windows 优化大师将其卸载了。然后手动删除一...

12330
来自专栏最新技术

使用Eclipse MicroProfile(更新版)构建您的下一个微服务

本快速教程将向您展示如何使用最新版本的Eclipse MicroProfile API构建您的下一个微服务。这是一篇基于以前John D Ament 的文章的修...

87720
来自专栏技术翻译

使用Netflix Hystrix保护您的应用程序

借助微服务架构,我们可以构建灵活且可独立部署的软件模块或系统,这些模块或系统通过HTTP资源API等轻量机制相互通信并提供结果。与单一应用程序相比,它具有许多优...

11900
来自专栏挖掘大数据

Apache NiFi 简介及Processor实战应用

Apache NiFi是什么?NiFi官网给出如下解释:“一个易用、强大、可靠的数据处理与分发系统”。通俗的来说,即Apache NiFi 是一个易于使用、功能...

2K100
来自专栏Laoqi's Linux运维专列

ssh访问控制,多次失败登录即封掉IP,防止暴力破解

近期一直发现站内的流量和IP不太正常,读取/var/log/secure 很多失败的登录信息!必须要整个方法整死他们,虽然我已经把ssh port修改为了XXX...

49640
来自专栏SeanCheney的专栏

爬虫框架整理汇总

50260
来自专栏张善友的专栏

使用Hystrix提高系统可用性

今天稍微复杂点的互联网应用,服务端基本都是分布式的,大量的服务支撑起整个系统,服务之间也难免有大量的依赖关系,依赖都是通过网络连接起来。 ? (图片来源:htt...

22250

扫码关注云+社区

领取腾讯云代金券