在《BFE和Nginx有什么差异?转发模型的对比》中,对BFE的转发模型进行了详细的说明。
在BFE转发的过程中,“转发表”是一个非常重要的组件。在BFE中为每个租户维护一张独立的“转发表”,在转发表中包含多条顺序执行的转发规则。
在2015年后,BFE转发表的设计没有做过大的修改,除了增加一些“条件原语”(什么是“条件原语”,见 BFE开源项目帮助文档 中的说明)。今年,我们对转发表做了一个较大的升级。
1. 转发表升级的背景
之前BFE转发表的优势是:
(1) 转发表在多个租户间相互独立,降低了转发表的复杂性和维护成本
(2) 基于BFE特有的条件原语和条件表达式,可以描述非常复杂的转发条件
(3) 在转发表内,转发规则的顺序执行,非常容易控制
但BFE的转发表也有一个缺陷,就是无法支持较大规模的转发表。顺序执行的算法复杂度为O(N),当转发表中规则的数量达到一定规模(上百条),会观察到性能有明显的下降。
这个问题在设计之初就是知道的,但是因为之前的使用场景中一个租户内转发规则的数量都比较少,这方面的问题并不突出。今年在某个使用场景中,单个租户的转发规则数量达到了几百条、甚至上千条,性能下降的现象比较明显,这就给转发表的优化升级价创造了契机。
2. 转发表的新方案
在升级后,BFE每个租户的转发表包含2部分:
(1) 基础规则表:可使用域名(Host)和路径(Path)作为匹配条件。支持最长匹配原则。
(2) 高级规则表:支持使用请求中的多种信息做匹配。支持顺序匹配。在高级规则表中可以设置默认规则。
和原方案相比,BFE原来的转发表成为“高级规则表”,继续保持原来机制描述能力强、执行顺序控制能力强的优势;新增的“基础规则表”,使用树形查找,匹配速度快,可以支持较大数量(几千甚至上万)转发规则的快速查找。
根据实测,在单租户内规则规模为3000条(这些规则只使用域名和路径作为匹配条件)的情况下,使用基础规则表比原来的方案性能提升了5倍。
下面重点介绍引入基础规则表后的变化。关于高级规则表的情况,请大家参考BFE开源项目中原有的资料。
3. 转发表内的优先级
在基础规则表和高级规则表之间有明确的优先级。BFE会按照基础规则表、高级规则表的顺序来查找,以确定目标集群。在基础规则表中,也可以将某条规则的目标集群设置为“ADVANCED_MODE”(高级模式)。如果在基础规则表中匹配到这条规则,则转至高级规则表进一步匹配。
详细的匹配顺序见下图。
4. 基础规则表
基础规则表由多条“基础规则”组成。
- 基础规则的匹配条件包括域名(host)和路径(path)两个部分。
- 目的集群通过集群名称来指定,也可以设置为“ADVANCED_MODE”转至高级规则表继续匹配。
- 多条基础规则之间没有前后顺序关系,而是基于精确优先的原则。
基础规则表的详细匹配规则,见BFE开源项目文档中“集群间分流”中的说明。
下面是基础规则的表的一个例子,用于帮助大家理解基础规则表的匹配过程。
有四条基础规则,分别为:
- 规则1:host条件:*.test1.com,path条件:空值,目标集群:StaticCluster
- 规则2:host条件:*.b.test1.com,path条件:/interface/* ,目标集群:PhpCluster
- 规则3:host条件:*.b.test1.com, path条件:/*, 目标集群:StaticCluster
- 规则4:host条件:www.test1.com, path条件:/interface/d, 目标集群:PhpCluster
收到一个请求,请求URL为vip.b.test1.com/interface/d,匹配的顺序如下:
-
首先对host(vip.b.test1.com)进行匹配:
- 1.1 对host做精确匹配,未匹配成功
- 1.2 对host做通配符匹配,发现请求的host(vip.b.test1.com)可以满足规则2和规则3的host条件。
-
继续对path(/interface/d)进行匹配:
- 2.1 对path做精确匹配,未匹配成功
- 2.2 对path做前缀匹配,发现请求的path(/interface/d)可以满足规则2和规则3的path条件。根据最长匹配原则,匹配到从左开始有最多路径元素的那条规则,即规则2。
匹配结束,在基础规则表中命中规则2。根据规则2的设置,将请求转发到集群PhpCluster。
5. 一个例子
下面举一个例子,综合使用了基础规则表和高级规则表的能力。
产品线demo,包含多种服务集群:Demo-A, Demo-B, Demo-C, Demo-D,Demo-E。
期望的转发逻辑条件如下:
- 对于host为www.a.com,path为"/a/*" (除了"/a/b")的请求,转发至Demo-A集群
- 对于host为www.a.com,path为"/a/b"的请求,转发至Demo-B集群
- 对于其他host为*.a.com的请求,转发至Demo-C集群
- 对于host为www.c.com的请求,转发至Demo-D集群
- 针对Demo-D集群,另外开启了一个灰度集群Demo-D1。如果cookie中包含deviceid,且这个cookie的值以“x”开头,则转发至Demo-D1
- 其它请求,都发往Demo-E
对应以上要求,基础规则表的配置为:
host条件 | path条件 | 目标集群 |
---|---|---|
www.a.com | /a/* | Demo-A |
www.a.com | /a/b | Demo-B |
*.a.com | * | Demo-C |
www.c.com | * | ADVANCED_MODE |
在基础规则表中,多条规则之间是无序的。匹配顺序见上面关于基础规则匹配顺序的说明。
针对Demo-D1集群的灰度发布,由于需要使用cookie中的信息,所以使用ADVANCED_MODE将满足条件的请求透传到高级规则表继续处理;在不需要灰度发布的时候,在基础规则表中目标集群可以写为Demo-D。
高级规则表的配置为:
匹配条件 | 目标集群 |
---|---|
req_host_in("www.c.com") && req_cookie_value_prefix_in("deviceid", "x", false) | Demo-D1 |
req_host_in("www.c.com") | Demo-D |
default | Demo-E |
在高级规则表中,多条规则之间是有序的。需要将转发给Demo-D1的规则放在前面。
在高级规则表中包含默认规则,对于没有命中其它规则的请求将被转发到Demo-E。
以上配置信息,对应的配置文件(/conf/server_data_conf/route_rule.conf)如下:
{
"Version": "1.0",
"ProductRule": {
"demo": [
{
"Cond": " req_host_in(\"www.c.com\") && req_cookie_value_prefix_in(\"deviceid\", \"x\", false)",
"ClusterName": "Demo-D1"
},
{
"Cond": " req_host_in(\"www.c.com\")",
"ClusterName": "Demo-D"
},
{
"Cond": "default_t()",
"ClusterName": "Demo-E"
}
]
},
“BasicRule”: {
"demo": [
{
"Hostname": ["www.a.com”],
“Path”: [“/a/*”],
"ClusterName": "Demo-A"
},
{
"Hostname": ["www.a.com"],
“Path”: [“/a/b”],
"ClusterName": "Demo-B"
},
{
"Hostname": ["*.a.com"],
“Path”: “*”,
"ClusterName": "Demo-C"
},
{
"Hostname": ["www.c.com"],
“Path”: “*”,
"ClusterName": "ADVANCED_MODE"
}
]
}
}
6. 总结
BFE开源软件已完成对于转发表能力的升级。在升级后,BFE既可以支持以域名和路径作为匹配条件的大量规模规则,也可以继续保持对于转发条件的强大描述机制。基于这个能力,BFE可以适应更广泛的应用场景,满足大家对于七层转发的各种需求。
欢迎关注“BFE开源项目”公众号,获得本项目的更多更新。谢谢!