当前位置: 首页 > news >正文

Nginx 缓存 DNS 解析问题

网上看到一些文章,觉得很不错,这里记录一下。

一、缓存问题的解决方案

1 每次更改 DNS 解析都重载 Nginx

        重载 Nginx 一定会刷新缓存。

2 使用 Nginx 的 resolver

        我们在使用 Nginx 过程中,有时需要根据 Url 传值动态选择 host 进行代理转发,这种模式下,一开始是不会去进行 DNS 解析的,只有请求的时候才会进行 DNS 解析,并且要设置 resolver 指定 DNS 服务器 IP。

        这个时候,我们就可以使用 resolver 语法来解决 DNS 缓存的问题,比如说,我在原来的 Nginx 配置里指定 DNS IP,并设置缓存 60 秒。

server {listen 80;server_name www.test.com;resolver 127.0.0.1 valid=60s;resolver_timeout 3s;set $proxy_url "proxy.test.com";location / {proxy_set_header Host proxy.test.com;proxy_pass http://$proxy_url;}
}

        但这种方法无法作用于 upstream 里的域名。

3 使用模块nginx-upstream-dynamic-servers

模块地址: nginx-upstream-dynamic-servers

https://github.com/GUI/nginx-upstream-dynamic-servers

        该模块在第一次启动的时候会进行一次解析,解析完后,在 DNS 服务器设定的 TTL 过期时间内不会再次更新,过期后会再次发起解析请求

使用方法

http {resolver 8.8.8.8;upstream example {server example.com resolve;}
}

使用这种方法的时候,DNS TTL 时间需要设置短一些。

注意:官方文档值验证了nginx 1.6, 1.7, 1.8, 1.9.,对于高版本是否支持还需验证。

并且官方文档也提及:

Alternatives

  • proxy_pass + resolver: If you only need to proxy to 1 domain and don't need the additional capabilities of upstreams, nginx's proxy_pass can perform resolving at run-time.
  • ngx_upstream_jdomain: An nginx module that asyncronously resolves domain names. The primary differences between jdomain and this module is that this module keeps domain names up to date even if no server traffic is being generated (jdomain requires traffic to each upstream in order to keep it up to date). This module also allows nginx to startup if unresolvable domain names are given.
  • tengine's dynamic_resolve: If you're using tengine (an nginx fork), there's a new feature (currently unreleased) to support resolving domain names in upstreams at run-time.
  • NGINX Plus

4 使用模块 ngx_upstream_jdomain

文档地址: domain_resolve

https://github.com/nicholaschiasson/ngx_upstream_jdomain

   ngx_upstream_jdomain 模块是一个依赖 DNS 解析实现的 upstream 负载均衡,该模式下,允许使用域名来写 upstream 后端。该模块默认情况下,会每秒做一次 DNS 解析,使用方法如下

http {resolver 8.8.8.8;resolver_timeout 10s;upstream backend {jdomain www.baidu.com port=80 interval=5; # 每 5 秒解析一次}server {listen  8080;location / {proxy_set_header Host $host;proxy_pass http://backend;}}
}

使用nginx的ngx_upstream_jdomain模块实现k8s容器的负载均衡


        最近一直在准备k8s上线事宜,目前已经在测试环境中全面部署并通过压力测试环境检验。离正式上线基本只剩下时间问题。我们目前测试环境中的容器负载均衡大量使用到了nginx,就是借助了ngx_upstream_jdomain模块,从而放弃了k8s官方的ingress。

        在这里简单说下k8s的ingress。k8s官方的ingress controller其实也是通过nginx来实现的,但是Ingress本身依赖于service,它通过查询service的映射,来找到service后端的pod的真实ip,并将其挂载到ingress controll的upstream中来实现负载均衡。这本身其实并没有什么问题。但由于在我们的k8s中,鉴于标准service基于kube-proxy的转发效率不高,我们放弃了标准service。转而直接采用了headless service的方式。这种方式的好处是,dns解析会直接解析到每个pod的ip,而不再解析到service ip,也不再需要kube-proxy来实现转发。缺点是负载均衡只能依赖dns轮循,没有灵活的调度策略,但毫无疑问,由于去除了kube-proxy这个中间层,转发效率得到了提高。另外,由于我们直接打通了Pod与物理服务器之间的网络,物理网络中的主机可以与Pod之间通信,如果在中间采用标准的service,service的ip反而无法与物理网络直接实现通信。

        这样一来,我们外部的负载均衡就没办法再去依赖Ingress了,我们采用了在外部部署nginx来实现负载均衡的方法,由于upstream里的pod ip会动态变化,所以我们不能直接在upstream里写死pod的ip地址,而只能用service的域名来替代,并让nginx自己去解析这个域名,我们知道headless service的域名由于没有内部的service ip,所以是直接解析到pod ip上的,这样就等于动态拿到了pod ip。在这种情况下,nginx_upstream_jdomain模块就登场了。

 使用nginx的ngx_upstream_jdomain模块实现k8s容器的负载均衡 - breezey - 博客园

另外,还需要说明的是,通过这种方式代理到后端的服务,后端服务接收到的$host的值即为www-stress-80,如果后端服务以主机头的方式来接受服务,这显然是不能接受的。所以在代理配置中,必须加上如下配置以将主机头传递给后端服务器:

proxy_set_header Host $host;

5 使用其他版本 Nginx

  • Tengine Tengine 的 ngx_http_upstream_dynamic 模块可以提供动态的 DNS 解析
  • NGINX Plus Plus版本提供了动态解析的语法

在这里我才用了第三种方案,使用模块nginx-upstream-dynamic-servers。

参考资料

  • 运维遇坑记录(3)-Nginx缓存了DNS解析造成后端不通
  • 使用 buildx 构建多平台 Docker 镜像
  • nginx-upstream-dynamic-servers
  • 利用 docker buildx 静态编译 nginx

http://www.mrgr.cn/news/79157.html

相关文章:

  • 【SpringBoot整合Tess4j实现图片文字识别(OCR】
  • 今天你学C++了吗?——C++中的类与对象(日期类的实现)——实践与知识的碰撞❤
  • 阿里云 云产品流转(实现设备与小程序交互)
  • net.core SignalR web Socket ws
  • 3.反转链表
  • Mac/Windows端长期破解myBase8方法(无需安装火绒)
  • THREE.js 入门(一)xyz坐标系
  • 深入浅出:php-学习入门全攻略
  • Docker 安装系列
  • git管理Unity项目的正确方式
  • python更新程序并部署服务器服务
  • 字符串函数和内存函数
  • C++ packaged_task
  • ElasticSearch学习记录
  • 51c视觉~YOLO~合集4
  • etcd-v3.5release-(2)-STM
  • python技巧:if else,逻辑判断要写完整。
  • Android 分词的两种方式
  • Unity数据持久化
  • Springboot3整合Redis
  • 工业—使用Flink处理Kafka中的数据_ProduceRecord1
  • 调试android 指纹遇到的坑
  • 右值引用和完美转发【C++11】
  • flask简易版的后端服务创建接口(python)
  • 【时间序列预测】基于Pytorch实现CNN_LSTM算法
  • 典型的调度算法--短作业优先调度算法