如何在几百万qps的网关服务中实现灵活调度策略
核心问题
从流量调度规则为例,大部分的使用方的转发规则都相对比较简单,但是部分业务的转发规则来自于原来的nginx配置,相对比较复杂,更有些使用方会有偏业务的逻辑在里面,例如:- 从某时刻后,将API1的A机房和B机房的流量切30%到C机房;
- 将某个APP的某个版本之上的android流量切到新的路由规则;
- cookie有某些特征或者query中有某些特征的流量转发到预览环境。
- 如何让简单的路由规则配置起来特别简单,性能较高?
- 如何实现复杂甚至业务个性化的调度策略实现?
3.1 方案思路概述
- 对于大多数的简单路由规则需要相对简单,性能相对高,通过域名匹配+树路由实现的url匹配即可;
- 对于少量的复杂路由规则需要扩展性足够强,可以在特征匹配阶段引入一个极简的脚本语言来实现。
3.3 进阶路由规则支持
变量表达式
为了能根据系统里面的常见特征进行精细化匹配,首先我们要对系统里面的常见特征进行描述。例如:- 通过${idc}表示当前所属的机房
- 通过${time}表示当前时间
- 通过${query}表示get参数
- 通过${header}表示header里面的数值
条件表达式
有了上面实现的变量表达式,我们就可以用$描述我们需要的特征变量了,但是如何对这些特征变量进行操作呢? Janus的方案是定义一门极简的语言(无论是用yacc等一类的生成语法分析的工具,还是自己做词法分析、语法分析,实现都比较简单,这里不再赘述实现细节),只支持逻辑运算+函数调用,部分例子如下: 函数调用:
性能对比
通过如上方案介绍可以看出,采用从控制面下发表达式的方式,可以满足绝大部分场景的需求,但是,对性能影响如何呢? 在数据面接收到控制面下发转发规则时,首先会对变量表达式和条件表达式进行编译,映射成go的代码,在后续运行时,与直接调用原生的go语言差异并不大。对比数据如下:条件表达式:
"random(0,100) || random(100,100)"对应的benchmark数据:
goos: windowsgoarch: amd64cpu: 11th Gen Intel(R) Core(TM) i5-1145G7 @ 2.60GHzBenchmarkRandom-8 35817918 34.52 ns/op 0 B/op 0 allocs/op
原生go代码:
(0 > rand.Intn(100)) || (100 > rand.Intn(100))对应的benchmark数据:
goos: windowsgoarch: amd64cpu: 11th Gen Intel(R) Core(TM) i5-1145G7 @ 2.60GHzBenchmarkRawRandom-8 39136900 31.63 ns/op 0 B/op 0 allocs/op
可以看到使用表达式与使用原生go代码在性能上相差不到10%,区别并不是特别大。
4.1 插件的运行条件
- 有些业务认为 :只有后端的http协议返回5xx才需要容灾
- 有些业务认为 :后端的http协议返回5xx 或者 返回值的json里面errno != 0需要容灾
- 更有些业务认为 :后端的http协议返回5xx 或者 header里面的sla_status=0需要容灾
- num_gt(${response.code}, 499)
- num_gt(${response.code}, 499) || (!str_equal(${response.jsonbody.errno}, 0))
- num_gt(${response.code}, 499) || (!str_equal(${response.header.sla_status}, 0))
4.2 通用缓存插件的设计
// 请求下游前if data, ok := redis.Get(key); ok {return data}// 请求下游data := reqeust(xxx)// 请求下游后redis.Set(key, data)
- 评论接口只要id一样就认为是同一个请求
- 我的粉丝接口不仅需要id一样,还需要uk一样才是同一个请求
-
主页接口需要uk一样才认为是同一个请求
- comment_${request.query.id}
- fans_${request.query.id}_${request.query.uk}
-
homepage_${request.query.uk}
- 哔哩哔哩 Web 首页重构——回首2021
- 会员接口治理的探索与实践
- 突破 etcd 限制!字节自研 K8s 存储 KubeBrain
- 周末小技 | 开发一个Feeds流系统——写扩散模式
- BIGO骨干网设计与实现(二)
本文由高可用架构转载。技术原创及架构实践文章,欢迎通过公众号菜单「联系我们」进行投稿