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

相关推荐
bingbingyihao14 小时前
接口请求控制工具
java·nginx·负载均衡
HEX9CF21 小时前
【Docker】快速部署 Certbot 并为 Nginx 服务器配置 SSL/TLS 证书
服务器·nginx·docker
小萌新上大分1 天前
nginx入门,部署静态资源,反向代理,负载均衡使用
nginx·spring cloud·nginx配置·nginx部署前端项目·nginx负载均衡策略·nginx反向代理配置
virelin_Y.lin1 天前
系统与网络安全------网络通信原理(6)
安全·web安全·应用层·ftp·dns·telnet
三天不学习2 天前
NginxWebUI:可视化 Nginx 配置管理工具,告别繁琐命令行!
运维·nginx
ak啊2 天前
Nginx 动态模块配置指南(以 Brotli 模块为例)
nginx
Z字小熊饼干爱吃保安2 天前
nginx介绍和几种安装方法
linux·运维·nginx·云计算
遇见火星3 天前
nginx或tengine服务器,配置HTTPS下使用WebSocket的线上环境实践!
服务器·websocket·nginx·https·tengine
ldq_sd3 天前
Django 在同一域名下使用 NGINX 服务器运行 Django 和 WordPress
运维·服务器·nginx