Nginx作为一个高性能的HTTP和反向代理服务器,目前已经成为了最为广泛使用的代理服务器。在使用Nginx作为反向代理的时候,假如有以下的一种场景:系统通过Nginx统一接入,而系统本身包含多个域名和多个后端服务器,为了实现故障的隔离,我们可能想把对不同域名的请求转发到不同后端。那么应该怎么实现呢?
基于Nginx本身的配置特性,我们可能自然而然地想到利用多个server_name的配置来实现,配置类似以下这段:
upstream ups1 {
server 192.168.10.13;
server 192.168.10.14;
}
upstream ups1 {
server 192.168.10.15;
server 192.168.10.16;
}
server{
listen 80;
server_name domain-name; # 监听域名
location / {
proxy_pass ups1; # 转发的后端,此处省略了http协议
}
}
server{
listen 80;
server_name another-domain-name; # 监听域名
location / {
proxy_pass ups2; # 转发的后端,此处省略了http协议
}
}
由于Nginx匹配请求的时候优先会匹配server_name与Host一致的,因此通过上述方式即可将不同域名的请求转发到不同后端。但是这种配置的缺点是配置冗长,如果域名较多,且其他配置项很多,那么就可能会产生大量重复的配置。并且新增域名的时候也要增加不少重复配置。
为了减少冗余配置,便于维护,我们可以利用map模块来实现。map模块由ngx_http_map_module提供,用于创建其值取决于其他值的变量。基于map实现的配置如下:
map $http_host $ups_name {
default 'ups1';
domain-name 'ups1';
another-domain-name 'ups2';
}
upstream ups1 {
server 192.168.10.13;
server 192.168.10.14;
}
upstream ups1 {
server 192.168.10.15;
server 192.168.10.16;
}
server{
listen 80;
server_name domain-name another-domain-name; # 监听域名
location / {
proxy_pass $ups_name; # 转发的后端,此处省略了http协议
}
}
通过把Host映射到跟upstream名称对应的字符,只需要配置一个server块即可满足将不同域名的请求转发到不同后端要求。并且由于map可以支持多个变量拼接在一起再映射,所以可以基于特性去做更多的个性化请求隔离控制。
另外map中的变量只有在使用时才进行评估,因此即使是大量映射变量的声明也不会给请求处理增加任何额外成本,所以我们甚至可以提前将预留的域名配置上去。
实际上,如果不想使用map模块去实现,我们仍可以像开头那样利用server_name的特性去实现,因为sever_name配置项本身支持正则表达式,我们可以通过正则表达式捕获变量的方式去转发到不同的后端,这个方法就留给读者去思考实现,在此不做赘述。