现象与问题的提出

在配置 Nginx 时,我们可以在 proxy_pass 后传递目标路径,如一个 URL、一个变量或者是一个 upstream 名。如,下方这些配置都是合法的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
upstream backend {
server foo.example.com;
server bar.example.com;
}
server {
listen 80;

location /apple/ {
proxy_pass http://backend; # upstream 名
}

location /orange/ {
proxy_pass http://docker_container; # 服务名,指向某个容器
}

location /pear/ {
proxy_pass http://127.0.0.1:8000 # 裸 IP
}
}

proxy_pass 接受 upstream 名、服务名等人类可读性更好的方式,当然也支持纯 IP 的方式。

在机器内部,肯定需要转变为 IP 地址才能通信。因此,方便人的这套接口一定在哪里发生了转换,变成了机器友好的 IP 地址。这篇文章讨论这一问题。

什么是 Nginx

Nginx 是一个 HTTP web 服务器,反向代理,内容缓存,负载均衡器等等。它接收传入的请求,将请求的目标导向正确的位置,并返回结果。

对于一个前后端分离的应用,我们可以如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
listen 80;
server_name www.example.com;

root /var/www/example;
index index.html;

location /api/ {
proxy_pass http://127.0.0.1:8000;
}

location / {
try_files $uri $uri/ /index.html;
}
}

这样,当用户访问 www.example.com/api/foobar 时,请求会被转发给服务器上 http://127.0.0.1:8000 的后端服务,处理接口请求;当用户访问 www.example.com/assets/app123456.js 时,会返回前端文件等静态内容。

这样就实现了一个最基本的前后端分离应用的部署,没有负载均衡,没有 HTTPS,没有更高级的特性,非常简单。但一切事物都是从简单逐渐到复杂的,对于我们本次实验,了解到这个程度便足够了。

为什么 Nginx 需要 DNS

在文章开头提到的各种配置中,可以在 proxy_pass 后直接传裸 IP,也可以传入 upstream 名。如果是微服务架构,还可以传入服务名。不论是何种形式,为了完成网络通信,都需要转变为 IP 地址。这就是作为电话簿的 DNS 要完成的事情。

裸 IP 的配置不必多说,没什么转换的开销;upstream 名该如何转换,这种写法看上去很神奇,如果我们 ping backend,似乎不会通;最后,如果是微服务名,又是怎么转变成 IP 地址的?

这里面一定经过了一些逻辑,根据现有的网络知识推测,肯定少不了 DNS,所以看看这件事在哪个函数完成。

源码分析

Nginx 的主流程与设计思想

upstream 的创建

DNS 解析

如何调试 Nginx 源码

`ngx_http_upstream` 的调用栈

总结