【Ribbon路由规则器】服务筛选,过滤服务基础组件AbstractServerPredicate

2023-11-14

前言

Ribbon在进行Server过滤的时候,用到了一个重要的基础组件【AbstractServerPredicate】,它的作用就是在众多Server的列表中通过一定的过滤策略踢除不合格的Server,留下来合格的Server列表。

负载均衡策略的核心之一就是对已知的服务列表进行过滤,留下一堆合格的Server进而按照一定规则进行选择

源码解读

PredicateKey

它是一个不可变对象,代表一个断言key。用于断言【AbstractServerPredicate】的入参,也就是public boolean apply(@Nullable PredicateKey input) {}方法的参数,该方法在后面会有具体的实例展示。源码如下:

package com.netflix.loadbalancer;

public class PredicateKey {
    private Object loadBalancerKey;
    private Server server;

    public PredicateKey(Object loadBalancerKey, Server server) {
        this.loadBalancerKey = loadBalancerKey;
        this.server = server;
    }

    public PredicateKey(Server server) {
        this((Object)null, server);
    }

    public final Object getLoadBalancerKey() {
        return this.loadBalancerKey;
    }

    public final Server getServer() {
        return this.server;
    }
}

上述源码中有两个属性,【loadBalancerKey】与【Server】。

Server】表示服务实例;

loadBalancerKey】则用于一个叫【IRule】的接口下的choose方法,即为key,其中【IRule】代表负载均衡策略。其源码如下:

package com.netflix.loadbalancer;

public interface IRule {
    Server choose(Object var1);

    void setLoadBalancer(ILoadBalancer var1);

    ILoadBalancer getLoadBalancer();
}

Ribbon是一个为客户端提供负载均衡功能的服务,它内部提供了一个叫做ILoadBalance的接口代表负载均衡器的操作,比如有添加服务器操作、选择服务器操作、获取所有的服务器列表、获取可用的服务器列表等等。顾名思义,loadBalancerKey相当于负载均衡器的key。其他的在此不做延申。

AbstractServerPredicate

它是服务器过滤逻辑的基础组件,可用于rules and server list filters。它传入的是一个【PredicateKey】,含有一个【Server】和【loadBalancerKey】,由此可以通过服务器和负载均衡器来开发过滤服务器的逻辑。

该类的成员属性源码如下

public abstract class AbstractServerPredicate implements Predicate<PredicateKey> {

    // 负载均衡器LoadBalancer规则:能从其获取到ILoadBalancer,从而得到一个对应的LoadBalancerStats实例
    protected IRule rule;
    // LoadBalancer状态信息。可以通过构造器指定/set方法指定,若没有指定的话将会从IRule里拿
    private volatile LoadBalancerStats lbStats;
    // 随机数。当过滤后还剩多台Server将从中随机获取
    private final Random random = new Random();
    // 下一个角标。用于轮询算法的指示
    private final AtomicInteger nextIndex = new AtomicInteger();
    // 一个特殊的Predicate:只有Server参数并无loadBalancerKey参数的PredicateKey,最终也是使用AbstractServerPredicate完成断言
    private final Predicate<Server> serverOnlyPredicate;
    
    public Predicate<Server> getServerOnlyPredicate() {
        return this.serverOnlyPredicate;
    }
}

该抽象类提供了三个静态工具方法,用于快速生成一个AbstractServerPredicate实例

该类的静态工具方法源码如下:

    public static AbstractServerPredicate alwaysTrue() {
        return new AbstractServerPredicate() {
            public boolean apply(@Nullable PredicateKey input) {
                return true;
            }
        };
    }

    public static AbstractServerPredicate ofKeyPredicate(final Predicate<PredicateKey> p) {
        return new AbstractServerPredicate() {
            @SuppressWarnings({"NP"})
            public boolean apply(PredicateKey input) {
                return p.apply(input);
            }
        };
    }

    public static AbstractServerPredicate ofServerPredicate(final Predicate<Server> p) {
        return new AbstractServerPredicate() {
            @SuppressWarnings({"NP"})
            public boolean apply(PredicateKey input) {
                return p.apply(input.getServer());
            }
        };
    }

该类的成员方法源码如下:

// 得到负载均衡器对应的LoadBalancerStats实例
// 该方法为protected,在子类中会被调用用于判断
protected LoadBalancerStats getLBStats() {
    if (this.lbStats != null) {
        return this.lbStats;
    } else if (this.rule != null) {
        //从rule里面拿到ILoadBalancer,进而拿到LoadBalancerStats
        ILoadBalancer lb = this.rule.getLoadBalancer();
        if (lb instanceof AbstractLoadBalancer) {
            LoadBalancerStats stats = ((AbstractLoadBalancer)lb).getLoadBalancerStats();
            this.setLoadBalancerStats(stats);
            return stats;
        } else {
            return null;
        }
     } else {
            return null;
     }
}

// Eligible:适合的
// 把servers通过Predicate#apply(PredicateKey)删选一把后,返回符合条件的Server们
// loadBalancerKey非必须的。
public List<Server> getEligibleServers(List<Server> servers) {
    return this.getEligibleServers(servers, (Object)null);
}

public List<Server> getEligibleServers(List<Server> servers, Object loadBalancerKey) {
    if (loadBalancerKey == null) {
        return ImmutableList.copyOf(Iterables.filter(servers, this.getServerOnlyPredicate()));
    } else {
        List<Server> results = Lists.newArrayList();
        Iterator var4 = servers.iterator();

        //遍历服务清单,使用apply方法来判断实例是否需要保留,如果是,就添加到结果列表中
        //所以apply方法需要在子类中实现,子类就可实现高级策略
        while(var4.hasNext()) {
            Server server = (Server)var4.next();
            if (this.apply(new PredicateKey(loadBalancerKey, server))) {
                results.add(server);
            }
        }

        return results;
     }
}

getEligibleServers方法内部调用断言方法Predicate#apply(PredicateKey)完成Server的过滤,它属于AbstractServerPredicate的核心,因为【apply】方法在此处是唯一调用处,因此该方法重要。另外,需要注意的是apply方法(具体的过滤逻辑)在本抽象类是没有提供实现的,全在子类身上

应用实例

过滤服务:AbstractDiscoveryEnabledPredicate类

import com.netflix.loadbalancer.AbstractServerPredicate;
import com.netflix.loadbalancer.PredicateKey;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;

/**
 * 过滤服务
 *
 */
public abstract class AbstractDiscoveryEnabledPredicate extends AbstractServerPredicate {

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean apply(@Nullable PredicateKey input) {
		return input != null
				&& input.getServer() instanceof NacosServer
				&& apply((NacosServer) input.getServer(), (HttpHeaders) input.getLoadBalancerKey());
	}

	/**
	 * Returns whether the specific {@link NacosServer} matches this predicate.
	 *
	 * @param server  the discovered server
	 * @param headers 请求头
	 * @return whether the server matches the predicate
	 */
	abstract boolean apply(NacosServer server, HttpHeaders headers);
}

服务筛选:GrayMetadataAwarePredicate类

import cn.hutool.core.util.StrUtil;
import com.medusa.gruul.common.core.constant.CommonConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.alibaba.nacos.ribbon.NacosServer;
import org.springframework.http.HttpHeaders;

import java.util.Map;

/**
 * 基于 Metadata version 的服务筛选
 *
 */
@Slf4j
public class GrayMetadataAwarePredicate extends AbstractDiscoveryEnabledPredicate {

    @Override
    protected boolean apply(NacosServer server, HttpHeaders headers) {

        final Map<String, String> metadata = server.getMetadata();
        String version = metadata.get(CommonConstants.VERSION);
        // 判断Nacos服务是否有版本标签
        if (StrUtil.isBlank(version)) {
            log.trace("nacos未配置version字段,GrayMetadataAwarePredicate将被跳过");
            return true;
        }

        // 判断请求中是否有版本
        String target = headers.getFirst(CommonConstants.VERSION);
        if (StrUtil.isBlank(target)) {
            log.trace("请求头中未配置version字段,GrayMetadataAwarePredicate将被跳过");
            return true;
        }

        log.info("请求版本:{} ,当前服务版本:{}", target, version);
        return target.equals(version);
    }

}

参考资料:

Ribbon服务器过滤逻辑的基础组件:AbstractServerPredicate

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Ribbon路由规则器】服务筛选,过滤服务基础组件AbstractServerPredicate 的相关文章

  • 什么是CSRF攻击,以及如何防御

    什么是CSRF攻击 以及如何防御 1 CSRF攻击的概念 2 CSRF攻击简单案例 2 1 银行网站项目 2 2 危险网站的项目 2 3 测试 3 默认的CSRF防御策略 4前后端分离的CSRF防御策略 1 CSRF攻击的概念 1 CSRF
  • MPI群通信与矩阵乘法的Fox算法实现

    原本以为 MPI天生只能在Linux上运行 但这次却发现了Intel MPI Library 这个好用的东西 基本不需要设置 安上之后 用自己能登录windows的帐号和密码注册就行了 虽然不是局域网上的机器 但也可以让我的双核CPU达到1
  • WebSocket协议之NGINX代理转发无法建立连接问题处理

    WebScoket协议如需要通过nginx代理 需要location 节点增加以下节点即可正常建立连接 需要配置以下节点 proxy http version 1 1 proxy set header Upgrade http upgrad
  • Python入门网络爬虫之精华版,赶快收藏

    相关文件 关注小编 私信小编领取哟 当然别忘了一件三连哟 公众号 Python日志 前言 Python学习网络爬虫主要分3个大的版块 抓取 分析 存储 另外 比较常用的爬虫框架Scrapy 这里最后也详细介绍一下 举例子 当我们在浏览器中输
  • STL 中集合操作相关算法

    merge 头文件 merge 算法定义在头文件 include 中 算法作用 merge 算法是合并两个有序的序列 合并结果拷贝到一个新的序列 前提是这两个序列的排序规则一样 代码示例 vector

随机推荐

  • vue---UI框架elementUI实现系统登录注册页

    https blog csdn net maidu xbd article details 87943243已经搭建好了vue开发环境 在本博客中 来介绍些结合element ui实现登录注册界面 界面效果展示如下图 实现的功能包括 首先安
  • 【数据结构】红黑树模拟实现

    一 红黑树底层原理 红黑树的底层可以看作是AVL树的变种 先前我们了解过AVL的模拟实现 avl对整棵树的控制还是非常严格的 因为高度差不能大于2 导致会经常发生旋转 旋转这个过程也会降低效率 所以为了整体的效率衍生出了红黑树 红黑树旋转的
  • 稳压二极管工作原理、重要参数意义和典型电路参数计算

    稳压二极管的工作原理 稳压二极管也叫稳压管 它在电路中一般起到稳定电压的作用 也可以为电路提供基准电压值 稳压二极管使用特殊工艺制造 这种工艺使它在反向击穿时仍然可以长时间稳定工作 不损坏 而工作在反向击穿状态的稳压管只要工作电流保持在一定
  • 电感磁芯公式

    NBA LI
  • [机缘参悟-89]:《本质思考》- 本质思考的7种习惯

    目录 一 精准性思考 精确 表面词语要精确 二 非歧义思考 深度 明确表面词语背后的动机 三 多维度思考 广度 全方面思考 四 反馈式思考 确认 反复确认 五 适应性思考 变化 因环境变化而变化 六 循环式思考 持续改进 逐渐得到问题的本质
  • linux more 下一页_Linux more命令如何使用?

    Linux下的more命令主要用于分屏显示 即内容超过一屏的文件 与cat命令有点区别 下面小编就给大家详细介绍下more命令 有兴趣的话不妨来了解下吧 more会以一页一页的显示方便使用者逐页阅读 而最基本的指令就是按空白键 space
  • git:分支合并

    1 git 分支的合并 merge 假设我们此时需要修复dev分支上的某个bug 此时在dev分支上创建修复分支fix 然后推进fix分支 当前的git仓库如图 注 为了方便演示 dev分支上只有一个test cpp源文件 然后我们在fix
  • 利用Visio绘制数据流图

    http blog sina com cn s blog a3059cda01011meg html 利用Visio 2007来绘制网上书店系统的数据流图 利用Visio 2007创建Gane Sarson数据流图 可以选择 软件和数据库
  • 【满分】【华为OD机试真题2023 JS】简单的自动曝光

    华为OD机试真题 2023年度机试题库全覆盖 刷题指南点这里 简单的自动曝光 时间限制 1s 空间限制 256MB 限定语言 不限 题目描述 一个图像有n个像素点 存储在一个长度为n的数组img里 每个像素点的取值范围 0 255 的正整数
  • 使用OpenCV库实现的模板轮廓匹配定位功能块

    c include
  • 批处理替换修改文件名

    echo off echo echo title 批量替换文件名中的部分字符串 color 3f echo Note echo 本批处理可批量替换本文件所在文件夹下的所有文件名的相同字符 echo echo echo echo echo e
  • CentOS 8 通过二进制安装 MySQL

    需求 CentOS8下采用二进制安装包的形式安装MySQL 并且指定数据库文件存放的路径地址 步骤如下 在 MySQL下载地址 中下载 MySQL 二进制安装包 注意 在版本选择的时候 版本号在8 0 11及以下包后缀都是 tar gz 但
  • Python中from from __future__ import *的用法

    from future import 参考 https blog csdn net zzc15806 article details 81133045 我们在读代码的时候 总是会看到代码开头会加上from future import 这样的
  • NoClassDefFoundError/ClassNotFoundException 到底从哪引用到了这个类?排查思路

    1 背景 公司内网登录改造升级 使用方需要配合升级 jar 包 本以为很简单的事情 升级版本上线就 OK 了 没想到升级头一个服务 部署到测试环境就有问题 2 表象 访问所有页面报 404 3 排查思路 3 1 排除法 确定是不是升级 ja
  • cmd简单游戏代码_制作一个猜数字的游戏

    十一节假日 我在敲代码 外甥女突然问我 舅舅 你能不能给我编个游戏啊 看着外甥女期盼的眼神 我当然不好拒绝啊 而且如果写一点代码 能让小朋友对编程有个简单的了解 甚至激发她对编程学习的兴趣 那也是极好的啊 话不多说 我立马敲一个猜数字的文字
  • api-ms-win-core-path-l1-1-0.dll丢失怎么解决?

    api ms win core path l1 1 0 dll文件可以帮助用户快速的启动一些相关的应用程序 让应用程序可以正常的使用 但是近期有用户在电脑的使用中 遇到了系统提示提示 api ms win core path l1 1 0
  • Mysql的分布式(XA)真面目

    Mysql XA 一 XA是什么 二 MySQL中XA实现 1 内部XA事务 两阶段提交PC 2 外部XA事务 总结 一 XA是什么 XA 协议本就是为一个分布式事务协议 它规定了 XA PREPARE XA COMMIT XA ROLLB
  • [React] markdown以及markdown-navbar实现方案

    React markdown以及markdown navbar实现方案 1 前言 心血来潮 想在自己的项目中实现 Markdown 文件的渲染 以下是我当前的实现方式以及遇到的一些问题的记录 本人水平很拉 有更好的方法欢迎在下面讨论 2 m
  • C++ Primer阅读笔记--万能引用和引用折叠

    目录 1 万能引用 1 1 万能引用的实现 1 2 万能引用与右值引用的区别 2 引用折叠 1 万能引用 1 1 万能引用的实现 万能引用可以向其传递任何类型的参数 其会自动进行参数类型的推断 万能引用的两种实现如下 基于模板实现 temp
  • 【Ribbon路由规则器】服务筛选,过滤服务基础组件AbstractServerPredicate

    前言 Ribbon在进行Server过滤的时候 用到了一个重要的基础组件 AbstractServerPredicate 它的作用就是在众多Server的列表中通过一定的过滤策略踢除不合格的Server 留下来合格的Server列表 负载均