worker进程卡在pcre匹配是正则回溯失控的明确信号,表现为单核cpu满载、qps下降、响应时间突增;可通过strace、gdb、perf快速定位;再结合access.log分析高耗时uri,用regex101验证步数爆炸;重点排查嵌套量词、模糊锚定+贪婪匹配、动态拼接三类高危正则;优先用map替代if+正则实现o(1)匹配。

直接看 worker 进程是否卡在 PCRE 匹配上,这是最明确的信号。当 CPU 单核打满、QPS 反而下降、响应时间突增时,问题大概率出在正则回溯失控,而不是流量本身过大。
快速确认是否是正则阻塞
不用等日志堆积,立刻抓进程现场:
- 用 strace -p
-e trace=regexec,regcomp 观察是否频繁陷入正则执行系统调用 - 用 gdb attach
后执行 bt,栈顶反复出现 pcre_exec或match相关函数,基本坐实 - 运行 perf top -p
,若 libpcre.so或libpcre2.so占比超 40%,说明正则消耗已主导 CPU
定位触发回溯的具体 URI 和规则
ReDoS 不是均匀慢,而是特定输入引爆:
- 从 access.log 中筛选
$request_time > 1的请求,重点关注含多个点、斜杠、重复符号或路径极长的 URI - 对可疑 URI,在测试环境用 curl -v 复现,确认是否复现延迟
- 提取对应 location 或 if 中的正则(如
~ ^/api/v[0-9]+/.*/.*$),粘贴到 regex101.com(选 PCRE2 引擎),输入该 URI,观察“步数”是否超万级——步数爆炸即存在灾难性回溯
识别三类高危正则写法
不需逐行审配置,盯住这三种典型结构:
-
嵌套量词:如
(a+)+、(.*a){3,}、^/v\d+/(.+?)/(.+?)$ -
模糊锚定 + 贪婪匹配:如
^/static/.*\.(js|css|png)$(URI 含多个点时易回溯)、location ~ \.php$(没加^和$,会全路径扫描) -
动态拼接且未校验:如
if ($arg_id ~ "^$arg_type.*$") { },变量未经清洗就进正则,既慢又危险
用 map 替代 if + 正则实现 O(1) 匹配
把高频、可枚举的分支逻辑提前固化:
- 将类似
if ($request_uri ~ ^/v(1|2|3)/api/.*) { proxy_pass ... }的写法,改为: - map $uri $api_version {
~^/v1/api/ 1;
~^/v2/api/ 2;
~^/v3/api/ 3;
default 0;
} - 后续用
if ($api_version) { ... },此时匹配由 map 编译后查表完成,不再触发 PCRE











