我眼中的 Nginx(六):深入 Nginx/Openresty 服务里的 DNS 解析
张超:又拍云系统开发高级工程师,负责又拍云 CDN 平台相关组件的更新及维护。Github ID: tokers,活跃于 OpenResty 社区和 Nginx 邮件列表等开源社区,专注于服务端技术的研究;曾为 ngx_lua 贡献源码,在 Nginx、ngx_lua、CDN 性能优化、日志优化方面有较为深入的研究。
DNS 解析在 Nginx/OpenResty 的服务里是不可分割的一个功能,本文主要来介绍下 Nginx 和 OpenResty 服务里的一些不同的 DNS 解析方式以及它们之间的优缺点。
配置解析阶段
很多时候我们会在 Nginx 配置文件里配置上一些域名,比如配置我们的上游服务器。
- upstream example.com {
- server foo.example.com;
- }
对于这类域名,Nginx 会在配置解析阶段就将其解析出来,接下来(请求处理过程)使用的都是当时解析得到的 IP。Nginx 核心有一个函数 ngx_parse_url,负责对 url 格式进行分析,包括解析出主机名,端口号以及 URL path 等。针对 IPv4 的情况,它会调用 ngx_parse_inet_url进行具体的解析任务,如果必要,最终它会调用到 ngx_inet_resolve_host进行域名解析,ngx_inet_resolve_host 大多情况下会使用 getaddrinfo 进行解析,最终向 /etc/resolv.conf 下所配置的 DNS server 发起解析请求。
归纳来说这个解析过程有两个特点,一是使用了系统配置的 DNS server;二是解析过程是同步且阻塞的,因此这种解析方式仅在 Nginx 配置解析阶段会被使用。另外这种解析方式的缺点就是只解析一次,所以如果在 Nginx 运行过程中域名解析发生了改变也是无法感知到的,除非手动重启 Nginx 服务。
运行时 DNS resolver
Nginx 核心提供了一套供运行时使用的 DNS 解析机制,它充分契合 Nginx 的事件模型,同样是异步非阻塞的,并且提供了缓存机制。http、stream 和 mail 模块分别提供了配置指令(比如 http 模块提供的 resolver),供我们配置相关 DNS server 地址等信息。
下面这个简单的反向代理配置,就会在进行代理前解析 http://www.upyun.com 这个域名。
- location / {
- set $myupstream www.upyun.com;
- proxy_http_version 1.1;
- proxy_set_header Connection "";
- proxy_pass http://${myupstream}/index.html;
- }
注意如果直接在 proxy_pass 指令里写明需要代理的域名(即不使用变量的方式),那么域名解析就会发生在配置解析阶段了,即上面所讲的过程。这其实也是一种实现动态 upstream 的方式。
这套运行时 DNS resolver 其实是一个 DNS client 的角色,由它自己组织查询报文并发送给目标 DNS 服务器,同时支持解析 IPv6 地址(从 1.5.8 开始),支持反向地址解析和 SRV 解析。它把对每个域名的解析抽象为一棵红黑树的节点,包括任何必要的信息。同时这棵红黑树也充当着缓存,查询时会以域名作为 key,如果对应缓存是新鲜的,即会复用缓存,并且会对解析得到的地址顺序进行一定的回转后再提供给上层使用。如果没有缓存或者缓存过期,新的 DNS 请求会被构建并且发送。
当然,很多时候这套运行时的 DNS resolver 也不能完全满足需求:
- 无法配置主备 DNS 服务器地址,我们在 resolver 指令里配置的地址都会按顺序被轮询到。
- 无法在 DNS 服务器故障或者网络质量不佳的情况下复用陈旧的缓存,这可能导致上层服务不可用。
- 每个 Nginx worker 进程独享解析缓存。
Cosocket
Cosocket 是 lua-nginx-module 提供的最强有力的接口(个人来看没有之一)。它的 connect方法同样支持传入域名,之后会调用上面介绍的 Nginx 运行时 resolver 来解析对应域名,然后随机挑选一个 IP 作为本次连接的目标 IP 地址。由于是使用的 Nginx 运行时 resolver ,如果 DNS resolver 无法正常进行解析,则利用 Cosocket 构建的服务也都会受到影响。
lua-resty-dns
OpenResty 官方开源的 lua-resty-dns 是利用 Cosocket 实现的一套百分百非阻塞的 DNS resolver,它仅仅充当了一个 DNS 解析器,没有任何其他的附加功能,包括缓存。
前面介绍过 Nginx 运行时 DNS resolver 在很多时候是有诸多的不便的,而 lua-resty-dns 则给我们留了很多的扩展空间:
- 提供主备 DNS 服务器地址 —— 结合像 lua-resty-checkups 这样的工具可以很容易的维护主备 DNS 服务器地址,包括进行心跳检测。
- 进程间共享缓存 —— 结合使用 lua-nginx-module 提供的共享内存字典,可以非常容易地管理缓存。
- 故障时使用陈旧缓存 —— 在 lua-resty-dns 报告异常时再次使用缓存即可(只要缓存拷贝没有被强行淘汰)。
目前 OpenResty 生态圈已经有一些基于lua-resty-dns 实现的加强版实现,比如 Kong 的 lua-resty-dns-client。
总的来说,每一种 DNS 解析方式都有它适用的场景,也有它自己的不足,没有最好的,只有最合适的。在程序设计的时候,需要找到最合适自己业务场景的方式,才能最大程度地保障服务的可用性和可靠性,避免带来一些灾难。
推荐阅读:
我眼中的 Nginx(五):Nginx - 子请求设计之道
我眼中的 Nginx(四):是什么让你的 Nginx 服务退出这么慢?
我眼中的 Nginx(三):Nginx 变量和变量插值
我眼中的 Nginx(二):HTTP/2 dynamic table size update
我眼中的 Nginx(一):Nginx 和位运算
我眼中的 Nginx(六):深入 Nginx/Openresty 服务里的 DNS 解析的更多相关文章
- Nginx(六):Nginx HTTP负载均衡和反向代理的配置与优化
一.什么是负载均衡和反向代理 随着网站访问量的快速增长,单台服务器已经无法承担大量用户的并发访问,必须釆用多台服务器协同工作,以提高计算机系统的处理能力和计算强度,满足当前业务量的需求.而如何在完成同 ...
- 用lua扩展你的Nginx(整理)-----openresty
用lua扩展你的Nginx(整理) 首先得声明.这不是我的原创,是在网上搜索到的一篇文章,原著是谁也搞不清楚了.按风格应该是属于章亦春的文章. 整理花了不少时间,所以就暂写成原创吧. 一. 概述 Ng ...
- web 部署专题(六):nginx 安装(二) linux
https://www.cnblogs.com/quzq/p/12131696.html 基础篇 一.环境 服务器版本:CentOS 7.2 为了保证学习阶段不遇到奇怪的事情,请保证以下四点(大神选择 ...
- Nginx源码研究六:NGINX的配置文件分析
上一篇写到nginx的各个模块的配置信息的存储结构,大体描述了对配置信息的配置项生成,定制,初始化过程.这里重点研究实现定制的过程,所谓实现定制,这里指的是,nginx系统提供使用者定义nginx的配 ...
- Nginx详解二十六:Nginx架构篇之性能优化
一.性能优化考虑点 1.当前系统结构瓶颈 通过压力测试观察指标.日志检测.性能分析 2.了解业务模式 接口业务类型.系统层次化结构 3.性能与安全 二.ab接口压力测试工具 1.安装:yum -y i ...
- Nginx详解十六:Nginx场景实践篇之缓存服务
缓存类型: 服务端缓存 代理缓存 客户端缓存 Nginx代理缓存 配置语法 使用之前需要先定义一个proxy_cache_path配置语法:proxy_cache_path path [levels= ...
- 第一次项目上Linux服务器(六:Nginx安装及相关命令(转))
1.下载nginx 方法一 wget http://nginx.org/download/nginx-1.11.6.tar.gz 方法二 http://nginx.org/en/download.ht ...
- 第十六篇 nginx主配置文件参数解释
# 指定拥有运行nginx权限的用户 #user nobody; # 指定开启的进程数,建议设置为CPU核心数 worker_processes ; # 指定全局错误日志级别,包括:debug/inf ...
- Nginx(六):配置解析之location解析
nginx成为非常流行的代理服务软件,最根本的原因也许是在于其强悍性能.但还有一些必要的条件,比如功能的完整,配置的易用,能够解决各种各样的实际需求问题,这些是一个好的软件的必备特性. 那么,今天我们 ...
随机推荐
- mongodb常用语句
一.查询 find方法 db.collection_name.find(); 查询所有的结果: select * from users; db.users.find(); 指定返回那些列(键): se ...
- MinGW安装与使用简介
MinGW 安装与使用简介 安装方法:其实很简单,如下: Step one: 到这里下载 MinGW, 网速慢的话可能打不开, 是个外国网站 (上面的网站镜像可能 出了点问题 , 有的东西下载下来却不 ...
- Java永久代去哪儿了
http://www.infoq.com/cn/articles/Java-PERMGEN-Removed 在Java虚拟机(以下简称JVM)中,类包含其对应的元数据,比如类的层级信息,方法数据和方法 ...
- .net core2.0添加json文件并转化成类注入控制器使用
上一篇,我们介绍了如何读取自定义的json文件,数据是读取出来了,只是处理的时候太麻烦,需要一遍一遍写,很枯燥.那么有没有很好的办法呢?经过钻研,办法有了. 既然一个一个读取比较麻烦,那么可以把它放入 ...
- Redis的Java使用入门
因项目需要,最近简单学习了redis的使用 redis在服务器centos环境下安装比较简单. 如果要在windows上安装,可以参考别人的文章 http://blog.csdn.net/renfuf ...
- 一个简单的小小记账本程序(java)
感觉基础知识学了不少,但是一直搞不清一个项目的实际开发流程,所以就借着这个小记账本的程序梳理一下.因为楼主也是出于学习阶段的菜鸟,所以程序可能会有各种玄学的bug,希望一起提升吧. 跟着站长学到了很多 ...
- Java虚拟机-垃圾收集器
垃圾收集器(Garbage Collection, GC)的诞生引导出了三个问题: 哪些内存需要回收? 什么时候回收? 如何回收? 对于线程独占的三个区域(程序计数器.虚拟机栈.本地方法栈)不用过多的 ...
- VueJs(12)---vue-router(导航守卫,路由元信息)
vue-router(导航守卫,路由元信息) 之前泄露两篇有关vue-router博客: VueJs(10)---vue-router(进阶1) VueJs(11)---vue-router(进阶2) ...
- GitHub学习笔记:分支管理
GitHub对于每个开发版本都需要有一个分支,默认的分支是master往往被大家保留下来作为主分支,分支类似于进程的一个指针,往往在master这个稳定的主干版本上分出一个或多个正在开发的分支版本,开 ...
- 想做微信小程序第三方代理,各位觉得一键生成平台能赚到钱吗?
这几年生意不景气,这是很多人的共识.从2009年开始,各种专家就判断"明年经济是最差的一年."然后,这个明年,一直"明"到了2018年,到最后,我们发现,经济就 ...