14 nginx 的 dns 缓存的流程

前言

这个是 2020年11月 记录的这个关于 nginx 的 dns 缓存的问题 docker 环境下面 前端A连到后端B + 前端B连到后端A

最近从草稿箱发布这个问题的时候, 重新看了一下 发现该问题的记录中仅仅是 定位到了 nginx 这边的 dns 缓存的问题, 但是 并没有到细节, 没有到 具体的 n种解决方式

这里 2024年2月, 本文的目的是 来看一下 这里的具体的细节, 从 nginx 具体的处理流程的过程中来看一下 为什么会是那样 ?

原始问题的上下文如下 docker部署了两套 前端+后端 的系统, appFront0 连接 appBackend0, appFront1 连接 appBackend1, 然后正常启动 前后端系统, 两个前端访问的各自后端系统

这时候, 不断的重启 appBackend0, appBackend1 直到复现 appFront0 访问 appBackend1 或者 appFront1 访问 appBackend0 的情况, 就复现了该问题

复现该问题的关键是 重启的过程中 appBackend0, appBackend1 的 ip 发生了变化

我们这里更侧重关注的就是 nginx 这边在 upstream 中使用域名配置了 上游服务, 然后之后 我们再 更新了 dns 服务的该域名的 ip 配置之后, 我们发现 nginx 这边使用的 ip 还是更新之前的 ip

我们这里 来梳理一下 这个流程, 然后 另外再扩展看一下 具体的 相关的系统调用这边是否有 dns 缓存

测试用例

nginx 配置如下, "/api/" 相关的服务代理到 "http://master:8081/"

http://master:8081/1.txt 的服务为一个文本文件

然后 /etc/hosts 中配置的 master 当前信息如下

当前配置为 192.168.220.2, 可以正常访问到服务

正常访问服务如下, 然后 之后将其切换为 "10.60.50.16" 一个不可用的 ip, 然后刷新页面 发现也可以正常访问到服务

我们要探究的就是 为什么 dns服务 中修改了 master 的 ip, nginx 中拿到的还是 原来映射的 192.168.220.2 呢?

问题的调试

这里会过的比较快, 大体的意思是 nginx 这边解析配置文件的时候 创建了对应的配置数据结构, 初始化的时候就进行了 dns 解析, 然后 后面的业务请求这边使用的是 这套配置

因此访问 http://localhost:82/api/1.txt 一直代理到的是 http://192.168.220.2:8081/1.txt

这里是初始化和上游服务连接的地方, 这里的 fd 就是关键, 是和上游服务关联的 socket

我们来看一下这个 socket

看一下这里的 socket 的信息如下, 下图的 sa_data 就是上游服务的 ip + port

这里 ngx_peer_connection_t pc 的数据来自于 ngx_http_upstream

这里的 sa_data 的数据解析如下, 解析为 192.168.220.2:8081

ngx_http_upstream.ngx_peer_connection_t 的数据来自于这里的 ngx_http_upstream.ngx_peer_connection_t.data 数据类型是 ngx_http_upstream_rr_peer_data_t

ngx_http_upstream.ngx_peer_connection_t.data 数据类型 ngx_http_upstream_rr_peer_data_t 来自于 upstream 这边初始化的时候

这里 ngx_inet_resolve_host 就是解析域名的地方, 然后下面 for(u.naddrs) 中将解析之后的地址信息初始化到 peer 上面去

这个就是 我们最上面和对方服务器创建连接的服务信息 192.168.220.2:8081

nginx 这边 dns 解析的方式

基于函数 getaddrinfo, 这个是 glibc 中的库函数

直接使用 getaddrinfo/gethostbyname 是否有 dns 缓存

这是 扩展的知识点

因为 我这边最开始 怀疑的缓存是在 getaddrinfo/gethostbyname 等等函数上面是否有缓存

因此 最开始的时候 做了一些测试用例, 也调试了一下 对应的函数

复制代码
root@ubuntu:~/Desktop/linux/HelloWorld# cat Test31GetHostByName.c

#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>

int main(int argc, char** argv) {

        char *name = "app0.com";
        char str[16];
        struct hostent* result;

        result = gethostbyname(name);
        printf(" official : %s \n", result->h_name);
        printf(" ip : %s \n", inet_ntop(result->h_addrtype, result->h_addr, str,                                                                                                                               sizeof(str)));

        sleep(10);

        result = gethostbyname(name);
        printf(" official : %s \n", result->h_name);
        printf(" ip : %s \n", inet_ntop(result->h_addrtype, result->h_addr, str,                                                                                                                               sizeof(str)));

}

然后在 sleep(10) 的期间, 调整 app0.com 的 ip映射配置, 结果如下, 可以看到 第二次调用拿到的是最新的 ip

复制代码
root@ubuntu:~/Desktop/linux/HelloWorld# ./Test31GetHostByName
 official : app0.com
 ip : 192.168.220.130
 official : app0.com
 ip : 10.60.50.16

相关推荐
杨了个杨89821 天前
Keepalived + Nginx + HAProxy 高可用架构部署实战案例
java·nginx·架构
李白的天不白1 天前
服务器地址在哪里 pwd
运维·前端·nginx
SDWAN_Cheap1 天前
网络基础扫盲第二弹:DNS、DHCP、ARP、NAT、TCP/IP,从原理到实践
网络·tcp/ip·dns·网络基础
snow@li1 天前
nginx:详解与速查表 / Nginx = 反向代理 + 负载均衡 + 静态服务器 + HTTP 缓存 / 请求分发、静态加速、上线不中断
linux·服务器·nginx
前端程序猿i2 天前
Nginx 教程:从入门到能上线
运维·nginx
明辰之林2 天前
Nginx 1.26.2 → 1.30.2 升级指南(离线环境)
nginx
小云小白2 天前
企业抗量子落地指南(一)全链路抗量子 TLS1.3 落地指南(浏览器 → Nginx → SpringBoot)
spring boot·nginx·抗量子通信
tobias.b2 天前
JumpServer4\.10\.16离线部署\+外部Nginx反向代理 解决30分钟空闲断开WebSocket超时(延长10天)
运维·websocket·nginx
衫水2 天前
Windows Server Nginx 代理企业内网 API 偶发超时处理与保活 SOP(20260608))
运维·windows·nginx
是一个Bug2 天前
Nginx 与 API Gateway:从“小区门卫”到“商场总服务台”
运维·nginx·gateway