Nginx 是一个被宽泛应用的反向代理(Reverse Proxy)开源软件。在“反向代理”这个方向上,BFE 是被设计用来代替 Nginx 的。于是,一个被常常提出的问题呈现了:为什么要应用 BFE?和 Nginx 相比,BFE 到底有什么中央是不同的。
BFE 和 Nginx 最大的不同是设计出发点和转发模型。BFE 从一开始就是为转发场景设计的,可能很好的满足各种转发场景的需要;而 Nginx 原本是作为 Web Server 设计的,用来做转发是“科班出身”,在模型方面存在一些问题。
本文将重点阐明两者在“转发模型”上的差别。
1. 对 Nginx 的剖析
1.1 Nginx 的转发配置
首先看看 Nginx 是怎么做的。
Nginx 配置中的外围概念是 server, location,upstream。
- server:代表一个 web server,能够定义 web server 的监听端口和主机名
- location:代表一个 web server 之下的各门路 / 接口
- upstream:代表被转发的指标
一个典型的 Nginx 转发配置如下所示:
# 定义转发指标集群 cluster_a
upstream cluster_a {
server 192.168.1.1:8080;
server 192.168.1.2:8080;
}
# 定义转发指标集群 cluster_b
upstream cluster_b {
server 192.168.1.3:8080;
server 192.168.1.4:8080;
}
# 定义 www.a.com 的转发规定
server {
listen 80;
server_name www.a.com; # host
location / { # path, 设置为 any
proxy_pass http://cluster_a;# 转发给 cluste_a
}
}
# 定义 www.b.com 的转发规定
server {
listen 80;
server_name www.b.com; # host
location / { # path,设置为 any
proxy_pass http://cluster_b; # 转发给 cluster_b
}
}
如果要在转发过程中做一些非凡的解决,则在以上的配置中插入相干的语句。例如,针对 www.a.com 的申请,能够减少如下 rewrite 规定:
server {
listen 80;
server_name www.a.com;
location / {rewrite '^/images/([a-z]{2})/([a-z0-9]{5})/(.*)\.(png|jpg)$' /data?file=$3.$4;
proxy_pass http://cluster_a
}
}
1.2 Nginx 转发模型的问题
尽管目前很多人将 Nginx 用于转发场景,然而不得不说,Nginx 的转发机制有比较严重的问题。
(1) 转发配置的形容能力较弱
对于一个转发场景来说,配置规定的根本逻辑是:转发条件 => 转发指标
多条转发规定能够造成一张转发表。
转发条件 | 转发指标 |
---|---|
Host=www.a.com | cluster_a |
Host=www.b.com | cluster_b |
在 Nginx 中,并没有呈现明确的转发表概念,转发规定的形容受到配置中 server-location 构造的限度。server-location 构造原本是设计用于 web server 的,用于转发就比拟轻便。例子中这种简略的转发逻辑须要比拟多的配置语句。
在 Nginx 开源版本中,location 形容机制在表达能力方面的毛病具体表现在:
- 仅反对基于 uri 的条件,无奈间接反对基于申请 Header 或申请上下文的条件
- 针对常见的 uri 蕴含匹配、后缀匹配也不得不应用正则表达式
- 难以对多个条件灵便进行逻辑组合(与或非)
(2) 转发规定的优先级较简单
在存在多条转发规定的时候,优先级的管制就变得十分重要。
Nginx 在匹配优先级上做了肯定的限度,必须首先匹配 Host 以确定 server,而后在 server 内匹配 location。这个限度在简略的场景下没有问题,然而在比较复杂的场景下可能会制约规定的编写。
在匹配 server 和匹配 location 时,都有比较复杂的规定(见下)。在比较复杂的场景下,最终失效的后果并不容易预测。
匹配 server 时,规定如下:
1、齐全匹配
2、通配符在前的,如 *.test.com
3、在后的,如 www.test.*
4、正则匹配,如~^\.www\.test\.com$
如果都不匹配
1、优先选择 listen 配置项后有 default 或 default_server 的
2、找到匹配 listen 端口的第一个 server 块
在匹配 location 时,规定如下:
1. 字符串最长匹配(非正则表达式)和在配置文件中呈现的先后顺序无关
2. 正则匹配
正则表达式依照配置文件中程序匹配,一旦匹配,不会持续匹配
(3) 大量应用正则表达式
在 Nginx 中,对于略微简单的场景,就须要在转发规定的形容中应用正则表达式。
在实践中,咱们发现正则表达式存在以下两个重大问题:
- 配置难以保护。正则表达式存在重大的可读性问题。用正则表达式编写的转发条件很难看懂,且容易存在二义性。
- 性能存在隐患。对于编写不当的正则表达式,可能在特定的流量特色下会呈现重大的性能进化。
(4)“根底转发”和“转发的附加解决”混淆在一起
在反向代理的转发模型中,须要包容以下两个基本功能:
- 根底转发配置。定义转发的条件和转发的指标。
- 转发的附加解决。定义在转发中须要做的操作,如 rewrite, redirect 等等。
在 Nginx 中,“根底转发”和“转发的附加解决”(如,rewrite, redirect 等)只能混在一起写。在一些状况下,“转发的附加解决”和“根底转发”的匹配逻辑可能并不完全一致,在 Nginx 中配置保护比拟艰难。
(5) 不反对在多组实例间依照比例调度
在多数据中心或多容器云的场景下,可能有这样的需要:
- 多组实例都提供雷同的服务
- 在多组实例间,使用权重比例来调度流量
这个需要转换为 Nginx 的概念,就是须要反对对满足某种转发规定的申请,依照设定的权重转发给多个 upstream。Nginx 不反对这样的性能。
2. BFE 和 Nginx 的差别
BFE 的定位是“为企业级场景设计的古代七层负载平衡开源软件”。和 Nginx 相比,BFE 有以下的变动:
(1) 面向转发场景设计
- 在 BFE 中明确引入了“转发表”的概念,能够清晰而简洁的设定转发条件和转发指标。
- 在 BFE 中,除了 Host 和 Path 外,也能够很容易的应用申请中更多的信息作为转发条件。
- 在 BFE“转发表”的多条规定间,有较简略的优先级策略,更易于了解
(2) 尽量避免正则表达式的应用
针对正则表达式所存在的问题,BFE 中设计了“条件表达式”(Condition Expression)机制,以进步转发规定的可维护性,并升高性能进化的隐患。
(3) 将“转发的附加解决”和“根底转发”的配置拆散
如 rewrite、redirect 这样的解决,各自有独立的配置。
(4) 提供了多组实例间依照比例调度的性能
这个性能对于多数据中心或多容器云场景的调度十分有用。
3. BFE 转发中的基本概念
在 BFE 中,有以下基本概念:
(1) 租户(Tenant)。应用 BFE 转发的业务能够基于“租户”的单位来辨别。BFE 引擎中的配置,比方转发策略、各扩大模块的配置等,都是以租户为单位来辨别的。
在 BFE 中,租户也被称为“产品线(Product)”。
(2) 后端集群(Cluster)。具备同类性能的后端被定义为一个集群。对于一个租户,能够定义多个集群。在某些场景中,集群也被称为服务(Service)。在一个租户内,能够应用租户的路由转发表将流量转发给适合的集群。
(3) 后端子集群(Sub Cluster)。在多数据中心场景下,集群能够划分为多个子集群。通常,能够将集群中处于同一数据中心的后端定义为一个子集群。在某些场景中,子集群也被称为实例组(Instance Group)。子集群概念的引入,次要是为了解决多数据中心场景下的流量调度。
(4) 后端实例(Instance)。每个子集群可蕴含多个后端服务实例(Instance),每个后端实例通过 ”IP 地址 + 端口号 ” 标识。
下图中用一个例子对以上概念之间的关系做出了阐明,其中蕴含 2 个租户。租户 1 配置了 2 个集群(集群 A 和集群 B),这 2 个集群别离有 2 个子集群和 1 个子集群,各子集群有 1~3 个实例;租户 2 只配置了一个集群(集群 C),集群 C 有 2 个子集群,2 个子集群各有 2 个实例。
4. BFE 的转发过程
上面应用一个例子来说 BFE 的转发流程。例子的场景如下图所示。客户端首先通过 DNS 解析,取得目标 IP 地址(步骤 1 -2)。之后申请首先被发送到四层负载平衡(步骤 3),而后再转发给 BFE(步骤 4)。
在 HTTP 申请达到 BFE 后,BFE 的解决步骤如下:
- 步骤 5:确定 HTTP 申请所属的租户。BFE 能够依据 HTTP 申请头中的“Host”字段或 HTTP 申请的指标 IP 地址来确定租户。在本案例中,针对 HTTP 申请头中 demo.example.com 域名,BFE 找到对应的租户为 demo。
- 步骤 6:依据租户的分流规定,决定 HTTP 申请的目标集群。对于每个租户,能够配置一张独立的路由转发表。通过查找路由转发表,确定申请所属的目标集群。路由转发机制的详情将在前面的章节中介绍。在本案例中,通过查表确定对应的目标集群为 demo-static。
- 步骤 7:依据集群的内网流量调度策略,抉择适合的子集群。对于每个 BFE 集群,能够针对每个集群的各子集群设置转发权重。BFE 依据设置的转发权重来执行转发操作。内网流量调度机制的详情将在前面的章节中介绍。在本案例中,假如在 IDC1 的 BFE 集群上,demo-static 的 3 个子集群对应的转发权重为(100, 0, 0),所以,确定转发的指标子集群为 demo-static.idc1。
- 步骤 8:依据集群的子集群负载平衡策略,抉择适合的实例。对于每个集群,能够设置子集群的负载平衡策略,如 WRR(Weighted Round Robin,加权轮询)、WLC(Weighted Least Connections,加权最小连接数)等。BFE 依据子集群的负载平衡策略,在子集群中抉择适合服务实例来解决申请。在本案例中,最终抉择 demo-static-01.idc1 来解决申请。
5. BFE 的转发表
在 BFE 内对每个租户保护一张独立的“转发表”。对于每个属于该租户的申请,通过查问转发表取得指标集群。
转发表由多条“转发规定”组成。在查问时,对多条转发规定以程序的形式查找;只有命中任何一条转发规定,就会完结退出,其中最初一条规定为“默认规定(Default)”。在所有转发规定都没有命中的时候,执行默认规定。
每条转发规定蕴含两局部:匹配条件和指标集群。其中匹配条件应用 BFE 自研的“条件表达式“来表述。
上面展现了一个转发表的例子。在这个例子中,蕴含以下 3 种服务集群。
(1) 动态集群(demo-static):服务动态流量。
(2) post 集群(demo-post):服务 post 流量。
(3) main 集群(demo-main):服务其余流量。
冀望的转发逻辑如下:
(1) 对于 Path 以 ”/static” 为前缀的,都发往 demo-static 集群。
(2) 申请办法为 ”POST” 且 Path 以 ”/setting” 为前缀的,都发往 demo-post 集群。
(3) 其余申请,都发往 demo-main 集群。
6. 附加解决的独立配置
在 BFE 中,为各扩大解决模块建设了独立的配置文件,这样能够升高配置保护的复杂性,防止配置之间的耦合。
以 redirect 性能为例,在目录 conf/mod_redirect/ 下,能够看到 mod_redirect.conf 和 redirect.data 这两个配置文件。
rewrite.data 蕴含重定向规定,可动静加载。在安装包中,示例中的配置文件如下:
{
"Version": "1",
"Config": {
"example_product": [
{"Cond": "req_path_prefix_in(\"/redirect\", false)",
"Actions": [
{
"Cmd": "URL_SET",
"Params": ["https://example.org"]
}
],
"Status": 301
}
]
}
}
7. 总结
本文从“转发模型”的角度对 Nginx 和 BFE 进行了比照。
Nginx 从 Web Server 登程,被“借用“于反向代理场景,在转发模型方面存在多处问题。在简略的利用场景下,这些问题可能还不显著;然而在较简单和较大规模的场景下,这些问题会显现出来。
BFE 定位于“为企业级场景设计的古代七层负载平衡开源软件”,在设计中思考了简单业务场景的需要,能够反对简单的转发规定,反对多数据中心和多容器云调度场景。
因为篇幅所限,对于 BFE 转发模型的介绍比拟粗略。有趣味的读者可进一步查看《深刻了解 BFE》中的阐明。此书已由电子工业出版社正式出版,书名为《万亿级流量转发 – BFE 核心技术与实现》。
可通过扫描下方的二维码优惠购买。
欢送关注“BFE 开源我的项目”公众号,取得本我的项目的更多更新。谢谢!