流量管理

动态路由

通常一个服务包含多个实例。在简单场景下,每个实例是对等的,通过负载均衡组件访问任意一个即可。

但是,在绝大部分场景下,每个实例具有逻辑属性和物理属性:

  • 逻辑属性:版本、协议、业务Set、特性环境等。北极星允许用户为每个实例设置自定义标签
  • 物理属性:地理位置。比如实例所属的地域-城市-园区的位置信息。

对于某个服务的全部实例,可以根据逻辑和物理属性将其划分成为多个分组或者集群,如下图所示:

服务主调方/消费者发送请求,客户端根据请求和主调方节点属性,将不同节点的不同请求路由到不同实例分组或者集群。

串联式路由插件

北极星动态路由组件采用插件化、可配置的方式实现。北极星默认内置以下路由插件:

  • 前置路由插件:默认在插件链的最前面执行,用于剔除隔离和权重为0的实例。
  • 规则路由插件:按照控制台配置的路由规则,根据用户请求参数执行路由规则进行服务实例的过滤。
  • 元数据路由插件:直接根据传入的实例元数据对服务实例进行过滤。
  • 就近路由插件:根据应用自身所属的地域信息,与实例的地域信息进行匹配,筛选出就近的服务实例。
  • 后置路由插件:剔除健康状态异常和故障熔断的实例。如果被剔除的节点数超过一定比例,返回前一个插件的筛选结果,防止因网络分区原因导致的误剔除。

当调用GetOneInstance接口时,会调用路由插件,执行动态路由进行实例筛选,执行流程如下图所示:

插件链中路由插件的执行顺序可以由用户自行编排,同时用户也可以定制自己的路由插件。

负载均衡

从满足本次转发要求的服务实例集中, 通过一定的均衡策略,选取一个实例返回给主调方,供主调方进行服务请求发送。

分类

负载均衡策略一般分为2类:

无状态负载均衡

无状态负载均衡策略,主要特点是每次负载均衡获取到的结果是由具体的负载均衡算法决定。目的是让负载均匀的分发到后端节点。

主要负载均衡策略包括:权重随机,权重轮询等

对于无状态的业务逻辑,为了保证后端节点能够均衡分配请求,此时应该选择权重随机负载均衡策略

有状态负载均衡

有状态负载均衡策略,除了要达到让负载均衡分散到节点的目标以外,还需要实现将同一对象的请求分发到同一个节点。例如业务场景需要将同一个用户的全部请求发送到后端同一个节点处理的情况。

主要负载均衡策略是一致性hash

算法

权重随机

权重随机负载均衡策略,利用区间算法,基于伪随机因子取模的方式选择对应服务实例。

对于有状态的业务逻辑(比如通过用户ID或者请求ID进行hash分区的),为了保证同key请求能够持续命中同一个物理节点,此时应该选择一致性hash负载均衡策略。

权重一致性hash(ringhash算法)

该负载均衡策略基于ketama环算法,每一个服务实例会按照权重分裂成若干个虚拟节点。虚拟节点通过取hash值的方式,映射到长度为2^32的hash环中。

发起查询时,北极星会基于用户传入的hashKey,计算出具体的hash值,然后到环中寻找hash值刚刚好大于传入数据hash值的虚拟节点,并返回其对应的服务实例

权重一致性hash(maglev算法)

该负载均衡策略基于maglev算法(https://static.googleusercontent.com/media/research.google.com/en//pubs/archive/44824.pdf)进行节点分配。

首先为实例集创建一个长度为质数65537的向量表,算法根据节点的权重,将向量表进行填充,直到向量表全部被节点所占满。取节点时则根据用户传值的hashValue取摸的方式,返回对应下标的节点。

算法优点:由于是直接取模寻址,因此算法性能相比ketama环要高(官方数据是在256K个插槽的情况下,性能是5X到10X的差距)。

算法缺点:当节点下线后,导致迁移的节点数量相比ketama环要多(官方数据为迁移节点数量是ketama的两倍)

权重设计

北极星的每个服务实例,都可以设置权重,请求会根据权重,按比例进行分配。权重分为静态权重和动态权重两类:

静态权重

用户可以通过界面配置或者实例注册的方式,调整服务实例的权重,由控制面推送给所有的数据面生效。

动态权重

数据面在运行过程中,定时上报负载数据给控制面,目前支持capacity&used两个指标, 被调方定时(一般2s)上报两个指标的数值到控制面,控制面根据负载信息,调整权重数据。主调方定时拉取最新的权重数据,实时更新以前的静态权重字段,复用老的weightrandom算法。

访问限流

限流能力是高并发系统中,对于服务提供方的一种保护手段。通过限流功能,我们可以通过控制QPS的方式,以避免被瞬时的流量高峰冲垮,从而保障系统的高可用性。

访问限流主要有如下两个应用场景:

  • 过载保护:保护业务不被突发流量打垮
  • 业务防刷:防止恶意用户发送过多流量影响其他正常用户

北极星为被调端服务提供2种类型的访问限流能力:

单机限流:针对单个被调实例的级别的限流,流量限额只针对当前被调实例生效,不共享。

分布式限流:针对服务下所有实例级别的限流,多个服务实例共享同一个全局流量限额。

两种限流模式如何选择?

  • 单机限流:一般适用于保护服务自身不被打垮,按照每个服务集群单机的容量来计算配额。
  • 分布式限流:一般适用于保护第三方服务或者公共服务(比如保护数据库);或者是在网关层进行限流,对通过网关接入的后端服务进行保护。

访问鉴权

访问鉴权包含以下3部分功能:

  • 认证:检验服务调用双方的身份真实性
  • 加密:对服务调用通讯数据进行加密
  • 鉴权:校验请求是否有访问服务接口的权限

访问鉴权可以有效地保护服务调用过程,防止中间人攻击、敏感数据泄露、数据越权访问等问题。

整体架构

Polaris支持使用mTLS来对服务调用进行认证与加密,整体架构如下所示:

  • polaris-security是Polaris的安全组件,在mTLS场景下,它支持作为中间证书签发机构(Intermediate Certificate Authority)使用。
  • Polaris Controller监测到用户服务启用mTLS功能后,会向Pod内自动注入所有启用mTLS功能需要的环境。
  • Polaris xDS Server会给启用mTLS的服务对应的Envoy sidecar下发相应的额外配置。
  • Polaris Sidecar中会额外启动mTLS agent组件,通过Unix Domain Socket通讯向Envoy提供SDS(Secret Discovery Service)能力。
  • mTLS agent组件会自动生成服务使用的身份证书及私钥,并自动进行轮转(rotate)。
  • 每当身份证书接近过期时,mTLS会向polaris-security发送CSR(证书签名请求)来进行更新。

证书签名及轮转原理

启动阶段

  • 用户启用mTLS功能之前,需要先在k8s集群中部署两个secret
  • polaris-security会读取polaris-security-secret,并为自身签发service certificate,用于在TLS握手中自证身份。
  • mTLS agent会读取polaris-sidecar-secret,用于TLS握手中验证polaris-security的身份。

证书签名

  • mTLS agent向polaris-security发起TLS保护的certificate signing request,polaris-security会提供自身的service certiface给mTLS agent验证。
  • 成功后,polaris-security从请求的header中提取出mTLS agent的Service Account Token,并使用Token Review请求的方式发送给Kubernetes API Server进行验证。
  • 验证成功后,正式进入证书签名流程,polaris-security会按CSR中的参数要求,使用CA私钥加密摘要,并将所有材料整合成已签名的证书,连同证书链一起返回给mTLS Agent。
  • mTLS Agent可以使用返回的材料来提供SDS服务,已签名的证书可以用作证明workload的身份;证书链可以用作验证对端workload的身份。

证书轮转

  • mTLS agent的Rotater类会负责证书轮转,它其实就是一个定时任务执行器,每隔一定时间间隔就会执行一次CSR发送任务,并根据返回结果更新SDS材料,请求失败则会自动重试。
  • 轮转时间间隔默认值为30分钟,证书TTL默认值为1小时,自动重试间隔默认为1秒。
  • polaris-security是一个无状态的组件,可以进行适当的水平扩展来保证高可用。

mTLS实现原理

Polaris提供三种不同的服务粒度模式供用户选择:

模式 解释
Permissive 宽容模式,服务接受纯文本/mTLS服务调用;发起服务调用时,根据对端接受状况自动选择发起mTLS或纯文本服务调用
Strict 严格模式,服务仅接受/发起mTLS服务调用
None 无加密模式(为默认选项),服务仅接受/发起纯文本服务调用

sidecar注入

  • mTLS的开关是用户服务的metadata中的polarismesh.cn/tls-mode键对应的label
  • 服务注册回调时,Polaris Controller的injector发现上述label的值为strict或permissve时,就会渲染出额外的注入配置:挂载secret及uds路径、开启iptables入流量拦截、为polaris-bootstrap-writer设置特殊的环境变量等。
  • polaris-bootstrap-writer检测到mTLS相关的环境变量被设置后,会使用一份mTLS专用的Envoy配置模版来进行渲染,这份模版中设置了sds的相关配置与特殊的node metadata,polaris控制面就是使用这个特殊的metadata来区分服务网格中的各个服务是否启用mTLS功能。

xDS

  • polaris控制面在给各个Envoy sidecar下发配置时,会根据node metadata中的mTLS相关信息来决定下发哪种配置。
  • 对于permissve模式,下发的listener会加入一个TLS Inspector filter配置,TLS Inspector能根据请求的头几字节自动判断这是纯文本请求或是mTLS请求,然后进行不同处理;下发的cluster会加入一个额外的Match条件,在对端endpoint拥有acceptMTLS metadata时,会使用tls transport socket,否则就使用默认的raw buffer transport socket。
  • 对于strict模式,下发的listener仅接受mTLS服务调用;而下发的cluster仅会使用tls transport socket来连接对端endpoint。