Nginx 配置上百个 server_name 时性能瓶颈在域名匹配,尤其正则表达式;应改用精确域名列表、分层匹配、调优哈希参数,并用 map 指令替代冗余 server 块。

用精确域名列表替代正则匹配
正则 `server_name ~^app\d+\.example\.com$` 每次都要执行完整 PCRE 运算,100 个这样的块会让首字节延迟明显上升。
✅ 正确做法:把可枚举的子域名全部列进一个 server 块:
server_name app1.example.com app2.example.com app3.example.com ... app99.example.com;- Nginx 对空格分隔的域名采用哈希表查找,O(1) 平均复杂度,比正则快一个数量级以上
- 注意总长度限制:单行 `server_name` 不宜超 4KB(受内部缓冲区影响),超长时可拆成多行,Nginx 支持换行续写
按优先级分层设计 server 块结构
Nginx 匹配顺序固定:精确匹配 > 左侧通配符(*.example.com)> 右侧通配符(example.*)> 正则。合理分层能大幅减少平均匹配耗时:
- 高频域名(如
www.example.com、api.example.com)单独设精确 `server` 块 - 中低频子域名归入一个泛域名块:
server_name *.example.com; - 真正需要动态提取的场景(如租户子域路由),改用泛域名 + `map` 指令在 location 内分流,避免在 server_name 层做正则
启用 server_name 哈希表优化
当精确域名总数超过 64 个,默认哈希桶可能冲突增多,导致链表查找退化。
✅ 显式调优:
- 在 http 块顶部添加:
server_names_hash_max_size 2048; - 配合:
server_names_hash_bucket_size 128;(根据最长域名长度调整,通常 64 或 128 足够) - 修改后必须重启 Nginx(不支持 reload),否则报错“could not build the server_names_hash”
用 map 实现动态逻辑,剥离 server_name 负担
例如需对不同子域名设置不同 root 或 header,不要为每个子域写一个 server 块:
- 定义映射:
map $host $site_root { default "/var/www/default"; "~^(?<s>.+)\.example\.com$" "/var/www/sites/$s"; }</s> - 在通用 server 块中直接引用:
root $site_root; - 这样只需 1 个 server 块支撑数百子域,且 map 查找是编译期构建、运行期 O(log n)



















