流量路由技术解析

news2025/1/21 20:25:33

作者:十眠

流量路由,顾名思义就是将具有某些属性特征的流量,路由到指定的目标。流量路由是流量治理中重要的一环,本节内容将会介绍流量路由常见的场景、流量路由技术的原理以及实现。

流量路由的业务场景

我们可以基于流量路由标准来实现各种业务场景,如标签路由、金丝雀发布、同机房优先路由等。

  • 标签路由

标签路由是按照标签为维度对目标负载进行划分,符合条件的流量匹配至对应的目标,从而实现标签路由的能力。当然基于标签路由的能力,赋予标签各种含义我们就可以实现各种流量路由的场景化能力。

在这里插入图片描述

  • 金丝雀发布

金丝雀发布是一种降低在生产中引入新软件版本的风险的技术,方法是在将更改推广到整个基础架构并使其可供所有人使用之前,缓慢地将更改推广到一小部分用户。金丝雀发布是一种在黑与白之间,能够平滑过渡的一种发布方式。让一部分用户继续用旧版本,一部分用户开始用新版本,如果用户对新版本没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到新版本上面来。一直都有听说,安全生产三板斧的概念:可灰度、可观测、可回滚。那么灰度发布能力就是帮助企业软件做到快速迭代验证的必备能力。在K8s中金丝雀发布的最佳实践如下:第一步:新建灰度 Deployment,部署新版本的镜像,打上新版本的标签。第二步:配置针对新版本的标签路由规则。第三步:验证成功,扩大灰度比例。第四步:若验证成功,将稳定版本的应用更新成最新镜像;若验证失败,把灰度的 Deployment 副本数调整到 0 或删除该 Deployment。

  • 全链路灰度

当企业的发展,微服务的数量会逐渐增多。在有一定规模的一定数量的微服务情况下,一次发版可能涉及到的服务数量会比较多,微服务链路也相当较长。全链路灰度可以保证特定的灰度流量可以路由到所有涉及到的灰度版本中。

在这里插入图片描述

  • 同可用区优先路由

当企业的对稳定性的要求变高时,企业的应用会选择部署在多个可用区中提高应用的可用性,避免某个可用区出现问题后导致影响应用的可用性。当应用在不同的可用区部署时,应用间跨可用区调用可能会被因为远距离调用造成的网络延迟影响,同可用区优先路由会让我们的Consumer应用优先调用当前可用区内的Provider应用,可以很好地减少这种远距离调用造成的影响,同时当某个可用区出现问题后,我们只需在流量入口处将当前可用区的流量隔离掉,其他可用区的流量不会访问至当前可用区的节点,可以很好地控制某个可用区出现问题后的影响面。

在这里插入图片描述

流量路由能力实现的场景众多,上面只是列举了一些典型的场景,下面我们将从流量路由原理入手,剖析流量路由的实现与技术细节。

流量路由原理

需要实现上述所提的流量路由的场景,那么对于Consumer应用来说,同一个 Provider 应用的不同节点之间是有一些特殊的标识。金丝雀发布场景来说,新版本代码所部署的节点需要被标上成新版本的标识;同机房优先路由来说,Provider节点要被标识上机房的信息;全链路灰度场景来说,灰度环境的节点需要被带上灰度标。因此,我们需要在Provider服务注册的过程中,就在注册到注册中心的地址信息中带上治理场景所需的标识。

  • 节点打标

首先介绍一下节点打标的能力,我们先看看 Apache Dubbo 的设计,其中 Dubbo 服务节点的地址信息使用 URL 模型来承载。

class URL implements Serializable {
    protected String protocol;
    // by default, host to registry
    protected String host;
    // by default, port to registry
    protected int port;
    protected String path;
    private final Map<String, String> parameters;
}

举个简单的例子,假如 Consumer 收到这样一条 dubbo://10.29.0.102:20880/GreetingService?tag=gray&az=az_1 地址信息,表示 GreetingService 服务使用的是 dubbo 协议,服务绑定的 ip 与 port 分别为 10.29.0.102 跟 20880,该地址携带上了 tag=gray、az=az_1 这样两条元数据信息,分别表示当前节点的标签为灰度,当前节点所处的可用区(az:Availability Zone 为云上的机房的可用区概念)为 az_1 。那么节点打标的能力其实就比较明确了,我们在服务提供者向注册中心注册服务地址之前,我们在当前服务提供者的地址信息上增加需要增加的元数据信息比如 verion = gray,比如在 Apache Dubbo 的 URL 中增加 paramters 信息,一般来说元数据信息都是 k-v 的 map 结构,这样框架向注册中心注册该节点时会为其添加需要的标签信息verison=gray

相似的, Spring Cloud 中通过表示服务节点信息的抽象

public class Server {
   public static interface MetaInfo {
        ...
    }
    private String host;
    private int port = 80;
    ...
}

Sentinel2.0 希望作为流量治理能力的实现,考虑到会被较多框架即成,因此需要考虑到各个框架的通用点以及本身设计的易用性,Sentinel2.0 中使用 Instance 模型表示服务节点信息的抽象,并且在其中保留了原有类型的引用。

public class Instance {
  private String host;
  private Integer port;
  private Map<String, String> metadata;
  private Object targetInstance;
}

其中 metadata 用来存储用于服务治理的元数据,比如AZ标、版本标签等等。

  • 流量路由

到目前为止,我们算是搞明白了 Consumer 收到的 Provider 的地址列表长什么样子。假设 Consumer 收到了 如下图所示 GreetingService 服务的6条地址,那么我们该如何进行选择呢?

在这里插入图片描述

算是进入到正题,我们看一下 Sentinel2.0 是如何实现流量路由能力的。

目前我们在 Sentinel2.0 中分别抽象了InstanceManager、RouterFilter 以及 LoadBalancer 三个对象,并通过 ClusterManager 将它们管理起来。其中 InstanceManager 将地址列表按需进行存储与管理,RouterFilter做为流量路由能力实现的主体,LoadBalancer做为负载均衡能力实现的主体。

在这里插入图片描述

Dubbo 在收到注册中心同步过来的 Provider URL 之后会生成对应的 Invoker ,Invoker 列表我们可以理解为就是可以调用的 Provider 节点列表的抽象。流量路由则是需要将传入的 Invoker 列表按照路由规则进行路由筛选,筛选出符合路由规则的服务提供者,即符合路由规则的 Invoker 列表。我们如何可以通过 Sentinel2.0 的抽象来实现流量路由的能力呢?当地址通知下来后,我们需要通过 instanceManager#storeInstances 将地址列表进行缓存。

@Override
public void notify(BitList<Invoker<T>> invokers) {
    super.notify(invokers);
    instanceManager.storeInstances(invokersToInstances(invokers));
}

在流量路由处,我们则调用 clusterManager#route 实现地址路由。

@Override
protected BitList<Invoker<T>> doRoute(BitList<Invoker<T>> invokers, URL url, Invocation invocation, boolean needToPrintMessage, Holder<RouterSnapshotNode<T>> routerSnapshotNodeHolder, Holder<String> messageHolder) throws RpcException {
    TrafficContext trafficContext = getTrafficContext(invocation);
    List<Instance> instances = clusterManager.route(trafficContext);
    return instancesToInvokers(instances);
}

其中 ClusterManager 会将路由执行的逻辑交给 RouterFiler.route 进行执行。

public List<Instance> route(TrafficContext context) {
    List<Instance> instances = instanceManager.getInstances();
    for (RouterFilter routerFilter : routerFilterList) {
        instances = routerFilter.filter(instances, context);
    }
    return instances;
}

每个 RouterFilter 服务路由都可以包含一条路由规则,路由规则决定了服务消费者的调用目标,即规定了服务消费者可调用哪些服务提供者;一次微服务调用的地址列表可以由多个 RouterFilter 服务路由共同影响,比如我们希望当前的 Consumer 流量访问到在同时符合灰度发布以及同可用区优先调用路由规则的节点上。我们可以按照需求增加路由链中的 RouterFilter,并且路由链的 Route 方法是循环调用每个 RouterFilter 的 Route 方法。并且上一个 Router 的输出 Invoker 列表会做为下一个 Router 的输入。介绍到这里,大家可能对下图会有一个更加深刻的理解了。

在这里插入图片描述

路由的整体模型大家已经理解了,我们来重点看一下具体的 RouterFilter 服务路由是如何实现的。

public interface RouterFilter {
  List<Instance> filter(List<Instance> instanceList, TrafficContext context) throws TrafficException;
}

RouterFilter 的 Route 方法会在每次请求调用时被执行,Route 方法有关键的两个入参 InstanceList 跟 TrafficContext,instanceList 是可调用的服务提供者节点列表的抽象。TrafficContext 是当前调用流量的请求上下文的抽象,我们可以从中读到请求中携带着的 RouterFilter 所关心的一些元数据(比如当前请求的AZ信息、请求参数中指定 key 的值等内容)。Route 方法会在每次调用时候根据请求中的上下文信息结合路由规则计算出当前请求需要匹配的目标节点特征,并遍历当前的地址列表,根据目标节点特征进行地址过滤。筛选出目标节点的地址列表,是输入地址列表的子集,然后传递给下一个 RouterFilter。

RouterFilter 的 Route 方法逻辑的伪代码如下:

@Override
public List<Instance> filter(List<Instance> instanceList, TrafficContext context) throws TrafficException {
    List<Instance> targetInstances = new ArrayList<>();
    for (Instance instance : instanceList) {
        if (trafficRouteMatch(instance, context)) {
            targetInstances.add(instance);
        }
    }
    return targetInstances;
}

instanceList 为输入地址列表,targetInstances 为输出地址列表即当前 Router 服务路由的结果。

Sentinel2.0流量路由规划

在这里插入图片描述

Sentinel2.0 将基于 OpenSergo 流量路由规则实现基本的流量路由能力,支持多种流量路由策略、负载均衡策略、虚拟工作负载等。Sentinel2.0 期望支持 Http、RPC、SQL等微服务各种流量的路由能力,并且可以快速被各主流微服务框架所集成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/151742.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

aws sam 本地测试部署 lambda 和 apigateway

使用sam框架可以在部署serverless应用之前&#xff0c;在本地调试application是否符合预期 sam框架安装 serverless应用是lambda函数&#xff0c;事件源和其他资源的组合 使用sam能够基于docker容器在本地测试lambda函数 安装sam wget https://github.com/aws/aws-sam-cli…

ArcGIS基础实验操作100例--实验77按要素分区统计路网

本实验专栏参考自汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 高级编辑篇--实验77 按要素分区统计路网 目录 一、实验背景 二、实验数据 三、实验步骤 &#xff08;…

ART-SLAM: Accurate Real-Time 6DoF LiDAR SLAM

IEEE Robotics and Automation Letters 意大利米兰理工学院 Abstract 地面车辆实时六自由度姿态估计&#xff0c;由于自动驾驶和三维建图等诸多应用&#xff0c;是机器人技术中一个相关和被研究广泛的课题。虽然有些系统已经存在&#xff0c;但它们要么不够准确&#xff0c;要…

Qt之标准对话框(QMessageBox、QFileDialog)

文章目录前言如何学习标准对话框QMessageBox消息对话框应用属性实操QFileDialog文件对话框应用属性实操前言 Qt为开发者提供了一些可复用的对话框&#xff0c;他对我们的开发是很重要的。下面我们就来学习 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考…

无监控,不运维!深入浅出介绍ChengYing监控设计和使用

监控系统俗称「第三只眼」&#xff0c;几乎是我们每天都会打交道的系统&#xff0c;它也一直是IT系统中的核心组成部分&#xff0c;负责问题的发现以及辅助性的定位。 ChengYing作为一站式全自动化全生命周期大数据平台运维管家&#xff0c;自然也提供大数据产品的监控服务。这…

力扣sql基础篇(二)

力扣sql基础篇(二) 1 每月交易I 1.1 题目内容 1.1.1 基本题目信息 1.1.2 示例输入输出 1.2 示例sql语句 # sum函数如果需要筛选,可以考虑在里面嵌套if函数 SELECT DATE_FORMAT(trans_date,"%Y-%m") month,country,count(*) trans_count,COUNT(IF(state"appr…

matlab利用逻辑数组将保密率负数部分转换为零

通信中计算保密率的公式为 r[Rd−Re]r[R_d-R_e]^ r[Rd​−Re​] 其中RdR_dRd​代表合法目的地的数据速率&#xff0c;ReR_eRe​代表窃听节点的数据速率 当窃听节点的速率大于目的节点的速率时候&#xff0c;计算出来的保密率是负值&#xff0c;这在设计的时候可以将这时候的保…

referer、prototype、array、json笔记整理

目录referer、prototype、array、json笔记整理refererReferrer-policy如何设置referer绕过图片防盗链1、利用https网站盗链http资源网站&#xff0c;refer不会发送2、设置meta3、设置referrerpolicy"no-referrer"4、利用iframe伪造请求referer5、客户端在请求时修改h…

【LeetCode每日一题】——233.数字 1 的个数

文章目录一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【解题思路】七【题目提示】八【时间频度】九【代码实现】十【提交结果】一【题目类别】 数学 二【题目难度】 困难 三【题目编号】 233.数字 1 的个数 四【题目描述】 给定一个整数 …

为你的Typecho使用Redis缓存,优化访问速度-织音博客

前言Typecho虽然轻量&#xff0c;但终究仍是PHP动态脚本&#xff0c;访问时需要频繁调取数据库的信息&#xff0c;导致并发值一高&#xff0c;CPU就100%占用&#xff0c;无法处理新的请求信息。这时&#xff0c;我们可以用Redis来设置缓存&#xff0c;从而不用频繁调动数据库&a…

【Meetup预告】SeaTunnel + OpenMLDB:共筑数据集成生态,加速实时场景落地

2023年1月12日&#xff08;周四&#xff09;20&#xff1a;00-21:30&#xff0c;云原生数据集成平台 SeaTunnel 联合开源机器学习数据库 OpenMLDB 合作带来本期 Meetup。 活动背景 Al 应用的繁荣发展&#xff0c;既得益于数据的爆发式增长&#xff0c;也受困于数据治理的种种…

使用Bokeh进行数据可视化的8个建议(上)

使用 Bokeh 库创建数据可视化的快速提示和示例。 长按关注《Python学研大本营》&#xff0c;加入读者群&#xff0c;分享更多精彩 扫码关注《Python学研大本营》&#xff0c;加入读者群&#xff0c;分享更多精彩 Python 是创建数据可视化的绝佳开源工具。有许多可用的数据可视…

JavaWeb:会话技术之Cookie

1&#xff0c;会话跟踪技术的概述 对于会话跟踪这四个词&#xff0c;我们需要拆开来进行解释&#xff0c;首先要理解什么是会话&#xff0c;然后再去理解什么是会话跟踪&#xff1a; 会话&#xff1a;用户打开浏览器&#xff0c;访问web服务器的资源&#xff0c;会话建立&…

设计模式-到底什么是builder模式

我们来看一个一些常见的开源代码中带builder字样的经典类&#xff1a;&#xff08;jdk&#xff09;Stringbuilder&#xff08;spring&#xff09;springApplicationBuilder&#xff08;es&#xff09;xxxQuerybulider如果只去看这些类的话&#xff0c;应该是一团乱码&#xff0…

【Kotlin】字符串操作 ① ( 截取字符串函数 substring | 拆分字符串函数 split | 解构语法特性 )

文章目录一、截取字符串函数 substring二、拆分字符串函数 split一、截取字符串函数 substring Kotlin 中提供了 截取字符串函数 substring , 可接收 IntRange 类型的参数 , 这是 整数范围 类型 ; 截取字符串函数 substring 函数原型为 : /*** 返回由给定的[range]索引指定的…

【pat】网红点打卡攻略【图】

一个旅游景点&#xff0c;如果被带火了的话&#xff0c;就被称为“网红点”。大家来网红点游玩&#xff0c;俗称“打卡”。在各个网红点打卡的快&#xff08;省&#xff09;乐&#xff08;钱&#xff09;方法称为“攻略”。你的任务就是从一大堆攻略中&#xff0c;找出那个能在…

【MyBatis】第一篇:初体验

还是老规矩看一下百度百科中的解释&#xff1a; MyBatis 是一款优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来配置和映射原生信息&#xff0c…

Web(三)

JavaScript基础概念&#xff1a;一门客户端脚本语言* 运行在客户端浏览器中的。每一个浏览器都有JavaScript的解析引擎* 脚本语言&#xff1a;不需要编译&#xff0c;直接就可以被浏览器解析执行了功能&#xff1a;* 可以来增强用户和html页面的交互过程&#xff0c;可以来控制…

蓝桥杯C51

#include "reg52.h"sfr AUXR 0x8e; //定义辅助寄存器sbit S5 P3^2; //定义按键S5引脚 sbit S4 P3^3; //定义按键S4引脚unsigned char count 0; //定义中断计数器 unsigned char t_h 0; //定义运行时间的变量 unsigned char t_m 0; …

Struts2之OGNL表达式

Struts2之OGNL表达式1、什么是OGNL表达式2、OGNL表达式的作用3、值栈与OGNL3.1、值栈3.2、OGNL访问值栈4、类型转换4.1、类型转换的意义4.2、内置的类型转换器4.3、自定义类型转换器4.3.1、创建日期转换器4.3.2、配置转换器4.3.3、页面4.3.4、实体类和Action控制器4.3.5、strut…