我眼中的 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成为非常流行的代理服务软件,最根本的原因也许是在于其强悍性能.但还有一些必要的条件,比如功能的完整,配置的易用,能够解决各种各样的实际需求问题,这些是一个好的软件的必备特性. 那么,今天我们 ...
随机推荐
- Java 故障安全异常处理
异常处理代码必须保证其故障安全机制,其中一条重要的规则如下: 在try-catch-finally块抛出的最后一个异常将会在调用堆栈中传递. 所有早期异常将会消失. 如果从一个catch或finall ...
- SSH框架组建时碰到的一些问题
以前用spring+hibernate的框架解决后台事务,这一次重新组建框架,计划引入Struts,如果方便的话,可能会进一步引入Freemarker.以下记下配置中的一些问题及解决,以供他人参考. ...
- 关于Apple开发者的D-U-N-S Number
企业开发者需要这个信息,中文译名叫邓白氏编码,很多攻略给的那个申请地址已经失效,这个组织官方也有地址可以提交申请资料,不过得注册,苹果目前可用的地址是:https://developer.apple. ...
- ruby the diference between gets and gets.chomp()
ruby the diference between gets and gets.chomp() 二者都是可以获取用户命令行输入的函数,但是 gets获取内容后,后面 附带了 多余的换行符号'\n'; ...
- Niop2017初赛滚粗记
初赛踢蹬滚粗 TOT (╯°Д°)╯︵┻━┻ ヽ(`Д´)ノ︵ ┻━┻ ┻━┻ 排序啊排序,净是排序,自打我学了C++就再没学过排序!!wtf! (╯°Д°)╯︵ /(.□ . )我tm怎么知道建国那 ...
- JSON-RPC远程调用协议
1. JSON-RPC简介 2. 请求 3. 响应 4. 错误 4.1. 错误对象 4.2. 错误码 5. 批量调用 6. 示例 6.1. 列表形式参数 6.2. key-value形式参数 6.3. ...
- 学HTTP协议所要知道的基础知识(微总结)
1.网络本质 进行资源共享和信息传输. 2.基于网络的应用程序的本质 就是获取数据和传输数据给用户使用. 3.TCP/IP协议栈工作流程 实体层是不属于TCP/IP协议栈的一层.也就是说TCP/IP协 ...
- 让程序跳转到绝对地址0x100000去执行
网上比较火的一个题,让程序跳转到绝对地址去执行 :可以的实现方式为: ( (void(*)())0x4110e6)(); (*(void(*)())0x4110e6)(); (*((void(*)() ...
- 通过数据流处理-微信小程序生成临时二维码
1.小程序代码 onLoad: function (options) { var that = this api.Login(function (login) { var codeModel = ne ...
- Spring Boot实战笔记(九)-- Spring高级话题(组合注解与元注解)
一.组合注解与元注解 从Spring 2开始,为了响应JDK 1.5推出的注解功能,Spring开始大量加入注解来替代xml配置.Spring的注解主要用来配置注入Bean,切面相关配置(@Trans ...