专栏首页MyTechnologyRibbon核心组件IRule及负载均衡算法

Ribbon核心组件IRule及负载均衡算法

Ribbon常用负载均衡算法:

IRule接口,Riboon使用该接口,根据特定算法从所有服务中,选择一个服务,

Rule接口有7个实现类,每个实现类代表一个负载均衡算法,默认使用轮询

如何替换掉轮询

我们需要新建一个规则类,然后在启动类中添加注解即可。

但是:

官方文档给出了警告:

这个自定义配置类不能放在 @CommpomentScan 所扫描的当前包下以及子包下,

(即不能放在SpringBoot启动类包下及其子包)

否则我们自定义的这个规则类会被所有的 Ribbon 客户端共享,达不到特殊定制化的目的。

下面我们来操作:

在已有的order80服务中新建一个package,(即服务提供者)

目录结构如下

package com.xn2001.myrule;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * Created by 乐心湖 on 2020/5/2 22:14
 */
@Configuration
public class MyselfRule {
    @Bean
    public IRule myRule(){
        // 定义为随机
        return new RandomRule();
    }
}

在主启动类添加注解

@RibbonClient(name = "CLOUD-PAYMENT-SERVICE",configuration = MyselfRule.class)

注意:name填写的是application.yml中配置的spring.application.name的大写形式。

测试,访问查看调用消费者是否已经随机而不是轮询。

在之前轮询的情况下端口是8001与8002交替出现,而负载均衡规则变为随机后,端口是随机出现的

负载均衡算法

负载均衡算法:rest 接口第几次请求数 % 服务器集群总数量 = 时机调用服务器位置下标,每次服务重启后rest 接口技术求从1开始。

List<ServiceInstance> instances = discoverClient.getInstances("CLOUD-PROVIDER-SERVICE");

如: List[0] instances = 127.0.0.1:8002

      List[1] instances = 127.0.0.1:8001

8001 + 8002 组合为集群,他们共计2台服务器,集群总数为2 , 按照轮询算法原理:

当请求总数为1 时:1%2 = 1, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8001 当请求总数为2 时:2%2 = 0, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8002 当请求总数为3 时:2%2 = 1, 对应下标位置为1, 则获得服务地址为 127.0.0.1:8001

例如我们现在有两台机子去负载均衡

请求次数

计算公式

取得下标

1

1%2=1

对应127.0.0.1:8001

2

2%2=0

对应127.0.0.1:8002

3

3%2=1

对应127.0.0.1:8001

手写负载均衡算法

首先你需要对CAS和自旋锁有一定的了解

下文仅仅是对过程的大致描述,不是实际的演示过程

在服务提供者中的的controller添加一个方法,这里我们直接返回是端口号serverPort

@GetMapping("/payment/lb")
public String getPaymentLb(){
    return serverPort;
}

将restTemplate配置类中的@LoadBalanced注解删除

开始撸自己的算法

先建一个lib包,这里需要放到SpringBoot启动类下可以让Spring扫描到的包下,然后写一个接口

package com.xn2001.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;

import java.util.List;

/**
 * Created by 乐心湖 on 2020/5/7 14:55
 */
public interface LoadBalancer {
    ServiceInstance instances(List<ServiceInstance> serviceInstances);
}
package com.xn2001.springcloud.lb;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Created by 乐心湖 on 2020/5/7 14:54
 */
@Component
public class MyLB implements LoadBalancer{

    private AtomicInteger atomicInteger = new AtomicInteger(0);

    public final int getAndIncrement(){
        int current;
        int next;
        do {
            current = this.atomicInteger.get();
            next = current >= 2147483647 ? 0 : current+1;
        }while (!this.atomicInteger.compareAndSet(current,next));

        System.out.println("第几次访问"+next);
        return next;
    }

    @Override
    public ServiceInstance instances(List<ServiceInstance> serviceInstances) {
        int index = getAndIncrement() % serviceInstances.size();
        return serviceInstances.get(index);
    }
}

current是初始值,next是访问次数。每次访问都会在自旋锁中把初始值+1,然后使用compareAndSet方法比较并交换。成功就跳出循环,失败则继续进入循环重新获取初始值+1…

这里保证了不用synchronized方法也能在高并发下实现线程安全的增加次数

instances()实现了访问次数%集群数量,使这个值永远不超过集群数量,然后得到这个值作为获取单个实例的下标,根据实例返回实例

在服务消费者中的controller层加入方法

先获取集群中的实例,然后判断是否为空,把获取到的list传给获取负载均衡算法中去,获取到实例地址(也就是分配了哪那一台服务器),restTemplate去调用服务。

@GetMapping("/consumer/payment/lb")
public String GetPaymentLB(){
    List<ServiceInstance> instances = discoveryClient.getInstances("CLOUD-PAYMENT-SERVICE");
    if (instances == null || instances.size() <= 0){
        return null;
    }
    ServiceInstance serviceInstance = loadBalancer.instances(instances);
    URI uri = serviceInstance.getUri();
    return restTemplate.getForObject(uri+"/payment/lb",String.class);
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java获取电脑真实的IP地址(排除虚拟机等干扰)

    参考资料:https://blog.csdn.net/yinshuomail/article/details/81624648

    乐心湖
  • Ubuntu“无法获得锁”解决方案(E: 无法获得锁 /var/cache/apt/archive)

    [scode type="yellow"]Ubuntu “无法获得锁”解决方案(E: 无法获得锁 /var/cache/apt/archive)[/scode]

    乐心湖
  • 实现多级分类嵌套数据的展示

    我新建了一个 LevelCatalogVo 在 LevelCatalog 原有的基础上加上了 List<LevelCatalogVo> 属性

    乐心湖
  • 在编程中处理adb命令—App自动化测试与框架实战(10)

    顾翔老师开发的bugreport2script开源了,希望大家多提建议。文件在https://github.com/xianggu625/bug2testscr...

    小老鼠
  • 前阿里P10大神AI创业,主打决策智能,从《星际争霸II》开始

    在北京大学第42届ACM-ICPC国际大学生程序设计竞赛全球总决赛现场,一款基于《星际争霸II》的AI人机协作挑战赛也在同期进行,主办方启元世界,一家主打决策智...

    量子位
  • java中返回任意类型值( <V> V get(Object obj))

    今天给大家介绍一下java中是如何实现返回值为任何类型,而且不需要强制类型转换就可以直接使用。 在一般情况下返回类型要么是范型,要么就是引用类型、基础类型之类的...

    林老师带你学编程
  • iOS开发中 JSON 和 Model 转换 以及泛形的写法

    现在iOS的开发语言 有 OC 和 Swift Swift 本来就支持泛形 OC 从 XCode7 后也支持泛形了

    剑行者
  • 算法篇:位运算基本操作

    https://leetcode-cn.com/problems/number-of-1-bits/

    灰子学技术
  • 哈夫曼树【最优二叉树】【Huffman】

            在很多问题的处理过程中,需要进行大量的条件判断,这些判断结构的设计直接影响着程序的执行效率。例如,编制一个程序,将百分制转换成五个等级输出。大家...

    瑾诺学长
  • JavaWeb——JSP入门学习(JSP基本概念、JSP脚本、JSP内置对象)

    本章内容只对JSP内容做入门介绍,是为了会话技术的Cookie和Session内容的承接,后续再写文章详细介绍JSP。

    Winter_world

扫码关注云+社区

领取腾讯云代金券