查看原文
其他

上医治未病:BFE对正则表达式的思考

BFE开源项目 BFE开源项目 2024-04-15

    上医治未病,中医治欲病,下医治已病”(《黄帝内经》)



    在七层负载均衡领域,正则表达式被广泛的使用于路由转发规则的配置。在Nginx和OpenResty中,都依赖于正则表达式的机制。


    在实践中,我们发现正则表达式存在以下两个严重问题:

(1) 配置难以维护。正则表达式存在严重的可读性问题。用正则表达式编写的转发条件很难看懂,且容易存在二义性,我们经常发现,对于一个人编写的分流条件,其他人很难接手继续维护。

(2) 性能存在隐患。对于编写不当的正则表达式,可能在特定的流量特征下会出现严重的性能退化。在线上曾经发生过这样的情况:原本每秒可以处理几千个请求的服务,由于增加了一个正则表达式描述,其性能下降到每秒只能处理几十个请求。


    针对正则表达式所存在的性能隐患,已经有不少分析的文章,可以搜索“正则表达式回溯漏洞”或“正则表达式回溯陷阱”。在解决这个问题方面,大家有不同的思路。



    一种思路是在发生性能方面的问题后,使用工具来快速定位问题。如OpenResty官网Blog在7月份发表了文章《Tracing the Slowest PCRE Regular Expressions in OpenResty or Nginx Processes》(https://blog.openresty.com/en/ngx-slowest-pcre-regexes/),可以实时的对Nginx和OpenResty的进程进行分析,并快速定位那些有问题的正则表达式。


    遗憾的是,以上的思路在大规模多租户的场景并不适用。在BFE所部署的场景中,经常并存很多租户。这些租户的管理员可以随时自助的提交转发配置,而这些配置在提交后会在几分钟内下发生效。如果某个租户的管理员提交了有问题的条件表达式,会很快在多个租户所复用的BFE集群生效,并对于转发集群整体的稳定性产生威胁。在这种情况下,即使有很好的工具来快速发现和定位有问题的表达式,也无法阻止事故的发生



    在BFE的设计中,我们使用了另外一种思路:尽量减少正则表达式的使用


    在BFE中,引入了自定义的条件表达式(Condition Expression)。条件表达式的详情见 https://github.com/bfenetworks/bfe/tree/develop/docs/zh_cn/condition,下面只做简要介绍。


在条件表达式的设计中引用了以下思想。

(1)在表述中明确指定所使用的HTTP请求字段,以此提升可读性。例如,从req_path_prefix_in()这样的名字中可以立刻看出是针对请求中的Path部分进行前缀匹配;从req_method_in()中可以看出是针对请求的“method”字段进行匹配。

(2)控制计算的复杂度,降低性能退化的风险。条件表达式主要使用精确匹配、前缀匹配、后缀匹配等计算方式,这些计算方式的计算复杂度都较低。


    条件表达式的例子如下:


// 如果请求域名是"bfe-networks.com"且请求方法是"GET", 返回true

req_host_in("bfe-networks.com") && req_method_in("GET")


 在以上例子中,req_host_in()req_method_in()2BFE内置的条件原语,类似这样的条件原语有几十个,可以描述各种可能的匹配条件(详情可以参考https://github.com/bfenetworks/bfe/blob/develop/docs/zh_cn/condition/condition_primitive_index.md)。

    多个条件原语之间可以使用与、或、非来组合,成为条件表达式



    条件表达式的机制,在多租户大流量场景下经过了多年的验证,取得了非常好的效果。在上千个租户的情况下,各租户的管理员都可以很好的维护自己的配置,并且对公用转发平台的稳定性没有影响。


       BFE转发模型的详细说明,可以参考历史文章:



    欢迎关注“BFE开源项目”微信公众号,获得本项目的更多信息。谢谢!

继续滑动看下一个
向上滑动看下一个

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存